diff --git a/.ci/monolithic-windows.sh b/.ci/monolithic-windows.sh index 57b276f3e1df0..f9c7d4436fba5 100755 --- a/.ci/monolithic-windows.sh +++ b/.ci/monolithic-windows.sh @@ -50,8 +50,8 @@ echo "--- cmake" pip install -q -r "${MONOREPO_ROOT}"/mlir/python/requirements.txt pip install -q -r "${MONOREPO_ROOT}"/.ci/requirements.txt -export CC=cl -export CXX=cl +export CC=clang +export CXX=clang++ export LD=link # The CMAKE_*_LINKER_FLAGS to disable the manifest come from research diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml index b4fa27203236a..cdec2fdff69dc 100644 --- a/.github/workflows/docs.yml +++ b/.github/workflows/docs.yml @@ -51,7 +51,7 @@ on: jobs: check-docs-build: name: "Test documentation build" - runs-on: ubuntu-latest + runs-on: ubuntu-22.04 if: github.repository == 'llvm/llvm-project' steps: # Don't fetch before checking for file changes to force the file changes diff --git a/.github/workflows/issue-subscriber.yml b/.github/workflows/issue-subscriber.yml index ef4fdf4418193..54cb04fd2cbc6 100644 --- a/.github/workflows/issue-subscriber.yml +++ b/.github/workflows/issue-subscriber.yml @@ -10,7 +10,7 @@ permissions: jobs: auto-subscribe: - runs-on: ubuntu-latest + runs-on: ubuntu-22.04 if: github.repository == 'llvm/llvm-project' steps: - name: Checkout Automation Script diff --git a/.github/workflows/libclang-abi-tests.yml b/.github/workflows/libclang-abi-tests.yml index 65cffccff776f..122f7fcb65bf7 100644 --- a/.github/workflows/libclang-abi-tests.yml +++ b/.github/workflows/libclang-abi-tests.yml @@ -27,7 +27,7 @@ concurrency: jobs: abi-dump-setup: if: github.repository_owner == 'llvm' - runs-on: ubuntu-latest + runs-on: ubuntu-22.04 outputs: BASELINE_REF: ${{ steps.vars.outputs.BASELINE_REF }} ABI_HEADERS: ${{ steps.vars.outputs.ABI_HEADERS }} @@ -83,7 +83,7 @@ jobs: abi-dump: if: github.repository_owner == 'llvm' needs: abi-dump-setup - runs-on: ubuntu-latest + runs-on: ubuntu-22.04 strategy: matrix: name: @@ -138,7 +138,7 @@ jobs: abi-compare: if: github.repository_owner == 'llvm' - runs-on: ubuntu-latest + runs-on: ubuntu-22.04 needs: - abi-dump-setup - abi-dump diff --git a/.github/workflows/libcxx-check-generated-files.yml b/.github/workflows/libcxx-check-generated-files.yml index 570055624b2a8..96f3ddbbf7521 100644 --- a/.github/workflows/libcxx-check-generated-files.yml +++ b/.github/workflows/libcxx-check-generated-files.yml @@ -9,7 +9,7 @@ permissions: jobs: check_generated_files: - runs-on: ubuntu-latest + runs-on: ubuntu-22.04 steps: - name: Fetch LLVM sources uses: actions/checkout@v4 diff --git a/.github/workflows/llvm-bugs.yml b/.github/workflows/llvm-bugs.yml index c392078fa4525..3fee30f00b20e 100644 --- a/.github/workflows/llvm-bugs.yml +++ b/.github/workflows/llvm-bugs.yml @@ -11,7 +11,7 @@ on: jobs: auto-subscribe: - runs-on: ubuntu-latest + runs-on: ubuntu-22.04 if: github.repository == 'llvm/llvm-project' steps: - uses: actions/setup-node@v4 diff --git a/.github/workflows/llvm-project-tests.yml b/.github/workflows/llvm-project-tests.yml index 4ff84c511250f..aca8d87b1a243 100644 --- a/.github/workflows/llvm-project-tests.yml +++ b/.github/workflows/llvm-project-tests.yml @@ -14,7 +14,7 @@ on: required: false os_list: required: false - default: '["ubuntu-latest", "windows-2019", "macOS-13"]' + default: '["ubuntu-22.04", "windows-2022", "macOS-13"]' python_version: required: false type: string @@ -44,7 +44,7 @@ on: # to install a python version linked against a newer version of glibc. # TODO(boomanaiden154): Bump the Ubuntu version once the version in the # container is bumped. - default: '["ubuntu-22.04", "windows-2019", "macOS-13"]' + default: '["ubuntu-22.04", "windows-2022", "macOS-13"]' python_version: required: false @@ -70,7 +70,14 @@ jobs: strategy: fail-fast: false matrix: - os: ${{ fromJSON(inputs.os_list) }} + os: + - ubuntu-22.04 + # Use windows-2019 due to: + # https://developercommunity.visualstudio.com/t/Prev-Issue---with-__assume-isnan-/1597317 + - windows-2022 + # We're using a specific version of macOS due to: + # https://github.com/actions/virtual-environments/issues/5900 + - macOS-latest steps: - name: Setup Windows if: startsWith(matrix.os, 'windows') @@ -84,7 +91,7 @@ jobs: - name: Setup Python uses: actions/setup-python@v5 with: - python-version: ${{ inputs.python_version }} + python-version: '3.11' - name: Install Ninja if: runner.os != 'Linux' uses: llvm/actions/install-ninja@main @@ -109,6 +116,7 @@ jobs: key: ${{ matrix.os }} variant: sccache - name: Build and Test + if: "!startsWith(matrix.os, 'windows')" env: # Workaround for https://github.com/actions/virtual-environments/issues/5900. # This should be a no-op for non-mac OSes @@ -138,6 +146,7 @@ jobs: -DLLVM_ENABLE_ASSERTIONS=ON \ -DLLDB_INCLUDE_TESTS=OFF \ -DLIBCLC_TARGETS_TO_BUILD="amdgcn--;amdgcn--amdhsa;r600--;nvptx--;nvptx64--;nvptx--nvidiacl;nvptx64--nvidiacl" \ + -DLLVM_EXPERIMENTAL_TARGETS_TO_BUILD="BPF;SBF" \ -DCMAKE_C_COMPILER_LAUNCHER=sccache \ -DCMAKE_CXX_COMPILER_LAUNCHER=sccache \ $extra_cmake_args \ @@ -145,7 +154,7 @@ jobs: ninja -C "$builddir" '${{ inputs.build_target }}' - name: Build and Test libclc - if: "!startsWith(matrix.os, 'windows') && contains(inputs.projects, 'libclc')" + if: "!startsWith(matrix.os, 'windows') && !startsWith(matrix.os, 'macOS') && contains(inputs.projects, 'libclc')" env: LLVM_BUILDDIR: ${{ steps.build-llvm.outputs.llvm-builddir }} run: | diff --git a/.github/workflows/llvm-tests.yml b/.github/workflows/llvm-tests.yml index e2ca2ff44890e..ee0be48f8a844 100644 --- a/.github/workflows/llvm-tests.yml +++ b/.github/workflows/llvm-tests.yml @@ -6,14 +6,16 @@ permissions: on: workflow_dispatch: push: - branches: - - 'release/**' + ignore-forks: true + #branches: + # - 'release/**' paths: - 'llvm/**' - '.github/workflows/llvm-tests.yml' pull_request: - branches: - - 'release/**' + ignore-forks: true + #branches: + # - 'release/**' paths: - 'llvm/**' - '.github/workflows/llvm-tests.yml' @@ -26,8 +28,8 @@ concurrency: jobs: abi-dump-setup: - if: github.repository_owner == 'llvm' - runs-on: ubuntu-latest + #if: github.repository_owner == 'llvm' + runs-on: ubuntu-22.04 outputs: BASELINE_REF: ${{ steps.vars.outputs.BASELINE_REF }} ABI_HEADERS: ${{ steps.vars.outputs.ABI_HEADERS }} @@ -69,9 +71,9 @@ jobs: fi abi-dump: - if: github.repository_owner == 'llvm' + #if: github.repository_owner == 'llvm' needs: abi-dump-setup - runs-on: ubuntu-latest + runs-on: ubuntu-22.04 strategy: matrix: name: @@ -141,8 +143,8 @@ jobs: path: llvm.symbols abi-compare: - if: github.repository_owner == 'llvm' - runs-on: ubuntu-latest + #if: github.repository_owner == 'llvm' + runs-on: ubuntu-22.04 needs: - abi-dump-setup - abi-dump diff --git a/.github/workflows/new-issues.yml b/.github/workflows/new-issues.yml index 3cac57e268513..c54ffbf5b0307 100644 --- a/.github/workflows/new-issues.yml +++ b/.github/workflows/new-issues.yml @@ -10,7 +10,7 @@ jobs: automate-issues-labels: permissions: issues: write - runs-on: ubuntu-latest + runs-on: ubuntu-22.04 if: github.repository == 'llvm/llvm-project' steps: - uses: llvm/actions/issue-labeler@main diff --git a/.github/workflows/new-prs.yml b/.github/workflows/new-prs.yml index 88175d6f8d64d..fead63cb89081 100644 --- a/.github/workflows/new-prs.yml +++ b/.github/workflows/new-prs.yml @@ -16,7 +16,7 @@ on: jobs: greeter: - runs-on: ubuntu-latest + runs-on: ubuntu-22.04 permissions: pull-requests: write # Only comment on PRs that have been opened for the first time, by someone @@ -56,7 +56,7 @@ jobs: automate-prs-labels: # Greet first so that only the author gets that notification. needs: greeter - runs-on: ubuntu-latest + runs-on: ubuntu-22.04 # Ignore PRs with more than 10 commits. Pull requests with a lot of # commits tend to be accidents usually when someone made a mistake while trying # to rebase. We want to ignore these pull requests to avoid excessive diff --git a/.github/workflows/pr-request-release-note.yml b/.github/workflows/pr-request-release-note.yml index 2fa501dda16bb..6b4d830d792a6 100644 --- a/.github/workflows/pr-request-release-note.yml +++ b/.github/workflows/pr-request-release-note.yml @@ -14,7 +14,7 @@ jobs: github.repository_owner == 'llvm' && startsWith(github.ref, 'refs/heads/release') - runs-on: ubuntu-latest + runs-on: ubuntu-22.04 steps: # We need to pull the script from the main branch, so that we ensure # we get the latest version of this script. diff --git a/.github/workflows/pr-subscriber.yml b/.github/workflows/pr-subscriber.yml index 272d3e2f9ef8a..d52f075270c46 100644 --- a/.github/workflows/pr-subscriber.yml +++ b/.github/workflows/pr-subscriber.yml @@ -10,7 +10,7 @@ permissions: jobs: auto-subscribe: - runs-on: ubuntu-latest + runs-on: ubuntu-22.04 if: github.repository == 'llvm/llvm-project' steps: - name: Checkout Automation Script diff --git a/.github/workflows/premerge.yaml b/.github/workflows/premerge.yaml index 9b6a1236823d7..0f7def312d68c 100644 --- a/.github/workflows/premerge.yaml +++ b/.github/workflows/premerge.yaml @@ -25,11 +25,17 @@ concurrency: jobs: premerge-checks-linux: - if: >- - false && github.repository_owner == 'llvm' && - (github.event_name != 'pull_request' || github.event.action != 'closed') - runs-on: llvm-premerge-linux-runners + if: (github.event_name != 'pull_request' || github.event.action != 'closed') + runs-on: ubuntu-22.04 steps: + - name: Free up space in Github runner + uses: easimon/maximize-build-space@master + with: + remove-dotnet: 'true' + remove-android: 'true' + remove-haskell: 'true' + remove-codeql: 'true' + root-reserve-mb: 2048 - name: Checkout LLVM uses: actions/checkout@v4 with: @@ -37,14 +43,12 @@ jobs: - name: Setup ccache uses: hendrikmuhs/ccache-action@v1.2.14 with: - max-size: "2000M" + max-size: "1500M" + - name: Print free space + run: | + echo "Free space:" + df -h - name: Build and Test - # Mark the job as a success even if the step fails so that people do - # not get notified while the new premerge pipeline is in an - # experimental state. - # TODO(boomanaiden154): Remove this once the pipeline is stable and we - # are ready for people to start recieving notifications. - continue-on-error: true run: | git config --global --add safe.directory '*' @@ -56,16 +60,10 @@ jobs: . ./.ci/compute-projects.sh - all_projects="bolt clang clang-tools-extra compiler-rt cross-project-tests flang libc libclc lld lldb llvm mlir openmp polly pstl" - modified_projects="$(keep-modified-projects ${all_projects})" - - linux_projects_to_test=$(exclude-linux $(compute-projects-to-test 0 ${modified_projects})) - linux_check_targets=$(check-targets ${linux_projects_to_test} | sort | uniq) - linux_projects=$(add-dependencies ${linux_projects_to_test} | sort | uniq) - - linux_runtimes_to_test=$(compute-runtimes-to-test ${linux_projects_to_test}) - linux_runtime_check_targets=$(check-targets ${linux_runtimes_to_test} | sort | uniq) - linux_runtimes=$(echo ${linux_runtimes_to_test} | sort | uniq) + linux_projects="clang lld lldb llvm" + linux_check_targets="check-clang check-lld check-lldb check-llvm" + linux_runtimes="" + linux_runtime_check_targets="" if [[ "${linux_projects}" == "" ]]; then echo "No projects to build" @@ -77,16 +75,16 @@ jobs: echo "Building runtimes: ${linux_runtimes}" echo "Running runtimes checks targets: ${linux_runtime_check_targets}" - export CC=/opt/llvm/bin/clang - export CXX=/opt/llvm/bin/clang++ + export CC=clang + export CXX=clang++ ./.ci/monolithic-linux.sh "$(echo ${linux_projects} | tr ' ' ';')" "$(echo ${linux_check_targets})" "$(echo ${linux_runtimes} | tr ' ' ';')" "$(echo ${linux_runtime_check_targets})" premerge-checks-windows: if: >- - false && github.repository_owner == 'llvm' && - (github.event_name != 'pull_request' || github.event.action != 'closed') - runs-on: llvm-premerge-windows-runners + false && github.repository_owner == 'llvm' && + (github.event_name != 'pull_request' || github.event.action != 'closed') + runs-on: windows-2022 defaults: run: shell: bash @@ -128,12 +126,6 @@ jobs: echo "windows-projects=${windows_projects}" >> $GITHUB_OUTPUT echo "windows-check-targets=${windows_check_targets}" >> $GITHUB_OUTPUT - name: Build and Test - # Mark the job as a success even if the step fails so that people do - # not get notified while the new premerge pipeline is in an - # experimental state. - # TODO(boomanaiden154): Remove this once the pipeline is stable and we - # are ready for people to start recieving notifications. - continue-on-error: true if: ${{ steps.vars.outputs.windows-projects != '' }} shell: cmd run: | @@ -144,11 +136,7 @@ jobs: permerge-check-macos: runs-on: macos-14 - if: >- - github.repository_owner == 'llvm' && - (startswith(github.ref_name, 'release/') || - startswith(github.base_ref, 'release/')) && - (github.event_name != 'pull_request' || github.event.action != 'closed') + if: (github.event_name != 'pull_request' || github.event.action != 'closed') steps: - name: Checkout LLVM uses: actions/checkout@v4 @@ -170,7 +158,7 @@ jobs: . ./.ci/compute-projects.sh - all_projects="clang clang-tools-extra lld lldb llvm mlir" + all_projects="clang lld lldb llvm" modified_projects="$(keep-modified-projects ${all_projects})" # We have to disable the runtimes builds due to https://github.com/llvm/llvm-project/issues/90568 diff --git a/.github/workflows/release-documentation.yml b/.github/workflows/release-documentation.yml index 09e21585bfc56..6d1ebdc392ac1 100644 --- a/.github/workflows/release-documentation.yml +++ b/.github/workflows/release-documentation.yml @@ -29,7 +29,7 @@ on: jobs: release-documentation: name: Build and Upload Release Documentation - runs-on: ubuntu-latest + runs-on: ubuntu-22.04 env: upload: ${{ inputs.upload && !contains(inputs.release-version, 'rc') }} steps: diff --git a/.github/workflows/release-doxygen.yml b/.github/workflows/release-doxygen.yml index ea95e5bb12b2b..53be795285aa3 100644 --- a/.github/workflows/release-doxygen.yml +++ b/.github/workflows/release-doxygen.yml @@ -33,7 +33,7 @@ on: jobs: release-doxygen: name: Build and Upload Release Doxygen - runs-on: ubuntu-latest + runs-on: ubuntu-22.04 permissions: contents: write env: diff --git a/.github/workflows/release-lit.yml b/.github/workflows/release-lit.yml index 9d6f3140e6883..de373e46f0112 100644 --- a/.github/workflows/release-lit.yml +++ b/.github/workflows/release-lit.yml @@ -25,7 +25,7 @@ on: jobs: release-lit: name: Release Lit - runs-on: ubuntu-latest + runs-on: ubuntu-22.04 steps: - name: Checkout LLVM uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 diff --git a/.github/workflows/release-tasks.yml b/.github/workflows/release-tasks.yml index 52076ea1821b0..e23173230773c 100644 --- a/.github/workflows/release-tasks.yml +++ b/.github/workflows/release-tasks.yml @@ -12,7 +12,7 @@ on: jobs: validate-tag: name: Validate Tag - runs-on: ubuntu-latest + runs-on: ubuntu-22.04 if: github.repository == 'llvm/llvm-project' outputs: release-version: ${{ steps.validate-tag.outputs.release-version }} diff --git a/.github/workflows/scorecard.yml b/.github/workflows/scorecard.yml index ff61cf83a6af3..0433c306f1834 100644 --- a/.github/workflows/scorecard.yml +++ b/.github/workflows/scorecard.yml @@ -21,7 +21,7 @@ permissions: jobs: analysis: name: Scorecard analysis - runs-on: ubuntu-latest + runs-on: ubuntu-22.04 if: github.repository == 'llvm/llvm-project' permissions: # Needed to upload the results to code-scanning dashboard. diff --git a/.github/workflows/version-check.yml b/.github/workflows/version-check.yml index 894e07d323ca9..66b0e21bbda89 100644 --- a/.github/workflows/version-check.yml +++ b/.github/workflows/version-check.yml @@ -14,7 +14,7 @@ permissions: jobs: version_check: if: github.repository_owner == 'llvm' - runs-on: ubuntu-latest + runs-on: ubuntu-22.04 steps: - name: Fetch LLVM sources uses: actions/checkout@v4 diff --git a/README.md b/README.md index a9b29ecbc1a3a..ff0c236bcd335 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,7 @@ +# The LLVM Compiler Infrastructure modified to support Berkley Packet Filter modules written in Rust + +This fork of LLVM is used by [this fork of Rust](https://github.com/anza-xyz/rust) + # The LLVM Compiler Infrastructure [![OpenSSF Scorecard](https://api.securityscorecards.dev/projects/github.com/llvm/llvm-project/badge)](https://securityscorecards.dev/viewer/?uri=github.com/llvm/llvm-project) diff --git a/clang/lib/Basic/Targets.cpp b/clang/lib/Basic/Targets.cpp index 281aebdb1c35d..1d02695119473 100644 --- a/clang/lib/Basic/Targets.cpp +++ b/clang/lib/Basic/Targets.cpp @@ -268,6 +268,8 @@ std::unique_ptr AllocateTarget(const llvm::Triple &Triple, case llvm::Triple::bpfeb: case llvm::Triple::bpfel: return std::make_unique(Triple, Opts); + case llvm::Triple::sbf: + return std::make_unique(Triple, Opts); case llvm::Triple::msp430: return std::make_unique(Triple, Opts); diff --git a/clang/lib/Basic/Targets/BPF.cpp b/clang/lib/Basic/Targets/BPF.cpp index f4684765b7ffb..50bc5b0dfd320 100644 --- a/clang/lib/Basic/Targets/BPF.cpp +++ b/clang/lib/Basic/Targets/BPF.cpp @@ -12,8 +12,10 @@ #include "BPF.h" #include "Targets.h" +#include "clang/Basic/Diagnostic.h" #include "clang/Basic/MacroBuilder.h" #include "clang/Basic/TargetBuiltins.h" +#include "clang/Driver/DriverDiagnostic.h" #include "llvm/ADT/StringRef.h" using namespace clang; @@ -68,7 +70,12 @@ void BPFTargetInfo::getTargetDefines(const LangOptions &Opts, Builder.defineMacro("__BPF_FEATURE_GOTOL"); Builder.defineMacro("__BPF_FEATURE_ST"); } + + if (HasSolanaFeature) { + Builder.defineMacro("__ELF__"); + } } + static constexpr llvm::StringLiteral ValidCPUNames[] = {"generic", "v1", "v2", "v3", "v4", "probe"}; diff --git a/clang/lib/Basic/Targets/BPF.h b/clang/lib/Basic/Targets/BPF.h index 27a4b5f314970..8be7b2be8dabc 100644 --- a/clang/lib/Basic/Targets/BPF.h +++ b/clang/lib/Basic/Targets/BPF.h @@ -22,10 +22,11 @@ namespace clang { namespace targets { class LLVM_LIBRARY_VISIBILITY BPFTargetInfo : public TargetInfo { + bool HasSolanaFeature = false; bool HasAlu32 = false; public: - BPFTargetInfo(const llvm::Triple &Triple, const TargetOptions &) + BPFTargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) : TargetInfo(Triple) { LongWidth = LongAlign = PointerWidth = PointerAlign = 64; SizeType = UnsignedLong; @@ -34,10 +35,28 @@ class LLVM_LIBRARY_VISIBILITY BPFTargetInfo : public TargetInfo { IntMaxType = SignedLong; Int64Type = SignedLong; RegParmMax = 5; + if (Triple.getArch() == llvm::Triple::sbf) { + HasSolanaFeature = true; + } else { + for (auto& it : Opts.FeaturesAsWritten) { + if (it == "+solana") { + HasSolanaFeature = true; + break; + } + } + } if (Triple.getArch() == llvm::Triple::bpfeb) { - resetDataLayout("E-m:e-p:64:64-i64:64-i128:128-n32:64-S128"); + if (HasSolanaFeature) { + resetDataLayout("E-m:e-p:64:64-i64:64-n32:64-S128"); + } else { + resetDataLayout("E-m:e-p:64:64-i64:64-i128:128-n32:64-S128"); + } } else { - resetDataLayout("e-m:e-p:64:64-i64:64-i128:128-n32:64-S128"); + if (HasSolanaFeature) { + resetDataLayout("e-m:e-p:64:64-i64:64-n32:64-S128"); + } else { + resetDataLayout("e-m:e-p:64:64-i64:64-i128:128-n32:64-S128"); + } } MaxAtomicPromoteWidth = 64; MaxAtomicInlineWidth = 64; @@ -115,6 +134,8 @@ class LLVM_LIBRARY_VISIBILITY BPFTargetInfo : public TargetInfo { std::pair hardwareInterferenceSizes() const override { return std::make_pair(32, 32); } + + bool hasBitIntType() const override { return HasSolanaFeature; } }; } // namespace targets } // namespace clang diff --git a/clang/lib/Driver/ToolChains/CommonArgs.cpp b/clang/lib/Driver/ToolChains/CommonArgs.cpp index ae635fb6a1807..d49d0585ba74f 100644 --- a/clang/lib/Driver/ToolChains/CommonArgs.cpp +++ b/clang/lib/Driver/ToolChains/CommonArgs.cpp @@ -674,6 +674,7 @@ std::string tools::getCPUName(const Driver &D, const ArgList &Args, case llvm::Triple::bpfel: case llvm::Triple::bpfeb: + case llvm::Triple::sbf: if (const Arg *A = Args.getLastArg(options::OPT_mcpu_EQ)) return A->getValue(); return ""; diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp index e440f60526bb3..e9eae195f3d08 100644 --- a/clang/lib/Sema/SemaChecking.cpp +++ b/clang/lib/Sema/SemaChecking.cpp @@ -1927,6 +1927,7 @@ bool Sema::CheckTSBuiltinFunctionCall(const TargetInfo &TI, unsigned BuiltinID, return ARM().CheckAArch64BuiltinFunctionCall(TI, BuiltinID, TheCall); case llvm::Triple::bpfeb: case llvm::Triple::bpfel: + case llvm::Triple::sbf: return BPF().CheckBPFBuiltinFunctionCall(BuiltinID, TheCall); case llvm::Triple::hexagon: return Hexagon().CheckHexagonBuiltinFunctionCall(BuiltinID, TheCall); diff --git a/clang/test/CodeGen/ext-int-cc.c b/clang/test/CodeGen/ext-int-cc.c index 14efd54e24ffb..3c4f2bef132bd 100644 --- a/clang/test/CodeGen/ext-int-cc.c +++ b/clang/test/CodeGen/ext-int-cc.c @@ -29,6 +29,7 @@ // RUN: %clang_cc1 -no-enable-noundef-analysis -triple arm -O3 -disable-llvm-passes -emit-llvm -o - %s | FileCheck %s --check-prefixes=ARM // RUN: %clang_cc1 -no-enable-noundef-analysis -triple loongarch64 -O3 -disable-llvm-passes -emit-llvm -o - %s | FileCheck %s --check-prefixes=LA64 // RUN: %clang_cc1 -no-enable-noundef-analysis -triple loongarch32 -O3 -disable-llvm-passes -emit-llvm -o - %s | FileCheck %s --check-prefixes=LA32 +// RUN: %clang_cc1 -no-enable-noundef-analysis -triple sbf -O3 -disable-llvm-passes -emit-llvm -o - %s | FileCheck %s --check-prefixes=SBF // Make sure 128 and 64 bit versions are passed like integers. void ParamPassing(_BitInt(128) b, _BitInt(64) c) {} @@ -61,6 +62,7 @@ void ParamPassing(_BitInt(128) b, _BitInt(64) c) {} // ARM: define{{.*}} arm_aapcscc void @ParamPassing(ptr byval(i128) align 8 %{{.+}}, i64 %{{.+}}) // LA64: define{{.*}} void @ParamPassing(i128 %{{.+}}, i64 %{{.+}}) // LA32: define{{.*}} void @ParamPassing(ptr %{{.+}}, i64 %{{.+}}) +// SBF: define{{.*}} void @ParamPassing(i128 %{{.+}}, i64 %{{.+}}) void ParamPassing2(_BitInt(127) b, _BitInt(63) c) {} // LIN64: define{{.*}} void @ParamPassing2(i64 %{{.+}}, i64 %{{.+}}, i64 %{{.+}}) @@ -256,6 +258,7 @@ _BitInt(127) ReturnPassing3(void) { return 0; } // ARM: define{{.*}} arm_aapcscc void @ReturnPassing3(ptr dead_on_unwind noalias writable sret // LA64: define{{.*}} i127 @ReturnPassing3( // LA32: define{{.*}} void @ReturnPassing3(ptr dead_on_unwind noalias writable sret +// SBF: define{{.*}} i127 @ReturnPassing3( _BitInt(128) ReturnPassing4(void) { return 0; } // LIN64: define{{.*}} { i64, i64 } @ReturnPassing4( diff --git a/clang/test/CodeGen/target-data.c b/clang/test/CodeGen/target-data.c index 71eb849433ed4..4d784710044af 100644 --- a/clang/test/CodeGen/target-data.c +++ b/clang/test/CodeGen/target-data.c @@ -265,6 +265,10 @@ // RUN: FileCheck %s -check-prefix=BPFEB // BPFEB: target datalayout = "E-m:e-p:64:64-i64:64-i128:128-n32:64-S128" +// RUN: %clang_cc1 -triple sbf -o - -emit-llvm %s | \ +// RUN: FileCheck %s -check-prefix=SBF +// SBF: target datalayout = "e-m:e-p:64:64-i64:64-n32:64-S128" + // RUN: %clang_cc1 -triple ve -o - -emit-llvm %s | \ // RUN: FileCheck %s -check-prefix=VE // VE: target datalayout = "e-m:e-i64:64-n32:64-S128-v64:64:64-v128:64:64-v256:64:64-v512:64:64-v1024:64:64-v2048:64:64-v4096:64:64-v8192:64:64-v16384:64:64" diff --git a/clang/test/Interpreter/global-dtor.cpp b/clang/test/Interpreter/global-dtor.cpp index 1f241d9f19317..e413f1695fa7f 100644 --- a/clang/test/Interpreter/global-dtor.cpp +++ b/clang/test/Interpreter/global-dtor.cpp @@ -10,4 +10,4 @@ extern "C" int printf(const char *, ...); struct D { float f = 1.0; D *m = nullptr; D(){} ~D() { printf("D[f=%f, m=0x%llx]\n", f, reinterpret_cast(m)); }} d; // CHECK: D[f=1.000000, m=0x0] -%quit \ No newline at end of file +%quit diff --git a/clang/unittests/Interpreter/ExceptionTests/InterpreterExceptionTest.cpp b/clang/unittests/Interpreter/ExceptionTests/InterpreterExceptionTest.cpp index bc2bd11df6aef..aa1ecc939229f 100644 --- a/clang/unittests/Interpreter/ExceptionTests/InterpreterExceptionTest.cpp +++ b/clang/unittests/Interpreter/ExceptionTests/InterpreterExceptionTest.cpp @@ -63,6 +63,7 @@ TEST(InterpreterExceptionTest, DISABLED_CatchException) { #else TEST(InterpreterExceptionTest, CatchException) { #endif + GTEST_SKIP() << "Skipping single test"; llvm::llvm_shutdown_obj Y; // Call llvm_shutdown() on exit. llvm::InitializeNativeTarget(); llvm::InitializeNativeTargetAsmPrinter(); diff --git a/lld/ELF/Arch/SBF.cpp b/lld/ELF/Arch/SBF.cpp new file mode 100644 index 0000000000000..51be72c9f373e --- /dev/null +++ b/lld/ELF/Arch/SBF.cpp @@ -0,0 +1,148 @@ +//===- SBF.cpp ------------------------------------------------------------===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "InputFiles.h" +#include "Symbols.h" +#include "Target.h" +#include "lld/Common/ErrorHandler.h" +#include "llvm/Object/ELF.h" +#include "llvm/Support/Endian.h" + +using namespace llvm; +using namespace llvm::object; +using namespace llvm::support::endian; +using namespace llvm::ELF; + +namespace lld { +namespace elf { + +namespace { +class SBF final : public TargetInfo { +public: + SBF(Ctx & ctx); + RelExpr getRelExpr(RelType type, const Symbol &s, + const uint8_t *loc) const override; + RelType getDynRel(RelType type) const override; + int64_t getImplicitAddend(const uint8_t *buf, RelType type) const override; + void relocate(uint8_t *loc, const Relocation &rel, uint64_t val) const override; + uint32_t calcEFlags() const override; +}; +} // namespace + +SBF::SBF(Ctx &ctx) : TargetInfo(ctx) { + relativeRel = R_SBF_64_RELATIVE; + symbolicRel = R_SBF_64_64; + defaultCommonPageSize = 8; + defaultMaxPageSize = 8; + defaultImageBase = 0; +} + +RelExpr SBF::getRelExpr(RelType type, const Symbol &s, + const uint8_t *loc) const { + switch (type) { + case R_SBF_64_32: + return R_PC; + case R_SBF_64_ABS32: + case R_SBF_64_NODYLD32: + case R_SBF_64_ABS64: + case R_SBF_64_64: + return R_ABS; + default: + Err(ctx) << getErrorLoc(ctx, loc) << "unrecognized reloc " << type.v; + } + return R_NONE; +} + +RelType SBF::getDynRel(RelType type) const { + switch (type) { + case R_SBF_64_ABS64: + // R_SBF_64_ABS64 is symbolic like R_SBF_64_64, which is set as our + // symbolicRel in the constructor. Return R_SBF_64_64 here so that if + // the symbol isn't preemptible, we emit a _RELATIVE relocation instead + // and skip emitting the symbol. + // + // See https://github.com/anza-xyz/llvm-project/blob/6b6aef5dbacef31a3c7b3a54f7f1ba54cafc7077/lld/ELF/Relocations.cpp#L1179 + return R_SBF_64_64; + default: + return type; + } +} + +int64_t SBF::getImplicitAddend(const uint8_t *buf, RelType type) const { + switch (type) { + case R_SBF_64_ABS32: + return SignExtend64<32>(read32le(buf)); + default: + return 0; + } +} + +void SBF::relocate(uint8_t *loc, const Relocation &rel, uint64_t val) const { + switch (rel.type) { + case R_SBF_64_32: { + // Relocation of a symbol + write32le(loc + 4, ((val - 8) / 8) & 0xFFFFFFFF); + break; + } + case R_SBF_64_ABS32: + case R_SBF_64_NODYLD32: { + // Relocation used by .BTF.ext and DWARF + write32le(loc, val & 0xFFFFFFFF); + break; + } + case R_SBF_64_64: { + // Relocation of a lddw instruction + // 64 bit address is divided into the imm of this and the following + // instructions, lower 32 first. + write32le(loc + 4, val & 0xFFFFFFFF); + write32le(loc + 8 + 4, val >> 32); + break; + } + case R_SBF_64_ABS64: { + // The relocation type is used for normal 64-bit data. The + // actual to-be-relocated data is stored at r_offset and the + // read/write data bitsize is 64 (8 bytes). The relocation can + // be resolved with the symbol value plus implicit addend. + write64le(loc, val); + break; + } + default: + Err(ctx) << getErrorLoc(ctx, loc) << "unrecognized reloc " << rel.type.v; + } +} + +static uint32_t getEFlags(InputFile *file, Ctx &ctx) { + if (ctx.arg.ekind == ELF64BEKind) + return cast>(file)->getObj().getHeader().e_flags; + return cast>(file)->getObj().getHeader().e_flags; +} + +uint32_t SBF::calcEFlags() const { + uint32_t ret = 0; + + // Ensure that all the object files were compiled with the same flags, as + // different flags indicate different ABIs. + for (InputFile *f : ctx.objectFiles) { + uint32_t flags = getEFlags(f, ctx); + if (ret == 0) { + ret = flags; + } else if (ret != flags) { + error("can not link object files with incompatible flags"); + } + } + + return ret; +} + +void setSBFTargetInfo(Ctx &ctx) { + ctx.target.reset(new SBF(ctx)); +} + +} // namespace elf +} // namespace lld diff --git a/lld/ELF/CMakeLists.txt b/lld/ELF/CMakeLists.txt index 83d816ddb0601..00182c9f146e4 100644 --- a/lld/ELF/CMakeLists.txt +++ b/lld/ELF/CMakeLists.txt @@ -32,6 +32,7 @@ add_lld_library(lldELF Arch/PPC.cpp Arch/PPC64.cpp Arch/RISCV.cpp + Arch/SBF.cpp Arch/SPARCV9.cpp Arch/SystemZ.cpp Arch/X86.cpp diff --git a/lld/ELF/Driver.cpp b/lld/ELF/Driver.cpp index a1e9ecae08557..ba3fbd2608474 100644 --- a/lld/ELF/Driver.cpp +++ b/lld/ELF/Driver.cpp @@ -1876,7 +1876,8 @@ static void setConfigs(Ctx &ctx, opt::InputArgList &args) { // builds and disabled otherwise. This check is enabled when writeAddends is // true. #ifndef NDEBUG - bool checkDynamicRelocsDefault = true; + // The SBF and BPF target for Solana do not support checking dynamic relocs. + bool checkDynamicRelocsDefault = m != EM_BPF && m != EM_SBF; #else bool checkDynamicRelocsDefault = false; #endif diff --git a/lld/ELF/InputFiles.cpp b/lld/ELF/InputFiles.cpp index d43de8ce6dfef..53025e664e7fd 100644 --- a/lld/ELF/InputFiles.cpp +++ b/lld/ELF/InputFiles.cpp @@ -1681,6 +1681,8 @@ static uint16_t getBitcodeMachineKind(Ctx &ctx, StringRef path, return t.isOSIAMCU() ? EM_IAMCU : EM_386; case Triple::x86_64: return EM_X86_64; + case Triple::sbf: + return EM_SBF; default: ErrAlways(ctx) << path << ": could not infer e_machine from bitcode target triple " diff --git a/lld/ELF/InputSection.cpp b/lld/ELF/InputSection.cpp index 52c472bb89caf..1aa1c77c1476e 100644 --- a/lld/ELF/InputSection.cpp +++ b/lld/ELF/InputSection.cpp @@ -1039,8 +1039,13 @@ void InputSection::relocateNonAlloc(Ctx &ctx, uint8_t *buf, const InputFile *f = this->file; for (auto it = rels.begin(), end = rels.end(); it != end; ++it) { const RelTy &rel = *it; - const RelType type = rel.getType(ctx.arg.isMips64EL); + RelType type = rel.getType(ctx.arg.isMips64EL); const uint64_t offset = rel.r_offset; + + // FIX: Temporary remap BPF_64_64 relocations in debug sections. + if (ctx.arg.emachine == EM_SBF && type == R_SBF_64_64 && isDebug) + type = R_BPF_64_ABS64; + uint8_t *bufLoc = buf + offset; int64_t addend = getAddend(rel); if (!RelTy::HasAddend) diff --git a/lld/ELF/Target.cpp b/lld/ELF/Target.cpp index c90ef8505aadd..86072ef06f539 100644 --- a/lld/ELF/Target.cpp +++ b/lld/ELF/Target.cpp @@ -63,6 +63,10 @@ void elf::setTarget(Ctx &ctx) { return setARMTargetInfo(ctx); case EM_AVR: return setAVRTargetInfo(ctx); + case EM_BPF: + return setSBFTargetInfo(ctx); + case EM_SBF: + return setSBFTargetInfo(ctx); case EM_HEXAGON: return setHexagonTargetInfo(ctx); case EM_LOONGARCH: diff --git a/lld/ELF/Target.h b/lld/ELF/Target.h index fd1e5d33c438a..227089c9bfe3e 100644 --- a/lld/ELF/Target.h +++ b/lld/ELF/Target.h @@ -194,6 +194,7 @@ void setSPARCV9TargetInfo(Ctx &); void setSystemZTargetInfo(Ctx &); void setX86TargetInfo(Ctx &); void setX86_64TargetInfo(Ctx &); +void setSBFTargetInfo(Ctx &); struct ErrorPlace { InputSectionBase *isec; diff --git a/lld/tools/lld/lld.cpp b/lld/tools/lld/lld.cpp index d6800fa1eea4b..4f8fa7e470fa4 100644 --- a/lld/tools/lld/lld.cpp +++ b/lld/tools/lld/lld.cpp @@ -37,6 +37,7 @@ #include "llvm/Support/Path.h" #include "llvm/Support/PluginLoader.h" #include "llvm/Support/Process.h" +#include "llvm/Support/TargetSelect.h" #include "llvm/TargetParser/Host.h" #include "llvm/TargetParser/Triple.h" #include @@ -72,7 +73,19 @@ LLD_HAS_DRIVER(mingw) LLD_HAS_DRIVER(macho) LLD_HAS_DRIVER(wasm) +// This function is called on startup. We need this for LTO since +// LTO calls LLVM functions to compile bitcode files to native code. +// Technically this can be delayed until we read bitcode files, but +// we don't bother to do lazily because the initialization is fast. +static void initLLVM() { + InitializeAllTargets(); + InitializeAllTargetMCs(); + InitializeAllAsmPrinters(); + InitializeAllAsmParsers(); +} + int lld_main(int argc, char **argv, const llvm::ToolContext &) { + initLLVM(); sys::Process::UseANSIEscapeCodes(true); if (::getenv("FORCE_LLD_DIAGNOSTICS_CRASH")) { diff --git a/lldb/include/lldb/Core/Opcode.h b/lldb/include/lldb/Core/Opcode.h index f72f2687b54fe..7fe56bb05dd72 100644 --- a/lldb/include/lldb/Core/Opcode.h +++ b/lldb/include/lldb/Core/Opcode.h @@ -9,6 +9,7 @@ #ifndef LLDB_CORE_OPCODE_H #define LLDB_CORE_OPCODE_H +#include "lldb/Utility/ArchSpec.h" #include "lldb/Utility/Endian.h" #include "lldb/lldb-enumerations.h" @@ -199,7 +200,7 @@ class Opcode { } } - int Dump(Stream *s, uint32_t min_byte_width); + int Dump(Stream *s, uint32_t min_byte_width, const ArchSpec &arch); const void *GetOpcodeBytes() const { return ((m_type == Opcode::eTypeBytes) ? m_data.inst.bytes : nullptr); diff --git a/lldb/include/lldb/Utility/ArchSpec.h b/lldb/include/lldb/Utility/ArchSpec.h index 7e9bc23a75acb..2c36668add84c 100644 --- a/lldb/include/lldb/Utility/ArchSpec.h +++ b/lldb/include/lldb/Utility/ArchSpec.h @@ -101,6 +101,19 @@ class ArchSpec { eRISCV_tso = 0x00000010, /// RVTSO (total store ordering) }; + // BPF specific e_flags + enum BPFeflags { + eBPF_abi_sbf_v2 = 0x00000020, + }; + + enum SBFSubType { + eSBFSubType_sbfv0, + eSBFSubType_sbfv1, + eSBFSubType_sbfv2, + eSBFSubType_sbfv3, + eSBFSubType_sbfv4, + }; + enum RISCVSubType { eRISCVSubType_unknown, eRISCVSubType_riscv32, @@ -236,6 +249,13 @@ class ArchSpec { eCore_wasm32, + eCore_bpf, + eCore_sbfv0, + eCore_sbfv1, + eCore_sbfv2, + eCore_sbfv3, + eCore_sbfv4, + kNumCores, kCore_invalid, diff --git a/lldb/scripts/solana/lldb_commands b/lldb/scripts/solana/lldb_commands new file mode 100644 index 0000000000000..4a1204ccc4be7 --- /dev/null +++ b/lldb/scripts/solana/lldb_commands @@ -0,0 +1,18 @@ +type synthetic add -l lldb_lookup.synthetic_lookup -x ".*" --category Rust +type summary add -F lldb_lookup.summary_lookup -e -x -h "^(alloc::([a-z_]+::)+)String$" --category Rust +type summary add -F lldb_lookup.summary_lookup -e -x -h "^&(mut )?str$" --category Rust +type summary add -F lldb_lookup.summary_lookup -e -x -h "^&(mut )?\\[.+\\]$" --category Rust +type summary add -F lldb_lookup.summary_lookup -e -x -h "^(std::ffi::([a-z_]+::)+)OsString$" --category Rust +type summary add -F lldb_lookup.summary_lookup -e -x -h "^(alloc::([a-z_]+::)+)Vec<.+>$" --category Rust +type summary add -F lldb_lookup.summary_lookup -e -x -h "^(alloc::([a-z_]+::)+)VecDeque<.+>$" --category Rust +type summary add -F lldb_lookup.summary_lookup -e -x -h "^(alloc::([a-z_]+::)+)BTreeSet<.+>$" --category Rust +type summary add -F lldb_lookup.summary_lookup -e -x -h "^(alloc::([a-z_]+::)+)BTreeMap<.+>$" --category Rust +type summary add -F lldb_lookup.summary_lookup -e -x -h "^(std::collections::([a-z_]+::)+)HashMap<.+>$" --category Rust +type summary add -F lldb_lookup.summary_lookup -e -x -h "^(std::collections::([a-z_]+::)+)HashSet<.+>$" --category Rust +type summary add -F lldb_lookup.summary_lookup -e -x -h "^(alloc::([a-z_]+::)+)Rc<.+>$" --category Rust +type summary add -F lldb_lookup.summary_lookup -e -x -h "^(alloc::([a-z_]+::)+)Arc<.+>$" --category Rust +type summary add -F lldb_lookup.summary_lookup -e -x -h "^(core::([a-z_]+::)+)Cell<.+>$" --category Rust +type summary add -F lldb_lookup.summary_lookup -e -x -h "^(core::([a-z_]+::)+)Ref<.+>$" --category Rust +type summary add -F lldb_lookup.summary_lookup -e -x -h "^(core::([a-z_]+::)+)RefMut<.+>$" --category Rust +type summary add -F lldb_lookup.summary_lookup -e -x -h "^(core::([a-z_]+::)+)RefCell<.+>$" --category Rust +type category enable Rust diff --git a/lldb/scripts/solana/lldb_lookup.py b/lldb/scripts/solana/lldb_lookup.py new file mode 100644 index 0000000000000..3cee51982ba9f --- /dev/null +++ b/lldb/scripts/solana/lldb_lookup.py @@ -0,0 +1,115 @@ +import lldb + +from lldb_providers import * +from rust_types import RustType, classify_struct, classify_union + + +# BACKCOMPAT: rust 1.35 +def is_hashbrown_hashmap(hash_map): + return len(hash_map.type.fields) == 1 + + +def classify_rust_type(type): + type_class = type.GetTypeClass() + if type_class == lldb.eTypeClassStruct: + return classify_struct(type.name, type.fields) + if type_class == lldb.eTypeClassUnion: + return classify_union(type.fields) + + return RustType.OTHER + + +def summary_lookup(valobj, dict): + # type: (SBValue, dict) -> str + """Returns the summary provider for the given value""" + rust_type = classify_rust_type(valobj.GetType()) + + if rust_type == RustType.STD_STRING: + return StdStringSummaryProvider(valobj, dict) + if rust_type == RustType.STD_OS_STRING: + return StdOsStringSummaryProvider(valobj, dict) + if rust_type == RustType.STD_STR: + return StdStrSummaryProvider(valobj, dict) + + if rust_type == RustType.STD_VEC: + return SizeSummaryProvider(valobj, dict) + if rust_type == RustType.STD_VEC_DEQUE: + return SizeSummaryProvider(valobj, dict) + if rust_type == RustType.STD_SLICE: + return SizeSummaryProvider(valobj, dict) + + if rust_type == RustType.STD_HASH_MAP: + return SizeSummaryProvider(valobj, dict) + if rust_type == RustType.STD_HASH_SET: + return SizeSummaryProvider(valobj, dict) + + if rust_type == RustType.STD_RC: + return StdRcSummaryProvider(valobj, dict) + if rust_type == RustType.STD_ARC: + return StdRcSummaryProvider(valobj, dict) + + if rust_type == RustType.STD_REF: + return StdRefSummaryProvider(valobj, dict) + if rust_type == RustType.STD_REF_MUT: + return StdRefSummaryProvider(valobj, dict) + if rust_type == RustType.STD_REF_CELL: + return StdRefSummaryProvider(valobj, dict) + + return "" + + +def synthetic_lookup(valobj, dict): + # type: (SBValue, dict) -> object + """Returns the synthetic provider for the given value""" + rust_type = classify_rust_type(valobj.GetType()) + + if rust_type == RustType.STRUCT: + return StructSyntheticProvider(valobj, dict) + if rust_type == RustType.STRUCT_VARIANT: + return StructSyntheticProvider(valobj, dict, is_variant=True) + if rust_type == RustType.TUPLE: + return TupleSyntheticProvider(valobj, dict) + if rust_type == RustType.TUPLE_VARIANT: + return TupleSyntheticProvider(valobj, dict, is_variant=True) + if rust_type == RustType.EMPTY: + return EmptySyntheticProvider(valobj, dict) + if rust_type == RustType.REGULAR_ENUM: + discriminant = valobj.GetChildAtIndex(0).GetChildAtIndex(0).GetValueAsUnsigned() + return synthetic_lookup(valobj.GetChildAtIndex(discriminant), dict) + if rust_type == RustType.SINGLETON_ENUM: + return synthetic_lookup(valobj.GetChildAtIndex(0), dict) + + if rust_type == RustType.STD_VEC: + return StdVecSyntheticProvider(valobj, dict) + if rust_type == RustType.STD_VEC_DEQUE: + return StdVecDequeSyntheticProvider(valobj, dict) + if rust_type == RustType.STD_SLICE: + return StdSliceSyntheticProvider(valobj, dict) + + if rust_type == RustType.STD_HASH_MAP: + if is_hashbrown_hashmap(valobj): + return StdHashMapSyntheticProvider(valobj, dict) + else: + return StdOldHashMapSyntheticProvider(valobj, dict) + if rust_type == RustType.STD_HASH_SET: + hash_map = valobj.GetChildAtIndex(0) + if is_hashbrown_hashmap(hash_map): + return StdHashMapSyntheticProvider(valobj, dict, show_values=False) + else: + return StdOldHashMapSyntheticProvider(hash_map, dict, show_values=False) + + if rust_type == RustType.STD_RC: + return StdRcSyntheticProvider(valobj, dict) + if rust_type == RustType.STD_ARC: + return StdRcSyntheticProvider(valobj, dict, is_atomic=True) + + if rust_type == RustType.STD_CELL: + return StdCellSyntheticProvider(valobj, dict) + if rust_type == RustType.STD_REF: + return StdRefSyntheticProvider(valobj, dict) + if rust_type == RustType.STD_REF_MUT: + return StdRefSyntheticProvider(valobj, dict) + if rust_type == RustType.STD_REF_CELL: + return StdRefSyntheticProvider(valobj, dict, is_cell=True) + + return DefaultSynthteticProvider(valobj, dict) diff --git a/lldb/scripts/solana/lldb_providers.py b/lldb/scripts/solana/lldb_providers.py new file mode 100644 index 0000000000000..35ac07f0db763 --- /dev/null +++ b/lldb/scripts/solana/lldb_providers.py @@ -0,0 +1,741 @@ +import sys + +from lldb import SBValue, SBData, SBError, eBasicTypeLong, eBasicTypeUnsignedLong, \ + eBasicTypeUnsignedChar + +# from lldb.formatters import Logger + +#################################################################################################### +# This file contains two kinds of pretty-printers: summary and synthetic. +# +# Important classes from LLDB module: +# SBValue: the value of a variable, a register, or an expression +# SBType: the data type; each SBValue has a corresponding SBType +# +# Summary provider is a function with the type `(SBValue, dict) -> str`. +# The first parameter is the object encapsulating the actual variable being displayed; +# The second parameter is an internal support parameter used by LLDB, and you should not touch it. +# +# Synthetic children is the way to provide a children-based representation of the object's value. +# Synthetic provider is a class that implements the following interface: +# +# class SyntheticChildrenProvider: +# def __init__(self, SBValue, dict) +# def num_children(self) +# def get_child_index(self, str) +# def get_child_at_index(self, int) +# def update(self) +# def has_children(self) +# def get_value(self) +# +# +# You can find more information and examples here: +# 1. https://lldb.llvm.org/varformats.html +# 2. https://lldb.llvm.org/python-reference.html +# 3. https://lldb.llvm.org/python_reference/lldb.formatters.cpp.libcxx-pysrc.html +# 4. https://github.com/llvm-mirror/lldb/tree/master/examples/summaries/cocoa +#################################################################################################### + +PY3 = sys.version_info[0] == 3 + + +class ValueBuilder: + def __init__(self, valobj): + # type: (SBValue) -> ValueBuilder + self.valobj = valobj + process = valobj.GetProcess() + self.endianness = process.GetByteOrder() + self.pointer_size = process.GetAddressByteSize() + + def from_int(self, name, value): + # type: (str, int) -> SBValue + type = self.valobj.GetType().GetBasicType(eBasicTypeLong) + data = SBData.CreateDataFromSInt64Array(self.endianness, self.pointer_size, [value]) + return self.valobj.CreateValueFromData(name, data, type) + + def from_uint(self, name, value): + # type: (str, int) -> SBValue + type = self.valobj.GetType().GetBasicType(eBasicTypeUnsignedLong) + data = SBData.CreateDataFromUInt64Array(self.endianness, self.pointer_size, [value]) + return self.valobj.CreateValueFromData(name, data, type) + + +def unwrap_unique_or_non_null(unique_or_nonnull): + # BACKCOMPAT: rust 1.32 + # https://github.com/rust-lang/rust/commit/7a0911528058e87d22ea305695f4047572c5e067 + # BACKCOMPAT: rust 1.60 + # https://github.com/rust-lang/rust/commit/2a91eeac1a2d27dd3de1bf55515d765da20fd86f + ptr = unique_or_nonnull.GetChildMemberWithName("pointer") + return ptr if ptr.TypeIsPointerType() else ptr.GetChildAtIndex(0) + + +class DefaultSynthteticProvider: + def __init__(self, valobj, dict): + # type: (SBValue, dict) -> DefaultSynthteticProvider + # logger = Logger.Logger() + # logger >> "Default synthetic provider for " + str(valobj.GetName()) + self.valobj = valobj + + def num_children(self): + # type: () -> int + return self.valobj.GetNumChildren() + + def get_child_index(self, name): + # type: (str) -> int + return self.valobj.GetIndexOfChildWithName(name) + + def get_child_at_index(self, index): + # type: (int) -> SBValue + return self.valobj.GetChildAtIndex(index) + + def update(self): + # type: () -> None + pass + + def has_children(self): + # type: () -> bool + return self.valobj.MightHaveChildren() + + +class EmptySyntheticProvider: + def __init__(self, valobj, dict): + # type: (SBValue, dict) -> EmptySyntheticProvider + # logger = Logger.Logger() + # logger >> "[EmptySyntheticProvider] for " + str(valobj.GetName()) + self.valobj = valobj + + def num_children(self): + # type: () -> int + return 0 + + def get_child_index(self, name): + # type: (str) -> int + return None + + def get_child_at_index(self, index): + # type: (int) -> SBValue + return None + + def update(self): + # type: () -> None + pass + + def has_children(self): + # type: () -> bool + return False + + +def SizeSummaryProvider(valobj, dict): + # type: (SBValue, dict) -> str + return 'size=' + str(valobj.GetNumChildren()) + + +def vec_to_string(vec): + length = vec.GetNumChildren() + chars = [vec.GetChildAtIndex(i).GetValueAsUnsigned() for i in range(length)] + return bytes(chars).decode(errors='replace') if PY3 else "".join(chr(char) for char in chars) + + +def StdStringSummaryProvider(valobj, dict): + # type: (SBValue, dict) -> str + # logger = Logger.Logger() + # logger >> "[StdStringSummaryProvider] for " + str(valobj.GetName()) + vec = valobj.GetChildAtIndex(0) + return '"%s"' % vec_to_string(vec) + + +def StdOsStringSummaryProvider(valobj, dict): + # type: (SBValue, dict) -> str + # logger = Logger.Logger() + # logger >> "[StdOsStringSummaryProvider] for " + str(valobj.GetName()) + buf = valobj.GetChildAtIndex(0).GetChildAtIndex(0) + is_windows = "Wtf8Buf" in buf.type.name + vec = buf.GetChildAtIndex(0) if is_windows else buf + return '"%s"' % vec_to_string(vec) + + +def StdStrSummaryProvider(valobj, dict): + # type: (SBValue, dict) -> str + # logger = Logger.Logger() + # logger >> "[StdStrSummaryProvider] for " + str(valobj.GetName()) + + length = valobj.GetChildMemberWithName("length").GetValueAsUnsigned() + if length == 0: + return '""' + + data_ptr = valobj.GetChildMemberWithName("data_ptr") + + start = data_ptr.GetValueAsUnsigned() + error = SBError() + process = data_ptr.GetProcess() + data = process.ReadMemory(start, length, error) + data = data.decode(encoding='UTF-8') if PY3 else data + return '"%s"' % data + + +class StructSyntheticProvider: + """Pretty-printer for structs and struct enum variants""" + + def __init__(self, valobj, dict, is_variant=False): + # type: (SBValue, dict, bool) -> StructSyntheticProvider + # logger = Logger.Logger() + self.valobj = valobj + self.is_variant = is_variant + self.type = valobj.GetType() + self.fields = {} + + if is_variant: + self.fields_count = self.type.GetNumberOfFields() - 1 + real_fields = self.type.fields[1:] + else: + self.fields_count = self.type.GetNumberOfFields() + real_fields = self.type.fields + + for number, field in enumerate(real_fields): + self.fields[field.name] = number + + def num_children(self): + # type: () -> int + return self.fields_count + + def get_child_index(self, name): + # type: (str) -> int + return self.fields.get(name, -1) + + def get_child_at_index(self, index): + # type: (int) -> SBValue + if self.is_variant: + field = self.type.GetFieldAtIndex(index + 1) + else: + field = self.type.GetFieldAtIndex(index) + return self.valobj.GetChildMemberWithName(field.name) + + def update(self): + # type: () -> None + pass + + def has_children(self): + # type: () -> bool + return True + + +class TupleSyntheticProvider: + """Pretty-printer for tuples and tuple enum variants""" + + def __init__(self, valobj, dict, is_variant=False): + # type: (SBValue, dict, bool) -> TupleSyntheticProvider + # logger = Logger.Logger() + self.valobj = valobj + self.is_variant = is_variant + self.type = valobj.GetType() + + if is_variant: + self.size = self.type.GetNumberOfFields() - 1 + else: + self.size = self.type.GetNumberOfFields() + + def num_children(self): + # type: () -> int + return self.size + + def get_child_index(self, name): + # type: (str) -> int + if name.isdigit(): + return int(name) + else: + return -1 + + def get_child_at_index(self, index): + # type: (int) -> SBValue + if self.is_variant: + field = self.type.GetFieldAtIndex(index + 1) + else: + field = self.type.GetFieldAtIndex(index) + element = self.valobj.GetChildMemberWithName(field.name) + return self.valobj.CreateValueFromData(str(index), element.GetData(), element.GetType()) + + def update(self): + # type: () -> None + pass + + def has_children(self): + # type: () -> bool + return True + + +class StdVecSyntheticProvider: + """Pretty-printer for alloc::vec::Vec + + struct Vec { buf: RawVec, len: usize } + struct RawVec { ptr: Unique, cap: usize, ... } + rust 1.31.1: struct Unique { pointer: NonZero<*const T>, ... } + rust 1.33.0: struct Unique { pointer: *const T, ... } + rust 1.62.0: struct Unique { pointer: NonNull, ... } + struct NonZero(T) + struct NonNull { pointer: *const T } + """ + + def __init__(self, valobj, dict): + # type: (SBValue, dict) -> StdVecSyntheticProvider + # logger = Logger.Logger() + # logger >> "[StdVecSyntheticProvider] for " + str(valobj.GetName()) + self.valobj = valobj + self.update() + + def num_children(self): + # type: () -> int + return self.length + + def get_child_index(self, name): + # type: (str) -> int + index = name.lstrip('[').rstrip(']') + if index.isdigit(): + return int(index) + else: + return -1 + + def get_child_at_index(self, index): + # type: (int) -> SBValue + start = self.data_ptr.GetValueAsUnsigned() + address = start + index * self.element_type_size + element = self.data_ptr.CreateValueFromAddress("[%s]" % index, address, self.element_type) + return element + + def update(self): + # type: () -> None + self.length = self.valobj.GetChildMemberWithName("len").GetValueAsUnsigned() + self.buf = self.valobj.GetChildMemberWithName("buf") + + self.data_ptr = unwrap_unique_or_non_null(self.buf.GetChildMemberWithName("ptr")) + + self.element_type = self.data_ptr.GetType().GetPointeeType() + self.element_type_size = self.element_type.GetByteSize() + + def has_children(self): + # type: () -> bool + return True + + +class StdSliceSyntheticProvider: + def __init__(self, valobj, dict): + self.valobj = valobj + self.update() + + def num_children(self): + # type: () -> int + return self.length + + def get_child_index(self, name): + # type: (str) -> int + index = name.lstrip('[').rstrip(']') + if index.isdigit(): + return int(index) + else: + return -1 + + def get_child_at_index(self, index): + # type: (int) -> SBValue + start = self.data_ptr.GetValueAsUnsigned() + address = start + index * self.element_type_size + element = self.data_ptr.CreateValueFromAddress("[%s]" % index, address, self.element_type) + return element + + def update(self): + # type: () -> None + self.length = self.valobj.GetChildMemberWithName("length").GetValueAsUnsigned() + self.data_ptr = self.valobj.GetChildMemberWithName("data_ptr") + + self.element_type = self.data_ptr.GetType().GetPointeeType() + self.element_type_size = self.element_type.GetByteSize() + + def has_children(self): + # type: () -> bool + return True + + +class StdVecDequeSyntheticProvider: + """Pretty-printer for alloc::collections::vec_deque::VecDeque + + struct VecDeque { tail: usize, head: usize, buf: RawVec } + """ + + def __init__(self, valobj, dict): + # type: (SBValue, dict) -> StdVecDequeSyntheticProvider + # logger = Logger.Logger() + # logger >> "[StdVecDequeSyntheticProvider] for " + str(valobj.GetName()) + self.valobj = valobj + self.update() + + def num_children(self): + # type: () -> int + return self.size + + def get_child_index(self, name): + # type: (str) -> int + index = name.lstrip('[').rstrip(']') + if index.isdigit() and self.tail <= index and (self.tail + index) % self.cap < self.head: + return int(index) + else: + return -1 + + def get_child_at_index(self, index): + # type: (int) -> SBValue + start = self.data_ptr.GetValueAsUnsigned() + address = start + ((index + self.tail) % self.cap) * self.element_type_size + element = self.data_ptr.CreateValueFromAddress("[%s]" % index, address, self.element_type) + return element + + def update(self): + # type: () -> None + self.head = self.valobj.GetChildMemberWithName("head").GetValueAsUnsigned() + self.tail = self.valobj.GetChildMemberWithName("tail").GetValueAsUnsigned() + self.buf = self.valobj.GetChildMemberWithName("buf") + self.cap = self.buf.GetChildMemberWithName("cap").GetValueAsUnsigned() + if self.head >= self.tail: + self.size = self.head - self.tail + else: + self.size = self.cap + self.head - self.tail + + self.data_ptr = unwrap_unique_or_non_null(self.buf.GetChildMemberWithName("ptr")) + + self.element_type = self.data_ptr.GetType().GetPointeeType() + self.element_type_size = self.element_type.GetByteSize() + + def has_children(self): + # type: () -> bool + return True + + +# BACKCOMPAT: rust 1.35 +class StdOldHashMapSyntheticProvider: + """Pretty-printer for std::collections::hash::map::HashMap + + struct HashMap {..., table: RawTable, ... } + struct RawTable { capacity_mask: usize, size: usize, hashes: TaggedHashUintPtr, ... } + """ + + def __init__(self, valobj, dict, show_values=True): + # type: (SBValue, dict, bool) -> StdOldHashMapSyntheticProvider + self.valobj = valobj + self.show_values = show_values + self.update() + + def num_children(self): + # type: () -> int + return self.size + + def get_child_index(self, name): + # type: (str) -> int + index = name.lstrip('[').rstrip(']') + if index.isdigit(): + return int(index) + else: + return -1 + + def get_child_at_index(self, index): + # type: (int) -> SBValue + # logger = Logger.Logger() + start = self.data_ptr.GetValueAsUnsigned() & ~1 + + # See `libstd/collections/hash/table.rs:raw_bucket_at + hashes = self.hash_uint_size * self.capacity + align = self.pair_type_size + # See `libcore/alloc.rs:padding_needed_for` + len_rounded_up = (((((hashes + align) % self.modulo - 1) % self.modulo) & ~( + (align - 1) % self.modulo)) % self.modulo - hashes) % self.modulo + # len_rounded_up = ((hashes + align - 1) & ~(align - 1)) - hashes + + pairs_offset = hashes + len_rounded_up + pairs_start = start + pairs_offset + + table_index = self.valid_indices[index] + idx = table_index & self.capacity_mask + address = pairs_start + idx * self.pair_type_size + element = self.data_ptr.CreateValueFromAddress("[%s]" % index, address, self.pair_type) + if self.show_values: + return element + else: + key = element.GetChildAtIndex(0) + return self.valobj.CreateValueFromData("[%s]" % index, key.GetData(), key.GetType()) + + def update(self): + # type: () -> None + # logger = Logger.Logger() + + self.table = self.valobj.GetChildMemberWithName("table") # type: SBValue + self.size = self.table.GetChildMemberWithName("size").GetValueAsUnsigned() + self.hashes = self.table.GetChildMemberWithName("hashes") + self.hash_uint_type = self.hashes.GetType() + self.hash_uint_size = self.hashes.GetType().GetByteSize() + self.modulo = 2 ** self.hash_uint_size + self.data_ptr = self.hashes.GetChildAtIndex(0).GetChildAtIndex(0) + + self.capacity_mask = self.table.GetChildMemberWithName("capacity_mask").GetValueAsUnsigned() + self.capacity = (self.capacity_mask + 1) % self.modulo + + marker = self.table.GetChildMemberWithName("marker").GetType() # type: SBType + self.pair_type = marker.template_args[0] + self.pair_type_size = self.pair_type.GetByteSize() + + self.valid_indices = [] + for idx in range(self.capacity): + address = self.data_ptr.GetValueAsUnsigned() + idx * self.hash_uint_size + hash_uint = self.data_ptr.CreateValueFromAddress("[%s]" % idx, address, + self.hash_uint_type) + hash_ptr = hash_uint.GetChildAtIndex(0).GetChildAtIndex(0) + if hash_ptr.GetValueAsUnsigned() != 0: + self.valid_indices.append(idx) + + # logger >> "Valid indices: {}".format(str(self.valid_indices)) + + def has_children(self): + # type: () -> bool + return True + + +class StdHashMapSyntheticProvider: + """Pretty-printer for hashbrown's HashMap""" + + def __init__(self, valobj, dict, show_values=True): + # type: (SBValue, dict, bool) -> StdHashMapSyntheticProvider + self.valobj = valobj + self.show_values = show_values + self.update() + + def num_children(self): + # type: () -> int + return self.size + + def get_child_index(self, name): + # type: (str) -> int + index = name.lstrip('[').rstrip(']') + if index.isdigit(): + return int(index) + else: + return -1 + + def get_child_at_index(self, index): + # type: (int) -> SBValue + pairs_start = self.data_ptr.GetValueAsUnsigned() + idx = self.valid_indices[index] + if self.new_layout: + idx = -(idx + 1) + address = pairs_start + idx * self.pair_type_size + element = self.data_ptr.CreateValueFromAddress("[%s]" % index, address, self.pair_type) + if self.show_values: + return element + else: + key = element.GetChildAtIndex(0) + return self.valobj.CreateValueFromData("[%s]" % index, key.GetData(), key.GetType()) + + def update(self): + # type: () -> None + table = self.table() + inner_table = table.GetChildMemberWithName("table") + + capacity = inner_table.GetChildMemberWithName("bucket_mask").GetValueAsUnsigned() + 1 + ctrl = inner_table.GetChildMemberWithName("ctrl").GetChildAtIndex(0) + + self.size = inner_table.GetChildMemberWithName("items").GetValueAsUnsigned() + self.pair_type = table.type.template_args[0] + if self.pair_type.IsTypedefType(): + self.pair_type = self.pair_type.GetTypedefedType() + self.pair_type_size = self.pair_type.GetByteSize() + + self.new_layout = not inner_table.GetChildMemberWithName("data").IsValid() + if self.new_layout: + self.data_ptr = ctrl.Cast(self.pair_type.GetPointerType()) + else: + self.data_ptr = inner_table.GetChildMemberWithName("data").GetChildAtIndex(0) + + u8_type = self.valobj.GetTarget().GetBasicType(eBasicTypeUnsignedChar) + u8_type_size = self.valobj.GetTarget().GetBasicType(eBasicTypeUnsignedChar).GetByteSize() + + self.valid_indices = [] + for idx in range(capacity): + address = ctrl.GetValueAsUnsigned() + idx * u8_type_size + value = ctrl.CreateValueFromAddress("ctrl[%s]" % idx, address, + u8_type).GetValueAsUnsigned() + is_present = value & 128 == 0 + if is_present: + self.valid_indices.append(idx) + + def table(self): + # type: () -> SBValue + if self.show_values: + hashbrown_hashmap = self.valobj.GetChildMemberWithName("base") + else: + # BACKCOMPAT: rust 1.47 + # HashSet wraps either std HashMap or hashbrown::HashSet, which both + # wrap hashbrown::HashMap, so either way we "unwrap" twice. + hashbrown_hashmap = self.valobj.GetChildAtIndex(0).GetChildAtIndex(0) + return hashbrown_hashmap.GetChildMemberWithName("table") + + def has_children(self): + # type: () -> bool + return True + + +def StdRcSummaryProvider(valobj, dict): + # type: (SBValue, dict) -> str + strong = valobj.GetChildMemberWithName("strong").GetValueAsUnsigned() + weak = valobj.GetChildMemberWithName("weak").GetValueAsUnsigned() + return "strong={}, weak={}".format(strong, weak) + + +class StdRcSyntheticProvider: + """Pretty-printer for alloc::rc::Rc and alloc::sync::Arc + + struct Rc { ptr: NonNull>, ... } + rust 1.31.1: struct NonNull { pointer: NonZero<*const T> } + rust 1.33.0: struct NonNull { pointer: *const T } + struct NonZero(T) + struct RcBox { strong: Cell, weak: Cell, value: T } + struct Cell { value: UnsafeCell } + struct UnsafeCell { value: T } + + struct Arc { ptr: NonNull>, ... } + struct ArcInner { strong: atomic::AtomicUsize, weak: atomic::AtomicUsize, data: T } + struct AtomicUsize { v: UnsafeCell } + """ + + def __init__(self, valobj, dict, is_atomic=False): + # type: (SBValue, dict, bool) -> StdRcSyntheticProvider + self.valobj = valobj + + self.ptr = unwrap_unique_or_non_null(self.valobj.GetChildMemberWithName("ptr")) + + self.value = self.ptr.GetChildMemberWithName("data" if is_atomic else "value") + + self.strong = self.ptr.GetChildMemberWithName("strong").GetChildAtIndex( + 0).GetChildMemberWithName("value") + self.weak = self.ptr.GetChildMemberWithName("weak").GetChildAtIndex( + 0).GetChildMemberWithName("value") + + self.value_builder = ValueBuilder(valobj) + + self.update() + + def num_children(self): + # type: () -> int + # Actually there are 3 children, but only the `value` should be shown as a child + return 1 + + def get_child_index(self, name): + # type: (str) -> int + if name == "value": + return 0 + if name == "strong": + return 1 + if name == "weak": + return 2 + return -1 + + def get_child_at_index(self, index): + # type: (int) -> SBValue + if index == 0: + return self.value + if index == 1: + return self.value_builder.from_uint("strong", self.strong_count) + if index == 2: + return self.value_builder.from_uint("weak", self.weak_count) + + return None + + def update(self): + # type: () -> None + self.strong_count = self.strong.GetValueAsUnsigned() + self.weak_count = self.weak.GetValueAsUnsigned() - 1 + + def has_children(self): + # type: () -> bool + return True + + +class StdCellSyntheticProvider: + """Pretty-printer for std::cell::Cell""" + + def __init__(self, valobj, dict): + # type: (SBValue, dict) -> StdCellSyntheticProvider + self.valobj = valobj + self.value = valobj.GetChildMemberWithName("value").GetChildAtIndex(0) + + def num_children(self): + # type: () -> int + return 1 + + def get_child_index(self, name): + # type: (str) -> int + if name == "value": + return 0 + return -1 + + def get_child_at_index(self, index): + # type: (int) -> SBValue + if index == 0: + return self.value + return None + + def update(self): + # type: () -> None + pass + + def has_children(self): + # type: () -> bool + return True + + +def StdRefSummaryProvider(valobj, dict): + # type: (SBValue, dict) -> str + borrow = valobj.GetChildMemberWithName("borrow").GetValueAsSigned() + return "borrow={}".format(borrow) if borrow >= 0 else "borrow_mut={}".format(-borrow) + + +class StdRefSyntheticProvider: + """Pretty-printer for std::cell::Ref, std::cell::RefMut, and std::cell::RefCell""" + + def __init__(self, valobj, dict, is_cell=False): + # type: (SBValue, dict, bool) -> StdRefSyntheticProvider + self.valobj = valobj + + borrow = valobj.GetChildMemberWithName("borrow") + value = valobj.GetChildMemberWithName("value") + if is_cell: + self.borrow = borrow.GetChildMemberWithName("value").GetChildMemberWithName("value") + self.value = value.GetChildMemberWithName("value") + else: + self.borrow = borrow.GetChildMemberWithName("borrow").GetChildMemberWithName( + "value").GetChildMemberWithName("value") + self.value = value.Dereference() + + self.value_builder = ValueBuilder(valobj) + + self.update() + + def num_children(self): + # type: () -> int + # Actually there are 2 children, but only the `value` should be shown as a child + return 1 + + def get_child_index(self, name): + if name == "value": + return 0 + if name == "borrow": + return 1 + return -1 + + def get_child_at_index(self, index): + # type: (int) -> SBValue + if index == 0: + return self.value + if index == 1: + return self.value_builder.from_int("borrow", self.borrow_count) + return None + + def update(self): + # type: () -> None + self.borrow_count = self.borrow.GetValueAsSigned() + + def has_children(self): + # type: () -> bool + return True diff --git a/lldb/scripts/solana/rust_types.py b/lldb/scripts/solana/rust_types.py new file mode 100644 index 0000000000000..bbc945a7ddab0 --- /dev/null +++ b/lldb/scripts/solana/rust_types.py @@ -0,0 +1,113 @@ +import re + + +class RustType(object): + OTHER = "Other" + STRUCT = "Struct" + TUPLE = "Tuple" + CSTYLE_VARIANT = "CStyleVariant" + TUPLE_VARIANT = "TupleVariant" + STRUCT_VARIANT = "StructVariant" + ENUM = "Enum" + EMPTY = "Empty" + SINGLETON_ENUM = "SingletonEnum" + REGULAR_ENUM = "RegularEnum" + COMPRESSED_ENUM = "CompressedEnum" + REGULAR_UNION = "RegularUnion" + + STD_STRING = "StdString" + STD_OS_STRING = "StdOsString" + STD_STR = "StdStr" + STD_SLICE = "StdSlice" + STD_VEC = "StdVec" + STD_VEC_DEQUE = "StdVecDeque" + STD_BTREE_SET = "StdBTreeSet" + STD_BTREE_MAP = "StdBTreeMap" + STD_HASH_MAP = "StdHashMap" + STD_HASH_SET = "StdHashSet" + STD_RC = "StdRc" + STD_ARC = "StdArc" + STD_CELL = "StdCell" + STD_REF = "StdRef" + STD_REF_MUT = "StdRefMut" + STD_REF_CELL = "StdRefCell" + + +STD_STRING_REGEX = re.compile(r"^(alloc::(\w+::)+)String$") +STD_STR_REGEX = re.compile(r"^&(mut )?str$") +STD_SLICE_REGEX = re.compile(r"^&(mut )?\[.+\]$") +STD_OS_STRING_REGEX = re.compile(r"^(std::ffi::(\w+::)+)OsString$") +STD_VEC_REGEX = re.compile(r"^(alloc::(\w+::)+)Vec<.+>$") +STD_VEC_DEQUE_REGEX = re.compile(r"^(alloc::(\w+::)+)VecDeque<.+>$") +STD_BTREE_SET_REGEX = re.compile(r"^(alloc::(\w+::)+)BTreeSet<.+>$") +STD_BTREE_MAP_REGEX = re.compile(r"^(alloc::(\w+::)+)BTreeMap<.+>$") +STD_HASH_MAP_REGEX = re.compile(r"^(std::collections::(\w+::)+)HashMap<.+>$") +STD_HASH_SET_REGEX = re.compile(r"^(std::collections::(\w+::)+)HashSet<.+>$") +STD_RC_REGEX = re.compile(r"^(alloc::(\w+::)+)Rc<.+>$") +STD_ARC_REGEX = re.compile(r"^(alloc::(\w+::)+)Arc<.+>$") +STD_CELL_REGEX = re.compile(r"^(core::(\w+::)+)Cell<.+>$") +STD_REF_REGEX = re.compile(r"^(core::(\w+::)+)Ref<.+>$") +STD_REF_MUT_REGEX = re.compile(r"^(core::(\w+::)+)RefMut<.+>$") +STD_REF_CELL_REGEX = re.compile(r"^(core::(\w+::)+)RefCell<.+>$") + +TUPLE_ITEM_REGEX = re.compile(r"__\d+$") + +ENCODED_ENUM_PREFIX = "RUST$ENCODED$ENUM$" +ENUM_DISR_FIELD_NAME = "<>" + +STD_TYPE_TO_REGEX = { + RustType.STD_STRING: STD_STRING_REGEX, + RustType.STD_OS_STRING: STD_OS_STRING_REGEX, + RustType.STD_STR: STD_STR_REGEX, + RustType.STD_SLICE: STD_SLICE_REGEX, + RustType.STD_VEC: STD_VEC_REGEX, + RustType.STD_VEC_DEQUE: STD_VEC_DEQUE_REGEX, + RustType.STD_HASH_MAP: STD_HASH_MAP_REGEX, + RustType.STD_HASH_SET: STD_HASH_SET_REGEX, + RustType.STD_BTREE_SET: STD_BTREE_SET_REGEX, + RustType.STD_BTREE_MAP: STD_BTREE_MAP_REGEX, + RustType.STD_RC: STD_RC_REGEX, + RustType.STD_ARC: STD_ARC_REGEX, + RustType.STD_REF: STD_REF_REGEX, + RustType.STD_REF_MUT: STD_REF_MUT_REGEX, + RustType.STD_REF_CELL: STD_REF_CELL_REGEX, + RustType.STD_CELL: STD_CELL_REGEX, +} + +def is_tuple_fields(fields): + # type: (list) -> bool + return all(TUPLE_ITEM_REGEX.match(str(field.name)) for field in fields) + + +def classify_struct(name, fields): + if len(fields) == 0: + return RustType.EMPTY + + for ty, regex in STD_TYPE_TO_REGEX.items(): + if regex.match(name): + return ty + + if fields[0].name == ENUM_DISR_FIELD_NAME: + return RustType.ENUM + + if is_tuple_fields(fields): + return RustType.TUPLE + + return RustType.STRUCT + + +def classify_union(fields): + if len(fields) == 0: + return RustType.EMPTY + + first_variant_name = fields[0].name + if first_variant_name is None: + if len(fields) == 1: + return RustType.SINGLETON_ENUM + else: + return RustType.REGULAR_ENUM + elif first_variant_name.startswith(ENCODED_ENUM_PREFIX): + assert len(fields) == 1 + return RustType.COMPRESSED_ENUM + else: + return RustType.REGULAR_UNION diff --git a/lldb/scripts/solana/solana-lldb b/lldb/scripts/solana/solana-lldb new file mode 100755 index 0000000000000..5f996a5b4dcf8 --- /dev/null +++ b/lldb/scripts/solana/solana-lldb @@ -0,0 +1,28 @@ +#!/bin/sh + +set -e + +here=$(dirname "$0") +lldb=${here}/lldb +if ! command -v "$lldb" > /dev/null; then + echo "LLDB not found!" >&2 + exit 1 +else + LLDB_VERSION=$("$lldb" --version | cut -d ' ' -f3) + + if [ "$LLDB_VERSION" = "3.5.0" ]; then + cat << EOF >&2 +*** +WARNING: This version of LLDB has known issues with Rust and cannot display the contents of local variables! +*** +EOF + fi +fi + +script_import_rust="command script import \"${here}/lldb_lookup.py\"" +script_import_solana="command script import \"${here}/solana_lookup.py\"" +commands_file_rust="${here}/lldb_commands" +commands_file_solana="${here}/solana_commands" + +# Call LLDB with the commands added to the argument list +"$lldb" --one-line-before-file "$script_import_rust" --one-line-before-file "$script_import_solana" --source-before-file "$commands_file_rust" --source-before-file "$commands_file_solana" "$@" diff --git a/lldb/scripts/solana/solana_commands b/lldb/scripts/solana/solana_commands new file mode 100644 index 0000000000000..b2a3fc4b95427 --- /dev/null +++ b/lldb/scripts/solana/solana_commands @@ -0,0 +1,3 @@ +type summary add -F solana_lookup.summary_lookup solana_program::account_info::AccountInfo --category Solana +type summary add -F solana_lookup.summary_lookup solana_program::pubkey::Pubkey --category Solana +type category enable Solana diff --git a/lldb/scripts/solana/solana_lookup.py b/lldb/scripts/solana/solana_lookup.py new file mode 100644 index 0000000000000..297d986bdf295 --- /dev/null +++ b/lldb/scripts/solana/solana_lookup.py @@ -0,0 +1,12 @@ +from solana_providers import * +from solana_types import SolanaType, classify_solana_type + + +def summary_lookup(valobj, dict): + # type: (SBValue, dict) -> str + """Returns the summary provider for the given value""" + solana_type = classify_solana_type(valobj.GetType()) + if solana_type == SolanaType.PUBKEY: + return PubkeySummaryProvider(valobj, dict) + if solana_type == SolanaType.ACCOUNT_INFO: + return AccountInfoSummaryProvider(valobj, dict) diff --git a/lldb/scripts/solana/solana_providers.py b/lldb/scripts/solana/solana_providers.py new file mode 100644 index 0000000000000..97514a5c03f06 --- /dev/null +++ b/lldb/scripts/solana/solana_providers.py @@ -0,0 +1,80 @@ +import lldb + + +def encode_b58(num): + alphabet = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz" + b58 = "" + while num != 0: + b58 += alphabet[num % 58] + num //= 58 + return b58[::-1] + +def PubkeySummaryProvider(valobj, internal_dict): + err = lldb.SBError() + if valobj.TypeIsPointerType(): + program_id_type = valobj.GetType().GetPointeeType() + value = valobj.GetPointeeData() + else: + value = valobj.GetData() + pubkey = [value.GetUnsignedInt8(err, i) for i in range(32)] + pubkey = ''.join("{0:0{1}x}".format(i, 2) for i in pubkey) + pubkey = encode_b58(int(pubkey, 16)) + + if valobj.TypeIsPointerType(): + return "-> Pubkey = {}".format(pubkey) + return "{}".format(pubkey) + + +def AccountInfoSummaryProvider(valobj, internal_dict): + err = lldb.SBError() + # key + key_valobj = valobj.GetChildAtIndex(0) + + # is_signer + signer_valobj = valobj.GetChildAtIndex(1) + + # is_writable + writable_valobj = valobj.GetChildAtIndex(2) + + # lamports + lamport_valobj = valobj.GetChildAtIndex(3) + lamport_valobj = lamport_valobj.GetChildAtIndex(0) + lamport_valobj = lamport_valobj.GetChildAtIndex(0) + lamport_valobj = lamport_valobj.GetChildAtIndex(0) + lamports_data = lamport_valobj.GetData(); + lamports = lamports_data.GetUnsignedInt64(err, 0) + + # data + data_valobj = valobj.GetChildAtIndex(4) + data_valobj = data_valobj.GetChildAtIndex(0) + data_valobj = data_valobj.GetChildAtIndex(0) + data_valobj = data_valobj.__str__().replace("value", "data") + data_valobj = data_valobj.__str__().replace(" [", " [") + data_valobj = data_valobj.__str__().replace("}", " }") + + # owner + owner_valobj = valobj.GetChildAtIndex(5) + + # executable + executable_valobj = valobj.GetChildAtIndex(6) + + # rent_epoch + rent_epoch_valobj = valobj.GetChildAtIndex(7) + rent_epoch_data = rent_epoch_valobj.GetData(); + rent_epoch = rent_epoch_data.GetUnsignedInt64(err, 0) + + ret_string = "" + if valobj.TypeIsPointerType(): + ret_string = "-> " + + return ret_string + """{{ + {} + {} + {} + (u64) lamports = {} + {} + {} + {} + (u64) rent_epoch = {} +}} + """.format(key_valobj, signer_valobj, writable_valobj, lamports, owner_valobj, executable_valobj, data_valobj, rent_epoch) diff --git a/lldb/scripts/solana/solana_types.py b/lldb/scripts/solana/solana_types.py new file mode 100644 index 0000000000000..67ff9d240dac4 --- /dev/null +++ b/lldb/scripts/solana/solana_types.py @@ -0,0 +1,19 @@ +import re + + +class SolanaType(object): + PUBKEY = "Pubkey" + ACCOUNT_INFO = "AccountInfo" + +PUBKEY_REGEX = re.compile(r"^(solana_program::pubkey::Pubkey)") +ACCOUNT_INFO_REGEX = re.compile(r"^(solana_program::account_info::AccountInfo)") + +SOLANA_TYPE_TO_REGEX = { + SolanaType.PUBKEY: PUBKEY_REGEX, + SolanaType.ACCOUNT_INFO: ACCOUNT_INFO_REGEX, +} + +def classify_solana_type(type): + for ty, regex in SOLANA_TYPE_TO_REGEX.items(): + if regex.match(type.name): + return ty diff --git a/lldb/source/Core/Disassembler.cpp b/lldb/source/Core/Disassembler.cpp index b05be7e1a46d7..d2c447d13aee9 100644 --- a/lldb/source/Core/Disassembler.cpp +++ b/lldb/source/Core/Disassembler.cpp @@ -635,21 +635,22 @@ void Instruction::Dump(lldb_private::Stream *s, uint32_t max_opcode_byte_size, } if (show_bytes) { + ArchSpec arch = exe_ctx->GetTargetPtr()->GetArchitecture(); if (m_opcode.GetType() == Opcode::eTypeBytes) { // x86_64 and i386 are the only ones that use bytes right now so pad out // the byte dump to be able to always show 15 bytes (3 chars each) plus a // space if (max_opcode_byte_size > 0) - m_opcode.Dump(&ss, max_opcode_byte_size * 3 + 1); + m_opcode.Dump(&ss, max_opcode_byte_size * 3 + 1, arch); else - m_opcode.Dump(&ss, 15 * 3 + 1); + m_opcode.Dump(&ss, 15 * 3 + 1, arch); } else { // Else, we have ARM or MIPS which can show up to a uint32_t 0x00000000 // (10 spaces) plus two for padding... if (max_opcode_byte_size > 0) - m_opcode.Dump(&ss, max_opcode_byte_size * 3 + 1); + m_opcode.Dump(&ss, max_opcode_byte_size * 3 + 1, arch); else - m_opcode.Dump(&ss, 12); + m_opcode.Dump(&ss, 12, arch); } } diff --git a/lldb/source/Core/Opcode.cpp b/lldb/source/Core/Opcode.cpp index 3e30d98975d8a..6143052a8adfc 100644 --- a/lldb/source/Core/Opcode.cpp +++ b/lldb/source/Core/Opcode.cpp @@ -21,7 +21,7 @@ using namespace lldb; using namespace lldb_private; -int Opcode::Dump(Stream *s, uint32_t min_byte_width) { +int Opcode::Dump(Stream *s, uint32_t min_byte_width, const ArchSpec &arch) { const uint32_t previous_bytes = s->GetWrittenBytes(); switch (m_type) { case Opcode::eTypeInvalid: @@ -39,7 +39,15 @@ int Opcode::Dump(Stream *s, uint32_t min_byte_width) { break; case Opcode::eType64: - s->Printf("0x%16.16" PRIx64, m_data.inst64); + if (arch.GetMachine() == llvm::Triple::sbf) { + for (uint32_t i = 0; i < 8; ++i) { + if (i > 0) + s->PutChar(' '); + s->Printf("%2.2x", m_data.inst.bytes[i]); + } + } + else + s->Printf("0x%16.16" PRIx64, m_data.inst64); break; case Opcode::eTypeBytes: diff --git a/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp b/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp index 13e1198516f78..e7184aacce16b 100644 --- a/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp +++ b/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp @@ -249,6 +249,23 @@ bool ELFNote::Parse(const DataExtractor &data, lldb::offset_t *offset) { return true; } +static uint32_t sbfVariantFromElfFlags(const elf::ELFHeader &header) { + switch (header.e_flags) { + case llvm::ELF::EF_SBF_V0: + return ArchSpec::eSBFSubType_sbfv0; + case llvm::ELF::EF_SBF_V1: + return ArchSpec::eSBFSubType_sbfv1; + case llvm::ELF::EF_SBF_V2: + return ArchSpec::eSBFSubType_sbfv2; + case llvm::ELF::EF_SBF_V3: + return ArchSpec::eSBFSubType_sbfv3; + case llvm::ELF::EF_SBF_V4: + return ArchSpec::eSBFSubType_sbfv4; + default: + return ArchSpec::eSBFSubType_sbfv0; + } +} + static uint32_t mipsVariantFromElfFlags (const elf::ELFHeader &header) { const uint32_t mips_arch = header.e_flags & llvm::ELF::EF_MIPS_ARCH; uint32_t endian = header.e_ident[EI_DATA]; @@ -343,6 +360,10 @@ static uint32_t subTypeFromElfHeader(const elf::ELFHeader &header) { return riscvVariantFromElfFlags(header); else if (header.e_machine == llvm::ELF::EM_LOONGARCH) return loongarchVariantFromElfFlags(header); + else if (header.e_machine == llvm::ELF::EM_BPF) + return sbfVariantFromElfFlags(header); + else if (header.e_machine == llvm::ELF::EM_SBF) + return sbfVariantFromElfFlags(header); return LLDB_INVALID_CPUTYPE; } diff --git a/lldb/source/Plugins/Platform/Linux/PlatformLinux.cpp b/lldb/source/Plugins/Platform/Linux/PlatformLinux.cpp index 13465986f49c5..754540230b3db 100644 --- a/lldb/source/Plugins/Platform/Linux/PlatformLinux.cpp +++ b/lldb/source/Plugins/Platform/Linux/PlatformLinux.cpp @@ -123,7 +123,8 @@ PlatformLinux::PlatformLinux(bool is_host) {llvm::Triple::x86_64, llvm::Triple::x86, llvm::Triple::arm, llvm::Triple::aarch64, llvm::Triple::mips64, llvm::Triple::mips64, llvm::Triple::hexagon, llvm::Triple::mips, llvm::Triple::mips64el, - llvm::Triple::mipsel, llvm::Triple::msp430, llvm::Triple::systemz}, + llvm::Triple::mipsel, llvm::Triple::msp430, llvm::Triple::systemz, + llvm::Triple::sbf}, llvm::Triple::Linux); } } diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugAranges.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugAranges.cpp index a1a70ac1c9e85..581bd907b868c 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugAranges.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugAranges.cpp @@ -41,7 +41,7 @@ void DWARFDebugAranges::extract(const DWARFDataExtractor &debug_aranges_data) { } const uint64_t cu_offset = set.getCompileUnitDIEOffset(); for (const auto &desc : set.descriptors()) { - if (desc.Length != 0) + if (desc.Length != 0 && desc.Address > 0) m_aranges.Append( RangeToDIE::Entry(desc.Address, desc.Length, cu_offset)); } @@ -63,7 +63,7 @@ void DWARFDebugAranges::Dump(Log *log) const { void DWARFDebugAranges::AppendRange(dw_offset_t offset, dw_addr_t low_pc, dw_addr_t high_pc) { - if (high_pc > low_pc) + if (high_pc > low_pc && low_pc > 0) m_aranges.Append(RangeToDIE::Entry(low_pc, high_pc - low_pc, offset)); } diff --git a/lldb/source/Utility/ArchSpec.cpp b/lldb/source/Utility/ArchSpec.cpp index b13e8ff1ec373..ab1b4bbb33ca4 100644 --- a/lldb/source/Utility/ArchSpec.cpp +++ b/lldb/source/Utility/ArchSpec.cpp @@ -248,6 +248,12 @@ static const CoreDefinition g_core_definitions[] = { {eByteOrderLittle, 4, 1, 4, llvm::Triple::wasm32, ArchSpec::eCore_wasm32, "wasm32"}, + {eByteOrderLittle, 8, 8, 8, llvm::Triple::bpfel, ArchSpec::eCore_bpf, "bpf"}, + {eByteOrderLittle, 8, 8, 8, llvm::Triple::sbf, ArchSpec::eCore_sbfv0, "sbf"}, + {eByteOrderLittle, 8, 8, 8, llvm::Triple::sbf, ArchSpec::eCore_sbfv1, "sbfv1"}, + {eByteOrderLittle, 8, 8, 8, llvm::Triple::sbf, ArchSpec::eCore_sbfv2, "sbfv2"}, + {eByteOrderLittle, 8, 8, 8, llvm::Triple::sbf, ArchSpec::eCore_sbfv3, "sbfv3"}, + {eByteOrderLittle, 8, 8, 8, llvm::Triple::sbf, ArchSpec::eCore_sbfv4, "sbfv4"}, }; // Ensure that we have an entry in the g_core_definitions for each core. If you @@ -432,6 +438,18 @@ static const ArchDefinitionEntry g_elf_arch_entries[] = { {ArchSpec::eCore_loongarch64, llvm::ELF::EM_LOONGARCH, ArchSpec::eLoongArchSubType_loongarch64, 0xFFFFFFFFu, 0xFFFFFFFFu}, // loongarch64 + {ArchSpec::eCore_bpf, llvm::ELF::EM_BPF, LLDB_INVALID_CPUTYPE, + 0xFFFFFFFFu, 0xFFFFFFFFu}, // bpf + {ArchSpec::eCore_sbfv0, llvm::ELF::EM_SBF, ArchSpec::eSBFSubType_sbfv0, + 0xFFFFFFFFu, 0xFFFFFFFFu}, // sbf + {ArchSpec::eCore_sbfv1, llvm::ELF::EM_SBF, ArchSpec::eSBFSubType_sbfv1, + 0xFFFFFFFFu, 0xFFFFFFFFu}, // sbfv1 + {ArchSpec::eCore_sbfv2, llvm::ELF::EM_SBF, ArchSpec::eSBFSubType_sbfv2, + 0xFFFFFFFFu, 0xFFFFFFFFu}, // sbfv2 + {ArchSpec::eCore_sbfv3, llvm::ELF::EM_SBF, ArchSpec::eSBFSubType_sbfv3, + 0xFFFFFFFFu, 0xFFFFFFFFu}, // sbfv3 + {ArchSpec::eCore_sbfv4, llvm::ELF::EM_SBF, ArchSpec::eSBFSubType_sbfv4, + 0xFFFFFFFFu, 0xFFFFFFFFu}, // sbfv3 }; static const ArchDefinition g_elf_arch_def = { diff --git a/llvm/CMakeLists.txt b/llvm/CMakeLists.txt index f5293e8663243..e58be29f1f664 100644 --- a/llvm/CMakeLists.txt +++ b/llvm/CMakeLists.txt @@ -492,6 +492,7 @@ set(LLVM_ALL_TARGETS NVPTX PowerPC RISCV + SBF Sparc SPIRV SystemZ diff --git a/llvm/include/llvm/BinaryFormat/ELF.h b/llvm/include/llvm/BinaryFormat/ELF.h index 8853c4a88b0b5..900db3861859e 100644 --- a/llvm/include/llvm/BinaryFormat/ELF.h +++ b/llvm/include/llvm/BinaryFormat/ELF.h @@ -323,6 +323,7 @@ enum { EM_VE = 251, // NEC SX-Aurora VE EM_CSKY = 252, // C-SKY 32-bit processor EM_LOONGARCH = 258, // LoongArch + EM_SBF = 263 // Solana Bytecode Format }; // Object file classes. @@ -950,6 +951,20 @@ enum : unsigned { EF_CUDA_VIRTUAL_SM = 0xff0000, }; +// SBF specific e_flags +enum : unsigned { + EF_SBF_V0 = 0x00, + EF_SBF_V1 = 0x01, + EF_SBF_V2 = 0x02, + EF_SBF_V3 = 0x03, + EF_SBF_V4 = 0x04, +}; + +// ELF Relocation types for SBF. +enum { +#include "ELFRelocs/SBF.def" +}; + // ELF Relocation types for BPF enum { #include "ELFRelocs/BPF.def" diff --git a/llvm/include/llvm/BinaryFormat/ELFRelocs/SBF.def b/llvm/include/llvm/BinaryFormat/ELFRelocs/SBF.def new file mode 100644 index 0000000000000..01a7eb09e8ec6 --- /dev/null +++ b/llvm/include/llvm/BinaryFormat/ELFRelocs/SBF.def @@ -0,0 +1,12 @@ +#ifndef ELF_RELOC +#error "ELF_RELOC must be defined" +#endif + +// Currently these match one-to-one with BPF relocations. +ELF_RELOC(R_SBF_NONE, 0) +ELF_RELOC(R_SBF_64_64, 1) +ELF_RELOC(R_SBF_64_ABS64, 2) +ELF_RELOC(R_SBF_64_ABS32, 3) +ELF_RELOC(R_SBF_64_NODYLD32, 4) +ELF_RELOC(R_SBF_64_RELATIVE, 8) // B + A +ELF_RELOC(R_SBF_64_32, 10) diff --git a/llvm/include/llvm/Object/ELFObjectFile.h b/llvm/include/llvm/Object/ELFObjectFile.h index 60c72062a3f6a..aae09c5bed3b1 100644 --- a/llvm/include/llvm/Object/ELFObjectFile.h +++ b/llvm/include/llvm/Object/ELFObjectFile.h @@ -1343,6 +1343,8 @@ StringRef ELFObjectFile::getFileFormatName() const { return "elf64-amdgpu"; case ELF::EM_BPF: return "elf64-bpf"; + case ELF::EM_SBF: + return "elf64-sbf"; case ELF::EM_VE: return "elf64-ve"; case ELF::EM_LOONGARCH: @@ -1432,6 +1434,8 @@ template Triple::ArchType ELFObjectFile::getArch() const { case ELF::EM_BPF: return IsLittleEndian ? Triple::bpfel : Triple::bpfeb; + case ELF::EM_SBF: + return Triple::sbf; case ELF::EM_VE: return Triple::ve; diff --git a/llvm/include/llvm/TargetParser/Triple.h b/llvm/include/llvm/TargetParser/Triple.h index 7d67966d17256..f38206d79ebf8 100644 --- a/llvm/include/llvm/TargetParser/Triple.h +++ b/llvm/include/llvm/TargetParser/Triple.h @@ -104,6 +104,7 @@ class Triple { wasm64, // WebAssembly with 64-bit pointers renderscript32, // 32-bit RenderScript renderscript64, // 64-bit RenderScript + sbf, ve, // NEC SX-Aurora Vector Engine LastArchType = ve }; @@ -165,6 +166,7 @@ class Triple { SPIRVSubArch_v15, SPIRVSubArch_v16, + // DXIL sub-arch corresponds to its version. DXILSubArch_v1_0, DXILSubArch_v1_1, @@ -176,6 +178,12 @@ class Triple { DXILSubArch_v1_7, DXILSubArch_v1_8, LatestDXILSubArch = DXILSubArch_v1_8, + + SBFSubArch_v0, + SBFSubArch_v1, + SBFSubArch_v2, + SBFSubArch_v3, + SBFSubArch_v4, }; enum VendorType { UnknownVendor, @@ -194,6 +202,7 @@ class Triple { SUSE, OpenEmbedded, Intel, + Solana, LastVendorType = Intel }; enum OSType { @@ -238,6 +247,7 @@ class Triple { ShaderModel, // DirectX ShaderModel LiteOS, Serenity, + SolanaOS, Vulkan, // Vulkan SPIR-V LastOSType = Vulkan }; @@ -782,6 +792,11 @@ class Triple { return getObjectFormat() == Triple::DXContainer; } + /// Tests whether the OS is Solana. + bool isOSSolana() const { + return getOS() == Triple::SolanaOS; + } + /// Tests whether the target is the PS4 platform. bool isPS4() const { return getArch() == Triple::x86_64 && @@ -1089,6 +1104,7 @@ class Triple { } /// Tests whether the target is eBPF. + /// TODO/TBD: For new sbf backend, we should probably remove sbf check here. bool isBPF() const { return getArch() == Triple::bpfel || getArch() == Triple::bpfeb; } @@ -1109,6 +1125,11 @@ class Triple { Env == llvm::Triple::EABIHF; } + /// Tests whether the target is SBF (little endian). + bool isSBF() const { + return getArch() == Triple::sbf; + } + /// Tests whether the target supports comdat bool supportsCOMDAT() const { return !(isOSBinFormatMachO() || isOSBinFormatXCOFF() || diff --git a/llvm/include/module.modulemap b/llvm/include/module.modulemap index b378023453241..adfb9a1cfa47b 100644 --- a/llvm/include/module.modulemap +++ b/llvm/include/module.modulemap @@ -97,6 +97,7 @@ module LLVM_BinaryFormat { textual header "llvm/BinaryFormat/ELFRelocs/PowerPC.def" textual header "llvm/BinaryFormat/ELFRelocs/RISCV.def" textual header "llvm/BinaryFormat/ELFRelocs/RISCV_nonstandard.def" + textual header "llvm/BinaryFormat/ELFRelocs/SBF.def" textual header "llvm/BinaryFormat/ELFRelocs/Sparc.def" textual header "llvm/BinaryFormat/ELFRelocs/SystemZ.def" textual header "llvm/BinaryFormat/ELFRelocs/VE.def" diff --git a/llvm/lib/BinaryFormat/ELF.cpp b/llvm/lib/BinaryFormat/ELF.cpp index 9878f5769087e..f60d0be94c191 100644 --- a/llvm/lib/BinaryFormat/ELF.cpp +++ b/llvm/lib/BinaryFormat/ELF.cpp @@ -194,6 +194,7 @@ uint16_t ELF::convertArchNameToEMachine(StringRef Arch) { .Case("riscv", EM_RISCV) .Case("lanai", EM_LANAI) .Case("bpf", EM_BPF) + .Case("sbf", EM_SBF) .Case("ve", EM_VE) .Case("csky", EM_CSKY) .Case("loongarch", EM_LOONGARCH) @@ -557,6 +558,8 @@ StringRef ELF::convertEMachineToArchName(uint16_t EMachine) { return "lanai"; case EM_BPF: return "bpf"; + case EM_SBF: + return "sbf"; case EM_VE: return "ve"; case EM_CSKY: diff --git a/llvm/lib/MC/MCObjectFileInfo.cpp b/llvm/lib/MC/MCObjectFileInfo.cpp index 150e38a94db6a..e7ab3bfefb7a3 100644 --- a/llvm/lib/MC/MCObjectFileInfo.cpp +++ b/llvm/lib/MC/MCObjectFileInfo.cpp @@ -362,6 +362,7 @@ void MCObjectFileInfo::initELFMCObjectFileInfo(const Triple &T, bool Large) { break; case Triple::bpfel: case Triple::bpfeb: + case Triple::sbf: FDECFIEncoding = dwarf::DW_EH_PE_sdata8; break; case Triple::hexagon: diff --git a/llvm/lib/Object/ELF.cpp b/llvm/lib/Object/ELF.cpp index b6d0699ee4fe0..fa3c93d45c43f 100644 --- a/llvm/lib/Object/ELF.cpp +++ b/llvm/lib/Object/ELF.cpp @@ -147,6 +147,13 @@ StringRef llvm::object::getELFRelocationTypeName(uint32_t Machine, break; } break; + case ELF::EM_SBF: + switch (Type) { +#include "llvm/BinaryFormat/ELFRelocs/SBF.def" + default: + break; + } + break; case ELF::EM_MSP430: switch (Type) { #include "llvm/BinaryFormat/ELFRelocs/MSP430.def" @@ -230,6 +237,8 @@ uint32_t llvm::object::getELFRelativeRelocationType(uint32_t Machine) { return ELF::R_VE_RELATIVE; case ELF::EM_AMDGPU: break; + case ELF::EM_SBF: + break; case ELF::EM_BPF: break; case ELF::EM_LOONGARCH: diff --git a/llvm/lib/Object/RelocationResolver.cpp b/llvm/lib/Object/RelocationResolver.cpp index a28f5943c320d..dd3db18c68a91 100644 --- a/llvm/lib/Object/RelocationResolver.cpp +++ b/llvm/lib/Object/RelocationResolver.cpp @@ -105,6 +105,7 @@ static uint64_t resolveAArch64(uint64_t Type, uint64_t Offset, uint64_t S, static bool supportsBPF(uint64_t Type) { switch (Type) { + case ELF::R_BPF_64_64: case ELF::R_BPF_64_ABS32: case ELF::R_BPF_64_ABS64: return true; @@ -116,6 +117,8 @@ static bool supportsBPF(uint64_t Type) { static uint64_t resolveBPF(uint64_t Type, uint64_t Offset, uint64_t S, uint64_t LocData, int64_t /*Addend*/) { switch (Type) { + case ELF::R_BPF_64_64: + return S + LocData; case ELF::R_BPF_64_ABS32: return (S + LocData) & 0xFFFFFFFF; case ELF::R_BPF_64_ABS64: @@ -125,6 +128,31 @@ static uint64_t resolveBPF(uint64_t Type, uint64_t Offset, uint64_t S, } } +static bool supportsSBF(uint64_t Type) { + switch (Type) { + case ELF::R_SBF_64_64: + case ELF::R_SBF_64_ABS32: + case ELF::R_SBF_64_ABS64: + return true; + default: + return false; + } +} + +static uint64_t resolveSBF(uint64_t Type, uint64_t Offset, uint64_t S, + uint64_t LocData, int64_t /*Addend*/) { + switch (Type) { + case ELF::R_SBF_64_64: + return S + LocData; + case ELF::R_SBF_64_ABS32: + return (S + LocData) & 0xFFFFFFFF; + case ELF::R_SBF_64_ABS64: + return S + LocData; + default: + llvm_unreachable("Invalid relocation type"); + } +} + static bool supportsMips64(uint64_t Type) { switch (Type) { case ELF::R_MIPS_32: @@ -797,6 +825,8 @@ getRelocationResolver(const ObjectFile &Obj) { return {supportsBPF, resolveBPF}; case Triple::loongarch64: return {supportsLoongArch, resolveLoongArch}; + case Triple::sbf: + return {supportsSBF, resolveSBF}; case Triple::mips64el: case Triple::mips64: return {supportsMips64, resolveMips64}; diff --git a/llvm/lib/ObjectYAML/ELFYAML.cpp b/llvm/lib/ObjectYAML/ELFYAML.cpp index 539834fc8d4db..6007cf187f548 100644 --- a/llvm/lib/ObjectYAML/ELFYAML.cpp +++ b/llvm/lib/ObjectYAML/ELFYAML.cpp @@ -355,6 +355,7 @@ void ScalarEnumerationTraits::enumeration( ECase(EM_RISCV); ECase(EM_LANAI); ECase(EM_BPF); + ECase(EM_SBF); ECase(EM_VE); ECase(EM_CSKY); ECase(EM_LOONGARCH); @@ -940,6 +941,9 @@ void ScalarEnumerationTraits::enumeration( case ELF::EM_BPF: #include "llvm/BinaryFormat/ELFRelocs/BPF.def" break; + case ELF::EM_SBF: +#include "llvm/BinaryFormat/ELFRelocs/SBF.def" + break; case ELF::EM_VE: #include "llvm/BinaryFormat/ELFRelocs/VE.def" break; diff --git a/llvm/lib/Target/SBF/AsmParser/CMakeLists.txt b/llvm/lib/Target/SBF/AsmParser/CMakeLists.txt new file mode 100644 index 0000000000000..1a8255366fb32 --- /dev/null +++ b/llvm/lib/Target/SBF/AsmParser/CMakeLists.txt @@ -0,0 +1,13 @@ +add_llvm_component_library(LLVMSBFAsmParser + SBFAsmParser.cpp + + LINK_COMPONENTS + MC + MCParser + SBFDesc + SBFInfo + Support + + ADD_TO_COMPONENT + SBF + ) diff --git a/llvm/lib/Target/SBF/AsmParser/SBFAsmParser.cpp b/llvm/lib/Target/SBF/AsmParser/SBFAsmParser.cpp new file mode 100644 index 0000000000000..89b0fc8eed20c --- /dev/null +++ b/llvm/lib/Target/SBF/AsmParser/SBFAsmParser.cpp @@ -0,0 +1,458 @@ +//===-- SBFAsmParser.cpp - Parse SBF assembly to MCInst instructions --===// +// +// 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 "MCTargetDesc/SBFMCTargetDesc.h" +#include "MCTargetDesc/SBFInstPrinter.h" +#include "TargetInfo/SBFTargetInfo.h" +#include "llvm/ADT/StringSwitch.h" +#include "llvm/MC/MCContext.h" +#include "llvm/MC/MCExpr.h" +#include "llvm/MC/MCInst.h" +#include "llvm/MC/MCInstrInfo.h" +#include "llvm/MC/MCParser/MCAsmLexer.h" +#include "llvm/MC/MCParser/MCParsedAsmOperand.h" +#include "llvm/MC/MCParser/MCTargetAsmParser.h" +#include "llvm/MC/MCStreamer.h" +#include "llvm/MC/MCSubtargetInfo.h" +#include "llvm/MC/TargetRegistry.h" +#include "llvm/Support/Casting.h" + +using namespace llvm; + +namespace { +struct SBFOperand; + +class SBFAsmParser : public MCTargetAsmParser { + + SMLoc getLoc() const { return getParser().getTok().getLoc(); } + + bool matchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode, + OperandVector &Operands, MCStreamer &Out, + uint64_t &ErrorInfo, + bool MatchingInlineAsm) override; + + bool parseRegister(MCRegister &Reg, SMLoc &StartLoc, + SMLoc &EndLoc) override; + ParseStatus tryParseRegister(MCRegister &Reg, SMLoc &StartLoc, + SMLoc &EndLoc) override; + + bool parseInstruction(ParseInstructionInfo &Info, StringRef Name, + SMLoc NameLoc, OperandVector &Operands) override; + +#define GET_ASSEMBLER_HEADER +#include "SBFGenAsmMatcher.inc" + + bool parseOperand(OperandVector &Operands, StringRef Mnemonic); + OperandMatchResultTy parseImmediate(OperandVector &Operands); + OperandMatchResultTy parseRegister(OperandVector &Operands); + OperandMatchResultTy parseMemOperand(OperandVector &Operands); + +public: + enum SBFMatchResultTy { + Match_Dummy = FIRST_TARGET_MATCH_RESULT_TY, +#define GET_OPERAND_DIAGNOSTIC_TYPES +#include "SBFGenAsmMatcher.inc" +#undef GET_OPERAND_DIAGNOSTIC_TYPES + }; + + SBFAsmParser(const MCSubtargetInfo &STI, MCAsmParser &Parser, + const MCInstrInfo &MII, const MCTargetOptions &Options) + : MCTargetAsmParser(Options, STI, MII) { + setAvailableFeatures(ComputeAvailableFeatures(STI.getFeatureBits())); + } +}; + +/// SBFOperand - Instances of this class represent a parsed machine +/// instruction +struct SBFOperand : public MCParsedAsmOperand { + + enum KindTy { + Token, + Register, + Immediate, + } Kind; + + struct RegOp { + MCRegister RegNum; + }; + + struct ImmOp { + const MCExpr *Val; + }; + + SMLoc StartLoc, EndLoc; + union { + StringRef Tok; + RegOp Reg; + ImmOp Imm; + }; + + SBFOperand(KindTy K) : Kind(K) {} + +public: + SBFOperand(const SBFOperand &o) : MCParsedAsmOperand() { + Kind = o.Kind; + StartLoc = o.StartLoc; + EndLoc = o.EndLoc; + + switch (Kind) { + case Register: + Reg = o.Reg; + break; + case Immediate: + Imm = o.Imm; + break; + case Token: + Tok = o.Tok; + break; + } + } + + bool isToken() const override { return Kind == Token; } + bool isReg() const override { return Kind == Register; } + bool isImm() const override { return Kind == Immediate; } + bool isMem() const override { return false; } + + bool isConstantImm() const { + return isImm() && isa(getImm()); + } + + int64_t getConstantImm() const { + const MCExpr *Val = getImm(); + return static_cast(Val)->getValue(); + } + + bool isSImm12() const { + return (isConstantImm() && isInt<12>(getConstantImm())); + } + + /// getStartLoc - Gets location of the first token of this operand + SMLoc getStartLoc() const override { return StartLoc; } + /// getEndLoc - Gets location of the last token of this operand + SMLoc getEndLoc() const override { return EndLoc; } + + MCRegister getReg() const override { + assert(Kind == Register && "Invalid type access!"); + return MCRegister(Reg.RegNum); + } + + const MCExpr *getImm() const { + assert(Kind == Immediate && "Invalid type access!"); + return Imm.Val; + } + + StringRef getToken() const { + assert(Kind == Token && "Invalid type access!"); + return Tok; + } + + void print(raw_ostream &OS) const override { + auto RegName = [](unsigned Reg) { + if (Reg) + return SBFInstPrinter::getRegisterName(Reg); + else + return "noreg"; + }; + + switch (Kind) { + case Immediate: + OS << *getImm(); + break; + case Register: + OS << ""; + break; + case Token: + OS << "'" << getToken() << "'"; + break; + } + } + + void addExpr(MCInst &Inst, const MCExpr *Expr) const { + assert(Expr && "Expr shouldn't be null!"); + + if (auto *CE = dyn_cast(Expr)) + Inst.addOperand(MCOperand::createImm(CE->getValue())); + else + Inst.addOperand(MCOperand::createExpr(Expr)); + } + + // Used by the TableGen Code + void addRegOperands(MCInst &Inst, unsigned N) const { + assert(N == 1 && "Invalid number of operands!"); + Inst.addOperand(MCOperand::createReg(getReg().id())); + } + + void addImmOperands(MCInst &Inst, unsigned N) const { + assert(N == 1 && "Invalid number of operands!"); + addExpr(Inst, getImm()); + } + + static std::unique_ptr createToken(StringRef Str, SMLoc S) { + auto Op = std::make_unique(Token); + Op->Tok = Str; + Op->StartLoc = S; + Op->EndLoc = S; + return Op; + } + + static std::unique_ptr createReg(MCRegister Reg, SMLoc S, + SMLoc E) { + auto Op = std::make_unique(Register); + Op->Reg.RegNum = Reg; + Op->StartLoc = S; + Op->EndLoc = E; + return Op; + } + + static std::unique_ptr createImm(const MCExpr *Val, SMLoc S, + SMLoc E) { + auto Op = std::make_unique(Immediate); + Op->Imm.Val = Val; + Op->StartLoc = S; + Op->EndLoc = E; + return Op; + } + + // Identifiers that can be used at the start of a statment. + static bool isValidIdAtStart(StringRef Name) { + return StringSwitch(Name.lower()) + .Case("if", true) + .Case("call", true) + .Case("callx", true) + .Case("goto", true) + .Case("*", true) + .Case("exit", true) + .Case("lock", true) + .Case("ld_pseudo", true) + .Default(false); + } + + // Identifiers that can be used in the middle of a statment. + static bool isValidIdInMiddle(StringRef Name) { + return StringSwitch(Name.lower()) + .Case("u64", true) + .Case("u32", true) + .Case("u16", true) + .Case("u8", true) + .Case("be64", true) + .Case("be32", true) + .Case("be16", true) + .Case("le64", true) + .Case("le32", true) + .Case("le16", true) + .Case("goto", true) + .Case("ll", true) + .Case("skb", true) + .Case("s", true) + .Default(false); + } +}; +} // end anonymous namespace. + +#define GET_REGISTER_MATCHER +#define GET_MATCHER_IMPLEMENTATION +#include "SBFGenAsmMatcher.inc" + +bool SBFAsmParser::matchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode, + OperandVector &Operands, + MCStreamer &Out, uint64_t &ErrorInfo, + bool MatchingInlineAsm) { + MCInst Inst; + SMLoc ErrorLoc; + + switch (MatchInstructionImpl(Operands, Inst, ErrorInfo, MatchingInlineAsm)) { + default: + break; + case Match_Success: + Inst.setLoc(IDLoc); + Out.emitInstruction(Inst, getSTI()); + return false; + case Match_MissingFeature: + return Error(IDLoc, "instruction use requires an option to be enabled"); + case Match_MnemonicFail: + return Error(IDLoc, "unrecognized instruction mnemonic"); + case Match_InvalidOperand: + ErrorLoc = IDLoc; + + if (ErrorInfo != ~0U) { + if (ErrorInfo >= Operands.size()) + return Error(ErrorLoc, "too few operands for instruction"); + + ErrorLoc = ((SBFOperand &)*Operands[ErrorInfo]).getStartLoc(); + + if (ErrorLoc == SMLoc()) + ErrorLoc = IDLoc; + } + + return Error(ErrorLoc, "invalid operand for instruction"); + } + + llvm_unreachable("Unknown match type detected!"); +} + +bool SBFAsmParser::parseRegister(MCRegister &Reg, SMLoc &StartLoc, + SMLoc &EndLoc) { + if (!tryParseRegister(Reg, StartLoc, EndLoc).isSuccess()) + return Error(StartLoc, "invalid register name"); + return false; +} + +ParseStatus SBFAsmParser::tryParseRegister(MCRegister &Reg, + SMLoc &StartLoc, + SMLoc &EndLoc) { + const AsmToken &Tok = getParser().getTok(); + StartLoc = Tok.getLoc(); + EndLoc = Tok.getEndLoc(); + Reg = 0; + StringRef Name = getLexer().getTok().getIdentifier(); + + if (!MatchRegisterName(Name)) { + getParser().Lex(); // Eat identifier token. + return ParseStatus::Success; + } + + return ParseStatus::NoMatch; +} + +OperandMatchResultTy SBFAsmParser::parseRegister(OperandVector &Operands) { + SMLoc S = getLoc(); + SMLoc E = SMLoc::getFromPointer(S.getPointer() - 1); + + switch (getLexer().getKind()) { + default: + return MatchOperand_NoMatch; + case AsmToken::Identifier: + StringRef Name = getLexer().getTok().getIdentifier(); + MCRegister Reg = MatchRegisterName(Name); + + if (!Reg) + return MatchOperand_NoMatch; + + getLexer().Lex(); + Operands.push_back(SBFOperand::createReg(Reg, S, E)); + } + return MatchOperand_Success; +} + +OperandMatchResultTy SBFAsmParser::parseImmediate(OperandVector &Operands) { + switch (getLexer().getKind()) { + default: + return MatchOperand_NoMatch; + case AsmToken::LParen: + case AsmToken::Minus: + case AsmToken::Plus: + case AsmToken::Integer: + case AsmToken::String: + case AsmToken::Identifier: + break; + } + + const MCExpr *IdVal; + SMLoc S = getLoc(); + + if (getParser().parseExpression(IdVal)) + return MatchOperand_ParseFail; + + SMLoc E = SMLoc::getFromPointer(S.getPointer() - 1); + Operands.push_back(SBFOperand::createImm(IdVal, S, E)); + + return MatchOperand_Success; +} + +OperandMatchResultTy SBFAsmParser::parseMemOperand(OperandVector &Operands) { + if (getLexer().isNot(AsmToken::LBrac)) { + return MatchOperand_ParseFail; + } + + getParser().Lex(); // Eat '['. + Operands.push_back(SBFOperand::createToken("[", getLoc())); + + if (parseRegister(Operands) != MatchOperand_Success) { + Error(getLoc(), "expected register"); + return MatchOperand_ParseFail; + } + + if (parseImmediate(Operands) != MatchOperand_Success) { + Error(getLoc(), "expected immediate offset"); + return MatchOperand_ParseFail; + } + + if (getLexer().isNot(AsmToken::RBrac)) { + Error(getLoc(), "expected ']'"); + return MatchOperand_ParseFail; + } + + getParser().Lex(); // Eat ']'. + Operands.push_back(SBFOperand::createToken("]", getLoc())); + + return MatchOperand_Success; +} + +/// Looks at a token type and creates the relevant operand from this +/// information, adding to Operands. If operand was parsed, returns false, else +/// true. +bool SBFAsmParser::parseOperand(OperandVector &Operands, StringRef Mnemonic) { + // Attempt to parse token as a register. + if (parseRegister(Operands) == MatchOperand_Success) + return false; + + // Attempt to parse token as an immediate. + if (parseImmediate(Operands) == MatchOperand_Success) { + return false; + } + + // Attempt to parse token sequence as a memory operand ("[reg+/-offset]"). + if (parseMemOperand(Operands) == MatchOperand_Success) { + return false; + } + + // Finally we have exhausted all options and must declare defeat. + Error(getLoc(), "unknown operand"); + return true; +} + +/// Parse an SBF instruction. +bool SBFAsmParser::parseInstruction(ParseInstructionInfo &Info, StringRef Name, + SMLoc NameLoc, OperandVector &Operands) { + // First operand is token for instruction mnemonic. + Operands.push_back(SBFOperand::createToken(Name, NameLoc)); + + // If there are no more operands, then finish. + if (getLexer().is(AsmToken::EndOfStatement)) { + getParser().Lex(); // Consume the EndOfStatement. + return false; + } + + // Parse first operand. + if (parseOperand(Operands, Name)) + return true; + + // Parse until end of statement, consuming commas between operands. + while (getLexer().is(AsmToken::Comma)) { + // Consume comma token. + getLexer().Lex(); + + // Parse next operand. + if (parseOperand(Operands, Name)) + return true; + } + + if (getLexer().isNot(AsmToken::EndOfStatement)) { + SMLoc Loc = getLexer().getLoc(); + getParser().eatToEndOfStatement(); + return Error(Loc, "unexpected token"); + } + + getParser().Lex(); // Consume the EndOfStatement. + return false; +} + +extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeSBFAsmParser() { + RegisterMCAsmParser XX(getTheSBFXTarget()); +} diff --git a/llvm/lib/Target/SBF/BTF.def b/llvm/lib/Target/SBF/BTF.def new file mode 100644 index 0000000000000..1de0e51b47570 --- /dev/null +++ b/llvm/lib/Target/SBF/BTF.def @@ -0,0 +1,38 @@ +//===- BTF.def - BTF definitions --------------------------------*- 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 +// +//===----------------------------------------------------------------------===// +// +// Macros for BTF. +// +//===----------------------------------------------------------------------===// + +#if !defined(HANDLE_BTF_KIND) +#error "Missing macro definition of HANDLE_BTF_*" +#endif + +HANDLE_BTF_KIND(0, UNKN) +HANDLE_BTF_KIND(1, INT) +HANDLE_BTF_KIND(2, PTR) +HANDLE_BTF_KIND(3, ARRAY) +HANDLE_BTF_KIND(4, STRUCT) +HANDLE_BTF_KIND(5, UNION) +HANDLE_BTF_KIND(6, ENUM) +HANDLE_BTF_KIND(7, FWD) +HANDLE_BTF_KIND(8, TYPEDEF) +HANDLE_BTF_KIND(9, VOLATILE) +HANDLE_BTF_KIND(10, CONST) +HANDLE_BTF_KIND(11, RESTRICT) +HANDLE_BTF_KIND(12, FUNC) +HANDLE_BTF_KIND(13, FUNC_PROTO) +HANDLE_BTF_KIND(14, VAR) +HANDLE_BTF_KIND(15, DATASEC) +HANDLE_BTF_KIND(16, FLOAT) +HANDLE_BTF_KIND(17, DECL_TAG) +HANDLE_BTF_KIND(18, TYPE_TAG) +HANDLE_BTF_KIND(19, ENUM64) + +#undef HANDLE_BTF_KIND diff --git a/llvm/lib/Target/SBF/BTF.h b/llvm/lib/Target/SBF/BTF.h new file mode 100644 index 0000000000000..52e6182ec32f8 --- /dev/null +++ b/llvm/lib/Target/SBF/BTF.h @@ -0,0 +1,273 @@ +//===-- BTF.h --------------------------------------------------*- 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 +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// This file contains the layout of .BTF and .BTF.ext ELF sections. +/// +/// The binary layout for .BTF section: +/// struct Header +/// Type and Str subsections +/// The Type subsection is a collection of types with type id starting with 1. +/// The Str subsection is simply a collection of strings. +/// +/// The binary layout for .BTF.ext section: +/// struct ExtHeader +/// FuncInfo, LineInfo, FieldReloc and ExternReloc subsections +/// The FuncInfo subsection is defined as below: +/// BTFFuncInfo Size +/// struct SecFuncInfo for ELF section #1 +/// A number of struct SBFFuncInfo for ELF section #1 +/// struct SecFuncInfo for ELF section #2 +/// A number of struct SBFFuncInfo for ELF section #2 +/// ... +/// The LineInfo subsection is defined as below: +/// SBFLineInfo Size +/// struct SecLineInfo for ELF section #1 +/// A number of struct SBFLineInfo for ELF section #1 +/// struct SecLineInfo for ELF section #2 +/// A number of struct SBFLineInfo for ELF section #2 +/// ... +/// The FieldReloc subsection is defined as below: +/// SBFFieldReloc Size +/// struct SecFieldReloc for ELF section #1 +/// A number of struct SBFFieldReloc for ELF section #1 +/// struct SecFieldReloc for ELF section #2 +/// A number of struct SBFFieldReloc for ELF section #2 +/// ... +/// +/// The section formats are also defined at +/// https://github.com/torvalds/linux/blob/master/include/uapi/linux/btf.h +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIB_TARGET_SBF_BTF_H +#define LLVM_LIB_TARGET_SBF_BTF_H + +#include + +namespace llvm { +namespace BTF { + +enum : uint32_t { MAGIC = 0xeB9F, VERSION = 1 }; + +/// Sizes in bytes of various things in the BTF format. +enum { + HeaderSize = 24, + ExtHeaderSize = 32, + CommonTypeSize = 12, + BTFArraySize = 12, + BTFEnumSize = 8, + BTFEnum64Size = 12, + BTFMemberSize = 12, + BTFParamSize = 8, + BTFDataSecVarSize = 12, + SecFuncInfoSize = 8, + SecLineInfoSize = 8, + SecFieldRelocSize = 8, + SBFFuncInfoSize = 8, + SBFLineInfoSize = 16, + SBFFieldRelocSize = 16, +}; + +/// The .BTF section header definition. +struct Header { + uint16_t Magic; ///< Magic value + uint8_t Version; ///< Version number + uint8_t Flags; ///< Extra flags + uint32_t HdrLen; ///< Length of this header + + /// All offsets are in bytes relative to the end of this header. + uint32_t TypeOff; ///< Offset of type section + uint32_t TypeLen; ///< Length of type section + uint32_t StrOff; ///< Offset of string section + uint32_t StrLen; ///< Length of string section +}; + +enum : uint32_t { + MAX_VLEN = 0xffff ///< Max # of struct/union/enum members or func args +}; + +enum TypeKinds : uint8_t { +#define HANDLE_BTF_KIND(ID, NAME) BTF_KIND_##NAME = ID, +#include "BTF.def" +}; + +/// The BTF common type definition. Different kinds may have +/// additional information after this structure data. +struct CommonType { + /// Type name offset in the string table. + uint32_t NameOff; + + /// "Info" bits arrangement: + /// Bits 0-15: vlen (e.g. # of struct's members) + /// Bits 16-23: unused + /// Bits 24-27: kind (e.g. int, ptr, array...etc) + /// Bits 28-30: unused + /// Bit 31: kind_flag, currently used by + /// struct, union and fwd + uint32_t Info; + + /// "Size" is used by INT, ENUM, STRUCT and UNION. + /// "Size" tells the size of the type it is describing. + /// + /// "Type" is used by PTR, TYPEDEF, VOLATILE, CONST, RESTRICT, + /// FUNC, FUNC_PROTO, VAR, DECL_TAG and TYPE_TAG. + /// "Type" is a type_id referring to another type. + union { + uint32_t Size; + uint32_t Type; + }; +}; + +// For some specific BTF_KIND, "struct CommonType" is immediately +// followed by extra data. + +// BTF_KIND_INT is followed by a u32 and the following +// is the 32 bits arrangement: +// BTF_INT_ENCODING(VAL) : (((VAL) & 0x0f000000) >> 24) +// BTF_INT_OFFSET(VAL) : (((VAL & 0x00ff0000)) >> 16) +// BTF_INT_BITS(VAL) : ((VAL) & 0x000000ff) + +/// Attributes stored in the INT_ENCODING. +enum : uint8_t { + INT_SIGNED = (1 << 0), + INT_CHAR = (1 << 1), + INT_BOOL = (1 << 2) +}; + +/// BTF_KIND_ENUM is followed by multiple "struct BTFEnum". +/// The exact number of btf_enum is stored in the vlen (of the +/// info in "struct CommonType"). +struct BTFEnum { + uint32_t NameOff; ///< Enum name offset in the string table + int32_t Val; ///< Enum member value +}; + +/// BTF_KIND_ENUM64 is followed by multiple "struct BTFEnum64". +/// The exact number of BTFEnum64 is stored in the vlen (of the +/// info in "struct CommonType"). +struct BTFEnum64 { + uint32_t NameOff; ///< Enum name offset in the string table + uint32_t Val_Lo32; ///< Enum member lo32 value + uint32_t Val_Hi32; ///< Enum member hi32 value +}; + +/// BTF_KIND_ARRAY is followed by one "struct BTFArray". +struct BTFArray { + uint32_t ElemType; ///< Element type + uint32_t IndexType; ///< Index type + uint32_t Nelems; ///< Number of elements for this array +}; + +/// BTF_KIND_STRUCT and BTF_KIND_UNION are followed +/// by multiple "struct BTFMember". The exact number +/// of BTFMember is stored in the vlen (of the info in +/// "struct CommonType"). +/// +/// If the struct/union contains any bitfield member, +/// the Offset below represents BitOffset (bits 0 - 23) +/// and BitFieldSize(bits 24 - 31) with BitFieldSize = 0 +/// for non bitfield members. Otherwise, the Offset +/// represents the BitOffset. +struct BTFMember { + uint32_t NameOff; ///< Member name offset in the string table + uint32_t Type; ///< Member type + uint32_t Offset; ///< BitOffset or BitFieldSize+BitOffset +}; + +/// BTF_KIND_FUNC_PROTO are followed by multiple "struct BTFParam". +/// The exist number of BTFParam is stored in the vlen (of the info +/// in "struct CommonType"). +struct BTFParam { + uint32_t NameOff; + uint32_t Type; +}; + +/// BTF_KIND_FUNC can be global, static or extern. +enum : uint8_t { + FUNC_STATIC = 0, + FUNC_GLOBAL = 1, + FUNC_EXTERN = 2, +}; + +/// Variable scoping information. +enum : uint8_t { + VAR_STATIC = 0, ///< Linkage: InternalLinkage + VAR_GLOBAL_ALLOCATED = 1, ///< Linkage: ExternalLinkage + VAR_GLOBAL_EXTERNAL = 2, ///< Linkage: ExternalLinkage +}; + +/// BTF_KIND_DATASEC are followed by multiple "struct BTFDataSecVar". +/// The exist number of BTFDataSec is stored in the vlen (of the info +/// in "struct CommonType"). +struct BTFDataSec { + uint32_t Type; ///< A BTF_KIND_VAR type + uint32_t Offset; ///< In-section offset + uint32_t Size; ///< Occupied memory size +}; + +/// The .BTF.ext section header definition. +struct ExtHeader { + uint16_t Magic; + uint8_t Version; + uint8_t Flags; + uint32_t HdrLen; + + uint32_t FuncInfoOff; ///< Offset of func info section + uint32_t FuncInfoLen; ///< Length of func info section + uint32_t LineInfoOff; ///< Offset of line info section + uint32_t LineInfoLen; ///< Length of line info section + uint32_t FieldRelocOff; ///< Offset of offset reloc section + uint32_t FieldRelocLen; ///< Length of offset reloc section +}; + +/// Specifying one function info. +struct SBFFuncInfo { + uint32_t InsnOffset; ///< Byte offset in the section + uint32_t TypeId; ///< Type id referring to .BTF type section +}; + +/// Specifying function info's in one section. +struct SecFuncInfo { + uint32_t SecNameOff; ///< Section name index in the .BTF string table + uint32_t NumFuncInfo; ///< Number of func info's in this section +}; + +/// Specifying one line info. +struct SBFLineInfo { + uint32_t InsnOffset; ///< Byte offset in this section + uint32_t FileNameOff; ///< File name index in the .BTF string table + uint32_t LineOff; ///< Line index in the .BTF string table + uint32_t LineCol; ///< Line num: line_col >> 10, + /// col num: line_col & 0x3ff +}; + +/// Specifying line info's in one section. +struct SecLineInfo { + uint32_t SecNameOff; ///< Section name index in the .BTF string table + uint32_t NumLineInfo; ///< Number of line info's in this section +}; + +/// Specifying one offset relocation. +struct SBFFieldReloc { + uint32_t InsnOffset; ///< Byte offset in this section + uint32_t TypeID; ///< TypeID for the relocation + uint32_t OffsetNameOff; ///< The string to traverse types + uint32_t RelocKind; ///< What to patch the instruction +}; + +/// Specifying offset relocation's in one section. +struct SecFieldReloc { + uint32_t SecNameOff; ///< Section name index in the .BTF string table + uint32_t NumFieldReloc; ///< Number of offset reloc's in this section +}; + +} // End namespace BTF. +} // End namespace llvm. + +#endif diff --git a/llvm/lib/Target/SBF/BTFDebug.cpp b/llvm/lib/Target/SBF/BTFDebug.cpp new file mode 100644 index 0000000000000..3c09fb34e444a --- /dev/null +++ b/llvm/lib/Target/SBF/BTFDebug.cpp @@ -0,0 +1,1646 @@ +//===- BTFDebug.cpp - BTF Generator ---------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// +// +// This file contains support for writing BTF debug info. +// +//===----------------------------------------------------------------------===// + +#include "BTFDebug.h" +#include "SBF.h" +#include "SBFCORE.h" +#include "MCTargetDesc/SBFMCTargetDesc.h" +#include "llvm/BinaryFormat/ELF.h" +#include "llvm/CodeGen/AsmPrinter.h" +#include "llvm/CodeGen/MachineModuleInfo.h" +#include "llvm/IR/Module.h" +#include "llvm/MC/MCContext.h" +#include "llvm/MC/MCObjectFileInfo.h" +#include "llvm/MC/MCSectionELF.h" +#include "llvm/MC/MCStreamer.h" +#include "llvm/Support/LineIterator.h" +#include "llvm/Support/MemoryBuffer.h" +#include "llvm/Target/TargetLoweringObjectFile.h" +#include +#include "SBFSubtarget.h" + +using namespace llvm; +using namespace BTFX; + +static const char *BTFKindStr[] = { +#define HANDLE_BTF_KIND(ID, NAME) "BTF_KIND_" #NAME, +#include "BTF.def" +}; + +/// Emit a BTF common type. +void BTFTypeBase::emitType(MCStreamer &OS) { + OS.AddComment(std::string(BTFKindStr[Kind]) + "(id = " + std::to_string(Id) + + ")"); + OS.emitInt32(BTFType.NameOff); + OS.AddComment("0x" + Twine::utohexstr(BTFType.Info)); + OS.emitInt32(BTFType.Info); + OS.emitInt32(BTFType.Size); +} + +BTFTypeDerived::BTFTypeDerived(const DIDerivedType *DTy, unsigned Tag, + bool NeedsFixup) + : DTy(DTy), NeedsFixup(NeedsFixup), Name(DTy->getName()) { + switch (Tag) { + case dwarf::DW_TAG_pointer_type: + Kind = BTF::BTF_KIND_PTR; + break; + case dwarf::DW_TAG_const_type: + Kind = BTF::BTF_KIND_CONST; + break; + case dwarf::DW_TAG_volatile_type: + Kind = BTF::BTF_KIND_VOLATILE; + break; + case dwarf::DW_TAG_typedef: + Kind = BTF::BTF_KIND_TYPEDEF; + break; + case dwarf::DW_TAG_restrict_type: + Kind = BTF::BTF_KIND_RESTRICT; + break; + default: + llvm_unreachable("Unknown DIDerivedType Tag"); + } + BTFType.Info = Kind << 24; +} + +/// Used by DW_TAG_pointer_type only. +BTFTypeDerived::BTFTypeDerived(unsigned NextTypeId, unsigned Tag, + StringRef Name) + : DTy(nullptr), NeedsFixup(false), Name(Name) { + Kind = BTF::BTF_KIND_PTR; + BTFType.Info = Kind << 24; + BTFType.Type = NextTypeId; +} + +void BTFTypeDerived::completeType(BTFDebug &BDebug) { + if (IsCompleted) + return; + IsCompleted = true; + + BTFType.NameOff = BDebug.addString(Name); + + if (NeedsFixup || !DTy) + return; + + // The base type for PTR/CONST/VOLATILE could be void. + const DIType *ResolvedType = DTy->getBaseType(); + if (!ResolvedType) { + assert((Kind == BTF::BTF_KIND_PTR || Kind == BTF::BTF_KIND_CONST || + Kind == BTF::BTF_KIND_VOLATILE) && + "Invalid null basetype"); + BTFType.Type = 0; + } else { + BTFType.Type = BDebug.getTypeId(ResolvedType); + } +} + +void BTFTypeDerived::emitType(MCStreamer &OS) { BTFTypeBase::emitType(OS); } + +void BTFTypeDerived::setPointeeType(uint32_t PointeeType) { + BTFType.Type = PointeeType; +} + +/// Represent a struct/union forward declaration. +BTFTypeFwd::BTFTypeFwd(StringRef Name, bool IsUnion) : Name(Name) { + Kind = BTF::BTF_KIND_FWD; + BTFType.Info = IsUnion << 31 | Kind << 24; + BTFType.Type = 0; +} + +void BTFTypeFwd::completeType(BTFDebug &BDebug) { + if (IsCompleted) + return; + IsCompleted = true; + + BTFType.NameOff = BDebug.addString(Name); +} + +void BTFTypeFwd::emitType(MCStreamer &OS) { BTFTypeBase::emitType(OS); } + +BTFTypeInt::BTFTypeInt(uint32_t Encoding, uint32_t SizeInBits, + uint32_t OffsetInBits, StringRef TypeName) + : Name(TypeName) { + // Translate IR int encoding to BTF int encoding. + uint8_t BTFEncoding; + switch (Encoding) { + case dwarf::DW_ATE_boolean: + BTFEncoding = BTF::INT_BOOL; + break; + case dwarf::DW_ATE_signed: + case dwarf::DW_ATE_signed_char: + BTFEncoding = BTF::INT_SIGNED; + break; + case dwarf::DW_ATE_unsigned: + case dwarf::DW_ATE_unsigned_char: + BTFEncoding = 0; + break; + default: + llvm_unreachable("Unknown BTFTypeInt Encoding"); + } + + Kind = BTF::BTF_KIND_INT; + BTFType.Info = Kind << 24; + BTFType.Size = roundupToBytes(SizeInBits); + IntVal = (BTFEncoding << 24) | OffsetInBits << 16 | SizeInBits; +} + +void BTFTypeInt::completeType(BTFDebug &BDebug) { + if (IsCompleted) + return; + IsCompleted = true; + + BTFType.NameOff = BDebug.addString(Name); +} + +void BTFTypeInt::emitType(MCStreamer &OS) { + BTFTypeBase::emitType(OS); + OS.AddComment("0x" + Twine::utohexstr(IntVal)); + OS.emitInt32(IntVal); +} + +BTFTypeEnum::BTFTypeEnum(const DICompositeType *ETy, uint32_t VLen, + bool IsSigned) : ETy(ETy) { + Kind = BTF::BTF_KIND_ENUM; + BTFType.Info = IsSigned << 31 | Kind << 24 | VLen; + BTFType.Size = roundupToBytes(ETy->getSizeInBits()); +} + +void BTFTypeEnum::completeType(BTFDebug &BDebug) { + if (IsCompleted) + return; + IsCompleted = true; + + BTFType.NameOff = BDebug.addString(ETy->getName()); + + DINodeArray Elements = ETy->getElements(); + for (const auto Element : Elements) { + const auto *Enum = cast(Element); + + struct BTF::BTFEnum BTFEnum; + BTFEnum.NameOff = BDebug.addString(Enum->getName()); + // BTF enum value is 32bit, enforce it. + uint32_t Value; + if (Enum->isUnsigned()) + Value = static_cast(Enum->getValue().getZExtValue()); + else + Value = static_cast(Enum->getValue().getSExtValue()); + BTFEnum.Val = Value; + EnumValues.push_back(BTFEnum); + } +} + +void BTFTypeEnum::emitType(MCStreamer &OS) { + BTFTypeBase::emitType(OS); + for (const auto &Enum : EnumValues) { + OS.emitInt32(Enum.NameOff); + OS.emitInt32(Enum.Val); + } +} + +BTFTypeEnum64::BTFTypeEnum64(const DICompositeType *ETy, uint32_t VLen, + bool IsSigned) : ETy(ETy) { + Kind = BTF::BTF_KIND_ENUM64; + BTFType.Info = IsSigned << 31 | Kind << 24 | VLen; + BTFType.Size = roundupToBytes(ETy->getSizeInBits()); +} + +void BTFTypeEnum64::completeType(BTFDebug &BDebug) { + if (IsCompleted) + return; + IsCompleted = true; + + BTFType.NameOff = BDebug.addString(ETy->getName()); + + DINodeArray Elements = ETy->getElements(); + for (const auto Element : Elements) { + const auto *Enum = cast(Element); + + struct BTF::BTFEnum64 BTFEnum; + BTFEnum.NameOff = BDebug.addString(Enum->getName()); + uint64_t Value; + if (Enum->isUnsigned()) + Value = static_cast(Enum->getValue().getZExtValue()); + else + Value = static_cast(Enum->getValue().getSExtValue()); + BTFEnum.Val_Lo32 = Value; + BTFEnum.Val_Hi32 = Value >> 32; + EnumValues.push_back(BTFEnum); + } +} + +void BTFTypeEnum64::emitType(MCStreamer &OS) { + BTFTypeBase::emitType(OS); + for (const auto &Enum : EnumValues) { + OS.emitInt32(Enum.NameOff); + OS.AddComment("0x" + Twine::utohexstr(Enum.Val_Lo32)); + OS.emitInt32(Enum.Val_Lo32); + OS.AddComment("0x" + Twine::utohexstr(Enum.Val_Hi32)); + OS.emitInt32(Enum.Val_Hi32); + } +} + +BTFTypeArray::BTFTypeArray(uint32_t ElemTypeId, uint32_t NumElems) { + Kind = BTF::BTF_KIND_ARRAY; + BTFType.NameOff = 0; + BTFType.Info = Kind << 24; + BTFType.Size = 0; + + ArrayInfo.ElemType = ElemTypeId; + ArrayInfo.Nelems = NumElems; +} + +/// Represent a BTF array. +void BTFTypeArray::completeType(BTFDebug &BDebug) { + if (IsCompleted) + return; + IsCompleted = true; + + // The IR does not really have a type for the index. + // A special type for array index should have been + // created during initial type traversal. Just + // retrieve that type id. + ArrayInfo.IndexType = BDebug.getArrayIndexTypeId(); +} + +void BTFTypeArray::emitType(MCStreamer &OS) { + BTFTypeBase::emitType(OS); + OS.emitInt32(ArrayInfo.ElemType); + OS.emitInt32(ArrayInfo.IndexType); + OS.emitInt32(ArrayInfo.Nelems); +} + +/// Represent either a struct or a union. +BTFTypeStruct::BTFTypeStruct(const DICompositeType *STy, bool IsStruct, + bool HasBitField, uint32_t Vlen) + : STy(STy), HasBitField(HasBitField) { + Kind = IsStruct ? BTF::BTF_KIND_STRUCT : BTF::BTF_KIND_UNION; + BTFType.Size = roundupToBytes(STy->getSizeInBits()); + BTFType.Info = (HasBitField << 31) | (Kind << 24) | Vlen; +} + +void BTFTypeStruct::completeType(BTFDebug &BDebug) { + if (IsCompleted) + return; + IsCompleted = true; + + BTFType.NameOff = BDebug.addString(STy->getName()); + + // Add struct/union members. + const DINodeArray Elements = STy->getElements(); + for (const auto *Element : Elements) { + struct BTF::BTFMember BTFMember; + const auto *DDTy = cast(Element); + + BTFMember.NameOff = BDebug.addString(DDTy->getName()); + if (HasBitField) { + uint8_t BitFieldSize = DDTy->isBitField() ? DDTy->getSizeInBits() : 0; + BTFMember.Offset = BitFieldSize << 24 | DDTy->getOffsetInBits(); + } else { + BTFMember.Offset = DDTy->getOffsetInBits(); + } + const auto *BaseTy = DDTy->getBaseType(); + BTFMember.Type = BDebug.getTypeId(BaseTy); + Members.push_back(BTFMember); + } +} + +void BTFTypeStruct::emitType(MCStreamer &OS) { + BTFTypeBase::emitType(OS); + for (const auto &Member : Members) { + OS.emitInt32(Member.NameOff); + OS.emitInt32(Member.Type); + OS.AddComment("0x" + Twine::utohexstr(Member.Offset)); + OS.emitInt32(Member.Offset); + } +} + +std::string BTFTypeStruct::getName() { return std::string(STy->getName()); } + +/// The Func kind represents both subprogram and pointee of function +/// pointers. If the FuncName is empty, it represents a pointee of function +/// pointer. Otherwise, it represents a subprogram. The func arg names +/// are empty for pointee of function pointer case, and are valid names +/// for subprogram. +BTFTypeFuncProto::BTFTypeFuncProto( + const DISubroutineType *STy, uint32_t VLen, + const std::unordered_map &FuncArgNames) + : STy(STy), FuncArgNames(FuncArgNames) { + Kind = BTF::BTF_KIND_FUNC_PROTO; + BTFType.Info = (Kind << 24) | VLen; +} + +void BTFTypeFuncProto::completeType(BTFDebug &BDebug) { + if (IsCompleted) + return; + IsCompleted = true; + + DITypeRefArray Elements = STy->getTypeArray(); + auto RetType = Elements[0]; + BTFType.Type = RetType ? BDebug.getTypeId(RetType) : 0; + BTFType.NameOff = 0; + + // For null parameter which is typically the last one + // to represent the vararg, encode the NameOff/Type to be 0. + for (unsigned I = 1, N = Elements.size(); I < N; ++I) { + struct BTF::BTFParam Param; + auto Element = Elements[I]; + if (Element) { + Param.NameOff = BDebug.addString(FuncArgNames[I]); + Param.Type = BDebug.getTypeId(Element); + } else { + Param.NameOff = 0; + Param.Type = 0; + } + Parameters.push_back(Param); + } +} + +void BTFTypeFuncProto::emitType(MCStreamer &OS) { + BTFTypeBase::emitType(OS); + for (const auto &Param : Parameters) { + OS.emitInt32(Param.NameOff); + OS.emitInt32(Param.Type); + } +} + +BTFTypeFunc::BTFTypeFunc(StringRef FuncName, uint32_t ProtoTypeId, + uint32_t Scope) + : Name(FuncName) { + Kind = BTF::BTF_KIND_FUNC; + BTFType.Info = (Kind << 24) | Scope; + BTFType.Type = ProtoTypeId; +} + +void BTFTypeFunc::completeType(BTFDebug &BDebug) { + if (IsCompleted) + return; + IsCompleted = true; + + BTFType.NameOff = BDebug.addString(Name); +} + +void BTFTypeFunc::emitType(MCStreamer &OS) { BTFTypeBase::emitType(OS); } + +BTFKindVar::BTFKindVar(StringRef VarName, uint32_t TypeId, uint32_t VarInfo) + : Name(VarName) { + Kind = BTF::BTF_KIND_VAR; + BTFType.Info = Kind << 24; + BTFType.Type = TypeId; + Info = VarInfo; +} + +void BTFKindVar::completeType(BTFDebug &BDebug) { + BTFType.NameOff = BDebug.addString(Name); +} + +void BTFKindVar::emitType(MCStreamer &OS) { + BTFTypeBase::emitType(OS); + OS.emitInt32(Info); +} + +BTFKindDataSec::BTFKindDataSec(AsmPrinter *AsmPrt, std::string SecName) + : Asm(AsmPrt), Name(SecName) { + Kind = BTF::BTF_KIND_DATASEC; + BTFType.Info = Kind << 24; + BTFType.Size = 0; +} + +void BTFKindDataSec::completeType(BTFDebug &BDebug) { + BTFType.NameOff = BDebug.addString(Name); + BTFType.Info |= Vars.size(); +} + +void BTFKindDataSec::emitType(MCStreamer &OS) { + BTFTypeBase::emitType(OS); + + for (const auto &V : Vars) { + OS.emitInt32(std::get<0>(V)); + Asm->emitLabelReference(std::get<1>(V), 4); + OS.emitInt32(std::get<2>(V)); + } +} + +BTFTypeFloat::BTFTypeFloat(uint32_t SizeInBits, StringRef TypeName) + : Name(TypeName) { + Kind = BTF::BTF_KIND_FLOAT; + BTFType.Info = Kind << 24; + BTFType.Size = roundupToBytes(SizeInBits); +} + +void BTFTypeFloat::completeType(BTFDebug &BDebug) { + if (IsCompleted) + return; + IsCompleted = true; + + BTFType.NameOff = BDebug.addString(Name); +} + +BTFTypeDeclTag::BTFTypeDeclTag(uint32_t BaseTypeId, int ComponentIdx, + StringRef Tag) + : Tag(Tag) { + Kind = BTF::BTF_KIND_DECL_TAG; + BTFType.Info = Kind << 24; + BTFType.Type = BaseTypeId; + Info = ComponentIdx; +} + +void BTFTypeDeclTag::completeType(BTFDebug &BDebug) { + if (IsCompleted) + return; + IsCompleted = true; + + BTFType.NameOff = BDebug.addString(Tag); +} + +void BTFTypeDeclTag::emitType(MCStreamer &OS) { + BTFTypeBase::emitType(OS); + OS.emitInt32(Info); +} + +BTFTypeTypeTag::BTFTypeTypeTag(uint32_t NextTypeId, StringRef Tag) + : DTy(nullptr), Tag(Tag) { + Kind = BTF::BTF_KIND_TYPE_TAG; + BTFType.Info = Kind << 24; + BTFType.Type = NextTypeId; +} + +BTFTypeTypeTag::BTFTypeTypeTag(const DIDerivedType *DTy, StringRef Tag) + : DTy(DTy), Tag(Tag) { + Kind = BTF::BTF_KIND_TYPE_TAG; + BTFType.Info = Kind << 24; +} + +void BTFTypeTypeTag::completeType(BTFDebug &BDebug) { + if (IsCompleted) + return; + IsCompleted = true; + BTFType.NameOff = BDebug.addString(Tag); + if (DTy) { + const DIType *ResolvedType = DTy->getBaseType(); + if (!ResolvedType) + BTFType.Type = 0; + else + BTFType.Type = BDebug.getTypeId(ResolvedType); + } +} + +uint32_t BTFStringTable::addString(StringRef S) { + // Check whether the string already exists. + for (auto &OffsetM : OffsetToIdMap) { + if (Table[OffsetM.second] == S) + return OffsetM.first; + } + // Not find, add to the string table. + uint32_t Offset = Size; + OffsetToIdMap[Offset] = Table.size(); + Table.push_back(std::string(S)); + Size += S.size() + 1; + return Offset; +} + +BTFDebug::BTFDebug(AsmPrinter *AP) + : DebugHandlerBase(AP), OS(*Asm->OutStreamer), SkipInstruction(false), + LineInfoGenerated(false), SecNameOff(0), ArrayIndexTypeId(0), + MapDefNotCollected(true) { + addString("\0"); +} + +uint32_t BTFDebug::addType(std::unique_ptr TypeEntry, + const DIType *Ty) { + TypeEntry->setId(TypeEntries.size() + 1); + uint32_t Id = TypeEntry->getId(); + DIToIdMap[Ty] = Id; + TypeEntries.push_back(std::move(TypeEntry)); + return Id; +} + +uint32_t BTFDebug::addType(std::unique_ptr TypeEntry) { + TypeEntry->setId(TypeEntries.size() + 1); + uint32_t Id = TypeEntry->getId(); + TypeEntries.push_back(std::move(TypeEntry)); + return Id; +} + +void BTFDebug::visitBasicType(const DIBasicType *BTy, uint32_t &TypeId) { + // Only int and binary floating point types are supported in BTF. + uint32_t Encoding = BTy->getEncoding(); + std::unique_ptr TypeEntry; + switch (Encoding) { + case dwarf::DW_ATE_boolean: + case dwarf::DW_ATE_signed: + case dwarf::DW_ATE_signed_char: + case dwarf::DW_ATE_unsigned: + case dwarf::DW_ATE_unsigned_char: + // Create a BTF type instance for this DIBasicType and put it into + // DIToIdMap for cross-type reference check. + TypeEntry = std::make_unique( + Encoding, BTy->getSizeInBits(), BTy->getOffsetInBits(), BTy->getName()); + break; + case dwarf::DW_ATE_float: + TypeEntry = + std::make_unique(BTy->getSizeInBits(), BTy->getName()); + break; + default: + return; + } + + TypeId = addType(std::move(TypeEntry), BTy); +} + +/// Handle subprogram or subroutine types. +void BTFDebug::visitSubroutineType( + const DISubroutineType *STy, bool ForSubprog, + const std::unordered_map &FuncArgNames, + uint32_t &TypeId) { + DITypeRefArray Elements = STy->getTypeArray(); + uint32_t VLen = Elements.size() - 1; + if (VLen > BTF::MAX_VLEN) + return; + + // Subprogram has a valid non-zero-length name, and the pointee of + // a function pointer has an empty name. The subprogram type will + // not be added to DIToIdMap as it should not be referenced by + // any other types. + auto TypeEntry = std::make_unique(STy, VLen, FuncArgNames); + if (ForSubprog) + TypeId = addType(std::move(TypeEntry)); // For subprogram + else + TypeId = addType(std::move(TypeEntry), STy); // For func ptr + + // Visit return type and func arg types. + for (const auto Element : Elements) { + visitTypeEntry(Element); + } +} + +void BTFDebug::processDeclAnnotations(DINodeArray Annotations, + uint32_t BaseTypeId, + int ComponentIdx) { + if (!Annotations) + return; + + for (const Metadata *Annotation : Annotations->operands()) { + const MDNode *MD = cast(Annotation); + const MDString *Name = cast(MD->getOperand(0)); + if (Name->getString() != "btf_decl_tag") + continue; + + const MDString *Value = cast(MD->getOperand(1)); + auto TypeEntry = std::make_unique(BaseTypeId, ComponentIdx, + Value->getString()); + addType(std::move(TypeEntry)); + } +} + +uint32_t BTFDebug::processDISubprogram(const DISubprogram *SP, + uint32_t ProtoTypeId, uint8_t Scope) { + auto FuncTypeEntry = + std::make_unique(SP->getName(), ProtoTypeId, Scope); + uint32_t FuncId = addType(std::move(FuncTypeEntry)); + + // Process argument annotations. + for (const DINode *DN : SP->getRetainedNodes()) { + if (const auto *DV = dyn_cast(DN)) { + uint32_t Arg = DV->getArg(); + if (Arg) + processDeclAnnotations(DV->getAnnotations(), FuncId, Arg - 1); + } + } + processDeclAnnotations(SP->getAnnotations(), FuncId, -1); + + return FuncId; +} + +/// Generate btf_type_tag chains. +int BTFDebug::genBTFTypeTags(const DIDerivedType *DTy, int BaseTypeId) { + SmallVector MDStrs; + DINodeArray Annots = DTy->getAnnotations(); + if (Annots) { + // For type with "int __tag1 __tag2 *p", the MDStrs will have + // content: [__tag1, __tag2]. + for (const Metadata *Annotations : Annots->operands()) { + const MDNode *MD = cast(Annotations); + const MDString *Name = cast(MD->getOperand(0)); + if (Name->getString() != "btf_type_tag") + continue; + MDStrs.push_back(cast(MD->getOperand(1))); + } + } + + if (MDStrs.size() == 0) + return -1; + + // With MDStrs [__tag1, __tag2], the output type chain looks like + // PTR -> __tag2 -> __tag1 -> BaseType + // In the below, we construct BTF types with the order of __tag1, __tag2 + // and PTR. + unsigned TmpTypeId; + std::unique_ptr TypeEntry; + if (BaseTypeId >= 0) + TypeEntry = + std::make_unique(BaseTypeId, MDStrs[0]->getString()); + else + TypeEntry = std::make_unique(DTy, MDStrs[0]->getString()); + TmpTypeId = addType(std::move(TypeEntry)); + + for (unsigned I = 1; I < MDStrs.size(); I++) { + const MDString *Value = MDStrs[I]; + TypeEntry = std::make_unique(TmpTypeId, Value->getString()); + TmpTypeId = addType(std::move(TypeEntry)); + } + return TmpTypeId; +} + +/// Handle structure/union types. +void BTFDebug::visitStructType(const DICompositeType *CTy, bool IsStruct, + uint32_t &TypeId) { + const DINodeArray Elements = CTy->getElements(); + uint32_t VLen = Elements.size(); + if (VLen > BTF::MAX_VLEN) + return; + + // Check whether we have any bitfield members or not + bool HasBitField = false; + for (const auto *Element : Elements) { + auto E = cast(Element); + if (E->isBitField()) { + HasBitField = true; + break; + } + } + + auto TypeEntry = + std::make_unique(CTy, IsStruct, HasBitField, VLen); + StructTypes.push_back(TypeEntry.get()); + TypeId = addType(std::move(TypeEntry), CTy); + + // Check struct/union annotations + processDeclAnnotations(CTy->getAnnotations(), TypeId, -1); + + // Visit all struct members. + int FieldNo = 0; + for (const auto *Element : Elements) { + const auto Elem = cast(Element); + visitTypeEntry(Elem); + processDeclAnnotations(Elem->getAnnotations(), TypeId, FieldNo); + FieldNo++; + } +} + +void BTFDebug::visitArrayType(const DICompositeType *CTy, uint32_t &TypeId) { + // Visit array element type. + uint32_t ElemTypeId; + const DIType *ElemType = CTy->getBaseType(); + visitTypeEntry(ElemType, ElemTypeId, false, false); + + // Visit array dimensions. + DINodeArray Elements = CTy->getElements(); + for (int I = Elements.size() - 1; I >= 0; --I) { + if (auto *Element = dyn_cast_or_null(Elements[I])) + if (Element->getTag() == dwarf::DW_TAG_subrange_type) { + const DISubrange *SR = cast(Element); + auto *CI = dyn_cast(SR->getCount()); + int64_t Count = CI->getSExtValue(); + + // For struct s { int b; char c[]; }, the c[] will be represented + // as an array with Count = -1. + auto TypeEntry = + std::make_unique(ElemTypeId, + Count >= 0 ? Count : 0); + if (I == 0) + ElemTypeId = addType(std::move(TypeEntry), CTy); + else + ElemTypeId = addType(std::move(TypeEntry)); + } + } + + // The array TypeId is the type id of the outermost dimension. + TypeId = ElemTypeId; + + // The IR does not have a type for array index while BTF wants one. + // So create an array index type if there is none. + if (!ArrayIndexTypeId) { + auto TypeEntry = std::make_unique(dwarf::DW_ATE_unsigned, 32, + 0, "__ARRAY_SIZE_TYPE__"); + ArrayIndexTypeId = addType(std::move(TypeEntry)); + } +} + +void BTFDebug::visitEnumType(const DICompositeType *CTy, uint32_t &TypeId) { + DINodeArray Elements = CTy->getElements(); + uint32_t VLen = Elements.size(); + if (VLen > BTF::MAX_VLEN) + return; + + bool IsSigned = false; + unsigned NumBits = 32; + // No BaseType implies forward declaration in which case a + // BTFTypeEnum with Vlen = 0 is emitted. + if (CTy->getBaseType() != nullptr) { + const auto *BTy = cast(CTy->getBaseType()); + IsSigned = BTy->getEncoding() == dwarf::DW_ATE_signed || + BTy->getEncoding() == dwarf::DW_ATE_signed_char; + NumBits = BTy->getSizeInBits(); + } + + if (NumBits <= 32) { + auto TypeEntry = std::make_unique(CTy, VLen, IsSigned); + TypeId = addType(std::move(TypeEntry), CTy); + } else { + assert(NumBits == 64); + auto TypeEntry = std::make_unique(CTy, VLen, IsSigned); + TypeId = addType(std::move(TypeEntry), CTy); + } + // No need to visit base type as BTF does not encode it. +} + +/// Handle structure/union forward declarations. +void BTFDebug::visitFwdDeclType(const DICompositeType *CTy, bool IsUnion, + uint32_t &TypeId) { + auto TypeEntry = std::make_unique(CTy->getName(), IsUnion); + TypeId = addType(std::move(TypeEntry), CTy); +} + +/// Handle structure, union, array and enumeration types. +void BTFDebug::visitCompositeType(const DICompositeType *CTy, + uint32_t &TypeId) { + auto Tag = CTy->getTag(); + if (Tag == dwarf::DW_TAG_structure_type || Tag == dwarf::DW_TAG_union_type) { + // Handle forward declaration differently as it does not have members. + if (CTy->isForwardDecl()) + visitFwdDeclType(CTy, Tag == dwarf::DW_TAG_union_type, TypeId); + else + visitStructType(CTy, Tag == dwarf::DW_TAG_structure_type, TypeId); + } else if (Tag == dwarf::DW_TAG_array_type) + visitArrayType(CTy, TypeId); + else if (Tag == dwarf::DW_TAG_enumeration_type) + visitEnumType(CTy, TypeId); +} + +bool BTFDebug::IsForwardDeclCandidate(const DIType *Base) { + if (const auto *CTy = dyn_cast(Base)) { + auto CTag = CTy->getTag(); + if ((CTag == dwarf::DW_TAG_structure_type || + CTag == dwarf::DW_TAG_union_type) && + !CTy->getName().empty() && !CTy->isForwardDecl()) + return true; + } + return false; +} + +/// Handle pointer, typedef, const, volatile, restrict and member types. +void BTFDebug::visitDerivedType(const DIDerivedType *DTy, uint32_t &TypeId, + bool CheckPointer, bool SeenPointer) { + unsigned Tag = DTy->getTag(); + + /// Try to avoid chasing pointees, esp. structure pointees which may + /// unnecessary bring in a lot of types. + if (CheckPointer && !SeenPointer) { + SeenPointer = Tag == dwarf::DW_TAG_pointer_type; + } + + if (CheckPointer && SeenPointer) { + const DIType *Base = DTy->getBaseType(); + if (Base) { + if (IsForwardDeclCandidate(Base)) { + /// Find a candidate, generate a fixup. Later on the struct/union + /// pointee type will be replaced with either a real type or + /// a forward declaration. + auto TypeEntry = std::make_unique(DTy, Tag, true); + auto &Fixup = FixupDerivedTypes[dyn_cast(Base)]; + Fixup.push_back(std::make_pair(DTy, TypeEntry.get())); + TypeId = addType(std::move(TypeEntry), DTy); + return; + } + } + } + + if (Tag == dwarf::DW_TAG_pointer_type) { + int TmpTypeId = genBTFTypeTags(DTy, -1); + if (TmpTypeId >= 0) { + auto TypeDEntry = + std::make_unique(TmpTypeId, Tag, DTy->getName()); + TypeId = addType(std::move(TypeDEntry), DTy); + } else { + auto TypeEntry = std::make_unique(DTy, Tag, false); + TypeId = addType(std::move(TypeEntry), DTy); + } + } else if (Tag == dwarf::DW_TAG_typedef || Tag == dwarf::DW_TAG_const_type || + Tag == dwarf::DW_TAG_volatile_type || + Tag == dwarf::DW_TAG_restrict_type) { + auto TypeEntry = std::make_unique(DTy, Tag, false); + TypeId = addType(std::move(TypeEntry), DTy); + if (Tag == dwarf::DW_TAG_typedef) + processDeclAnnotations(DTy->getAnnotations(), TypeId, -1); + } else if (Tag != dwarf::DW_TAG_member) { + return; + } + + // Visit base type of pointer, typedef, const, volatile, restrict or + // struct/union member. + uint32_t TempTypeId = 0; + if (Tag == dwarf::DW_TAG_member) + visitTypeEntry(DTy->getBaseType(), TempTypeId, true, false); + else + visitTypeEntry(DTy->getBaseType(), TempTypeId, CheckPointer, SeenPointer); +} + +/// Visit a type entry. CheckPointer is true if the type has +/// one of its predecessors as one struct/union member. SeenPointer +/// is true if CheckPointer is true and one of its predecessors +/// is a pointer. The goal of CheckPointer and SeenPointer is to +/// do pruning for struct/union types so some of these types +/// will not be emitted in BTF and rather forward declarations +/// will be generated. +void BTFDebug::visitTypeEntry(const DIType *Ty, uint32_t &TypeId, + bool CheckPointer, bool SeenPointer) { + if (!Ty || DIToIdMap.find(Ty) != DIToIdMap.end()) { + TypeId = DIToIdMap[Ty]; + + // To handle the case like the following: + // struct t; + // typedef struct t _t; + // struct s1 { _t *c; }; + // int test1(struct s1 *arg) { ... } + // + // struct t { int a; int b; }; + // struct s2 { _t c; } + // int test2(struct s2 *arg) { ... } + // + // During traversing test1() argument, "_t" is recorded + // in DIToIdMap and a forward declaration fixup is created + // for "struct t" to avoid pointee type traversal. + // + // During traversing test2() argument, even if we see "_t" is + // already defined, we should keep moving to eventually + // bring in types for "struct t". Otherwise, the "struct s2" + // definition won't be correct. + // + // In the above, we have following debuginfo: + // {ptr, struct_member} -> typedef -> struct + // and BTF type for 'typedef' is generated while 'struct' may + // be in FixUp. But let us generalize the above to handle + // {different types} -> [various derived types]+ -> another type. + // For example, + // {func_param, struct_member} -> const -> ptr -> volatile -> struct + // We will traverse const/ptr/volatile which already have corresponding + // BTF types and generate type for 'struct' which might be in Fixup + // state. + if (Ty && (!CheckPointer || !SeenPointer)) { + if (const auto *DTy = dyn_cast(Ty)) { + while (DTy) { + const DIType *BaseTy = DTy->getBaseType(); + if (!BaseTy) + break; + + if (DIToIdMap.find(BaseTy) != DIToIdMap.end()) { + DTy = dyn_cast(BaseTy); + } else { + if (CheckPointer && DTy->getTag() == dwarf::DW_TAG_pointer_type) { + SeenPointer = true; + if (IsForwardDeclCandidate(BaseTy)) + break; + } + uint32_t TmpTypeId; + visitTypeEntry(BaseTy, TmpTypeId, CheckPointer, SeenPointer); + break; + } + } + } + } + + return; + } + + if (const auto *BTy = dyn_cast(Ty)) + visitBasicType(BTy, TypeId); + else if (const auto *STy = dyn_cast(Ty)) + visitSubroutineType(STy, false, std::unordered_map(), + TypeId); + else if (const auto *CTy = dyn_cast(Ty)) + visitCompositeType(CTy, TypeId); + else if (const auto *DTy = dyn_cast(Ty)) + visitDerivedType(DTy, TypeId, CheckPointer, SeenPointer); + else + llvm_unreachable("Unknown DIType"); +} + +void BTFDebug::visitTypeEntry(const DIType *Ty) { + uint32_t TypeId; + visitTypeEntry(Ty, TypeId, false, false); +} + +void BTFDebug::visitMapDefType(const DIType *Ty, uint32_t &TypeId) { + if (!Ty || DIToIdMap.find(Ty) != DIToIdMap.end()) { + TypeId = DIToIdMap[Ty]; + return; + } + + // MapDef type may be a struct type or a non-pointer derived type + const DIType *OrigTy = Ty; + while (auto *DTy = dyn_cast(Ty)) { + auto Tag = DTy->getTag(); + if (Tag != dwarf::DW_TAG_typedef && Tag != dwarf::DW_TAG_const_type && + Tag != dwarf::DW_TAG_volatile_type && + Tag != dwarf::DW_TAG_restrict_type) + break; + Ty = DTy->getBaseType(); + } + + const auto *CTy = dyn_cast(Ty); + if (!CTy) + return; + + auto Tag = CTy->getTag(); + if (Tag != dwarf::DW_TAG_structure_type || CTy->isForwardDecl()) + return; + + // Visit all struct members to ensure pointee type is visited + const DINodeArray Elements = CTy->getElements(); + for (const auto *Element : Elements) { + const auto *MemberType = cast(Element); + visitTypeEntry(MemberType->getBaseType()); + } + + // Visit this type, struct or a const/typedef/volatile/restrict type + visitTypeEntry(OrigTy, TypeId, false, false); +} + +/// Read file contents from the actual file or from the source +std::string BTFDebug::populateFileContent(const DISubprogram *SP) { + auto File = SP->getFile(); + std::string FileName; + + if (!File->getFilename().starts_with("/") && File->getDirectory().size()) + FileName = File->getDirectory().str() + "/" + File->getFilename().str(); + else + FileName = std::string(File->getFilename()); + + // No need to populate the contends if it has been populated! + if (FileContent.contains(FileName)) + return FileName; + + std::vector Content; + std::string Line; + Content.push_back(Line); // Line 0 for empty string + + std::unique_ptr Buf; + auto Source = File->getSource(); + if (Source) + Buf = MemoryBuffer::getMemBufferCopy(*Source); + else if (ErrorOr> BufOrErr = + MemoryBuffer::getFile(FileName)) + Buf = std::move(*BufOrErr); + if (Buf) + for (line_iterator I(*Buf, false), E; I != E; ++I) + Content.push_back(std::string(*I)); + + FileContent[FileName] = Content; + return FileName; +} + +void BTFDebug::constructLineInfo(const DISubprogram *SP, MCSymbol *Label, + uint32_t Line, uint32_t Column) { + std::string FileName = populateFileContent(SP); + BTFLineInfo LineInfo; + + LineInfo.Label = Label; + LineInfo.FileNameOff = addString(FileName); + // If file content is not available, let LineOff = 0. + if (Line < FileContent[FileName].size()) + LineInfo.LineOff = addString(FileContent[FileName][Line]); + else + LineInfo.LineOff = 0; + LineInfo.LineNum = Line; + LineInfo.ColumnNum = Column; + LineInfoTable[SecNameOff].push_back(LineInfo); +} + +void BTFDebug::emitCommonHeader() { + OS.AddComment("0x" + Twine::utohexstr(BTF::MAGIC)); + OS.emitIntValue(BTF::MAGIC, 2); + OS.emitInt8(BTF::VERSION); + OS.emitInt8(0); +} + +void BTFDebug::emitBTFSection() { + // Do not emit section if no types and only "" string. + if (!TypeEntries.size() && StringTable.getSize() == 1) + return; + + MCContext &Ctx = OS.getContext(); + MCSectionELF *Sec = Ctx.getELFSection(".BTF", ELF::SHT_PROGBITS, 0); + Sec->setAlignment(Align(4)); + OS.switchSection(Sec); + + // Emit header. + emitCommonHeader(); + OS.emitInt32(BTF::HeaderSize); + + uint32_t TypeLen = 0, StrLen; + for (const auto &TypeEntry : TypeEntries) + TypeLen += TypeEntry->getSize(); + StrLen = StringTable.getSize(); + + OS.emitInt32(0); + OS.emitInt32(TypeLen); + OS.emitInt32(TypeLen); + OS.emitInt32(StrLen); + + // Emit type table. + for (const auto &TypeEntry : TypeEntries) + TypeEntry->emitType(OS); + + // Emit string table. + uint32_t StringOffset = 0; + for (const auto &S : StringTable.getTable()) { + OS.AddComment("string offset=" + std::to_string(StringOffset)); + OS.emitBytes(S); + OS.emitBytes(StringRef("\0", 1)); + StringOffset += S.size() + 1; + } +} + +void BTFDebug::emitBTFExtSection() { + // Do not emit section if empty FuncInfoTable and LineInfoTable + // and FieldRelocTable. + if (!FuncInfoTable.size() && !LineInfoTable.size() && + !FieldRelocTable.size()) + return; + + MCContext &Ctx = OS.getContext(); + MCSectionELF *Sec = Ctx.getELFSection(".BTF.ext", ELF::SHT_PROGBITS, 0); + Sec->setAlignment(Align(4)); + OS.switchSection(Sec); + + // Emit header. + emitCommonHeader(); + OS.emitInt32(BTF::ExtHeaderSize); + + // Account for FuncInfo/LineInfo record size as well. + uint32_t FuncLen = 4, LineLen = 4; + // Do not account for optional FieldReloc. + uint32_t FieldRelocLen = 0; + for (const auto &FuncSec : FuncInfoTable) { + FuncLen += BTF::SecFuncInfoSize; + FuncLen += FuncSec.second.size() * BTF::SBFFuncInfoSize; + } + for (const auto &LineSec : LineInfoTable) { + LineLen += BTF::SecLineInfoSize; + LineLen += LineSec.second.size() * BTF::SBFLineInfoSize; + } + for (const auto &FieldRelocSec : FieldRelocTable) { + FieldRelocLen += BTF::SecFieldRelocSize; + FieldRelocLen += FieldRelocSec.second.size() * BTF::SBFFieldRelocSize; + } + + if (FieldRelocLen) + FieldRelocLen += 4; + + OS.emitInt32(0); + OS.emitInt32(FuncLen); + OS.emitInt32(FuncLen); + OS.emitInt32(LineLen); + OS.emitInt32(FuncLen + LineLen); + OS.emitInt32(FieldRelocLen); + + // Emit func_info table. + OS.AddComment("FuncInfo"); + OS.emitInt32(BTF::SBFFuncInfoSize); + for (const auto &FuncSec : FuncInfoTable) { + OS.AddComment("FuncInfo section string offset=" + + std::to_string(FuncSec.first)); + OS.emitInt32(FuncSec.first); + OS.emitInt32(FuncSec.second.size()); + for (const auto &FuncInfo : FuncSec.second) { + Asm->emitLabelReference(FuncInfo.Label, 4); + OS.emitInt32(FuncInfo.TypeId); + } + } + + // Emit line_info table. + OS.AddComment("LineInfo"); + OS.emitInt32(BTF::SBFLineInfoSize); + for (const auto &LineSec : LineInfoTable) { + OS.AddComment("LineInfo section string offset=" + + std::to_string(LineSec.first)); + OS.emitInt32(LineSec.first); + OS.emitInt32(LineSec.second.size()); + for (const auto &LineInfo : LineSec.second) { + Asm->emitLabelReference(LineInfo.Label, 4); + OS.emitInt32(LineInfo.FileNameOff); + OS.emitInt32(LineInfo.LineOff); + OS.AddComment("Line " + std::to_string(LineInfo.LineNum) + " Col " + + std::to_string(LineInfo.ColumnNum)); + OS.emitInt32(LineInfo.LineNum << 10 | LineInfo.ColumnNum); + } + } + + // Emit field reloc table. + if (FieldRelocLen) { + OS.AddComment("FieldReloc"); + OS.emitInt32(BTF::SBFFieldRelocSize); + for (const auto &FieldRelocSec : FieldRelocTable) { + OS.AddComment("Field reloc section string offset=" + + std::to_string(FieldRelocSec.first)); + OS.emitInt32(FieldRelocSec.first); + OS.emitInt32(FieldRelocSec.second.size()); + for (const auto &FieldRelocInfo : FieldRelocSec.second) { + Asm->emitLabelReference(FieldRelocInfo.Label, 4); + OS.emitInt32(FieldRelocInfo.TypeID); + OS.emitInt32(FieldRelocInfo.OffsetNameOff); + OS.emitInt32(FieldRelocInfo.RelocKind); + } + } + } +} + +void BTFDebug::beginFunctionImpl(const MachineFunction *MF) { + auto *SP = MF->getFunction().getSubprogram(); + auto *Unit = SP->getUnit(); + + if (Unit->getEmissionKind() == DICompileUnit::NoDebug) { + SkipInstruction = true; + return; + } + SkipInstruction = false; + + // Collect MapDef types. Map definition needs to collect + // pointee types. Do it first. Otherwise, for the following + // case: + // struct m { ...}; + // struct t { + // struct m *key; + // }; + // foo(struct t *arg); + // + // struct mapdef { + // ... + // struct m *key; + // ... + // } __attribute__((section(".maps"))) hash_map; + // + // If subroutine foo is traversed first, a type chain + // "ptr->struct m(fwd)" will be created and later on + // when traversing mapdef, since "ptr->struct m" exists, + // the traversal of "struct m" will be omitted. + if (MapDefNotCollected) { + processGlobals(true); + MapDefNotCollected = false; + } + + // Collect all types locally referenced in this function. + // Use RetainedNodes so we can collect all argument names + // even if the argument is not used. + std::unordered_map FuncArgNames; + for (const DINode *DN : SP->getRetainedNodes()) { + if (const auto *DV = dyn_cast(DN)) { + // Collect function arguments for subprogram func type. + uint32_t Arg = DV->getArg(); + if (Arg) { + visitTypeEntry(DV->getType()); + FuncArgNames[Arg] = DV->getName(); + } + } + } + + // Construct subprogram func proto type. + uint32_t ProtoTypeId; + visitSubroutineType(SP->getType(), true, FuncArgNames, ProtoTypeId); + + // Construct subprogram func type + uint8_t Scope = SP->isLocalToUnit() ? BTF::FUNC_STATIC : BTF::FUNC_GLOBAL; + uint32_t FuncTypeId = processDISubprogram(SP, ProtoTypeId, Scope); + + for (const auto &TypeEntry : TypeEntries) + TypeEntry->completeType(*this); + + // Construct funcinfo and the first lineinfo for the function. + MCSymbol *FuncLabel = Asm->getFunctionBegin(); + BTFFuncInfo FuncInfo; + FuncInfo.Label = FuncLabel; + FuncInfo.TypeId = FuncTypeId; + if (FuncLabel->isInSection()) { + MCSection &Section = FuncLabel->getSection(); + const MCSectionELF *SectionELF = dyn_cast(&Section); + assert(SectionELF && "Null section for Function Label"); + SecNameOff = addString(SectionELF->getName()); + } else { + SecNameOff = addString(".text"); + } + FuncInfoTable[SecNameOff].push_back(FuncInfo); +} + +void BTFDebug::endFunctionImpl(const MachineFunction *MF) { + SkipInstruction = false; + LineInfoGenerated = false; + SecNameOff = 0; +} + +/// On-demand populate types as requested from abstract member +/// accessing or preserve debuginfo type. +unsigned BTFDebug::populateType(const DIType *Ty) { + unsigned Id; + visitTypeEntry(Ty, Id, false, false); + for (const auto &TypeEntry : TypeEntries) + TypeEntry->completeType(*this); + return Id; +} + +/// Generate a struct member field relocation. +void BTFDebug::generatePatchImmReloc(const MCSymbol *ORSym, uint32_t RootId, + const GlobalVariable *GVar, bool IsAma) { + BTFFieldReloc FieldReloc; + FieldReloc.Label = ORSym; + FieldReloc.TypeID = RootId; + + StringRef AccessPattern = GVar->getName(); + size_t FirstDollar = AccessPattern.find_first_of('$'); + if (IsAma) { + size_t FirstColon = AccessPattern.find_first_of(':'); + size_t SecondColon = AccessPattern.find_first_of(':', FirstColon + 1); + StringRef IndexPattern = AccessPattern.substr(FirstDollar + 1); + StringRef RelocKindStr = AccessPattern.substr(FirstColon + 1, + SecondColon - FirstColon); + StringRef PatchImmStr = AccessPattern.substr(SecondColon + 1, + FirstDollar - SecondColon); + + FieldReloc.OffsetNameOff = addString(IndexPattern); + FieldReloc.RelocKind = std::stoull(std::string(RelocKindStr)); + PatchImms[GVar] = std::make_pair(std::stoll(std::string(PatchImmStr)), + FieldReloc.RelocKind); + } else { + StringRef RelocStr = AccessPattern.substr(FirstDollar + 1); + FieldReloc.OffsetNameOff = addString("0"); + FieldReloc.RelocKind = std::stoull(std::string(RelocStr)); + PatchImms[GVar] = std::make_pair(RootId, FieldReloc.RelocKind); + } + FieldRelocTable[SecNameOff].push_back(FieldReloc); +} + +void BTFDebug::processGlobalValue(const MachineOperand &MO) { + // check whether this is a candidate or not + if (MO.isGlobal()) { + const GlobalValue *GVal = MO.getGlobal(); + auto *GVar = dyn_cast(GVal); + if (!GVar) { + // Not a global variable. Maybe an extern function reference. + processFuncPrototypes(dyn_cast(GVal)); + return; + } + + if (!GVar->hasAttribute(SBFCoreSharedInfo::AmaAttr) && + !GVar->hasAttribute(SBFCoreSharedInfo::TypeIdAttr)) + return; + + MCSymbol *ORSym = OS.getContext().createTempSymbol(); + OS.emitLabel(ORSym); + + MDNode *MDN = GVar->getMetadata(LLVMContext::MD_preserve_access_index); + uint32_t RootId = populateType(dyn_cast(MDN)); + generatePatchImmReloc(ORSym, RootId, GVar, + GVar->hasAttribute(SBFCoreSharedInfo::AmaAttr)); + } +} + +static bool isCoreLoadOrStore(unsigned OpCode, bool NewMemEncoding) { + if (NewMemEncoding) + return OpCode == SBF::CORE_LD64_V2 || OpCode == SBF::CORE_LD32_V2 || + OpCode == SBF::CORE_ST_V2; + + return OpCode == SBF::CORE_LD64_V1 || OpCode == SBF::CORE_LD32_V1 || + OpCode == SBF::CORE_ST_V1; +} + +void BTFDebug::beginInstruction(const MachineInstr *MI) { + DebugHandlerBase::beginInstruction(MI); + + if (SkipInstruction || MI->isMetaInstruction() || + MI->getFlag(MachineInstr::FrameSetup)) + return; + + if (MI->isInlineAsm()) { + // Count the number of register definitions to find the asm string. + unsigned NumDefs = 0; + for (; MI->getOperand(NumDefs).isReg() && MI->getOperand(NumDefs).isDef(); + ++NumDefs) + ; + + // Skip this inline asm instruction if the asmstr is empty. + const char *AsmStr = MI->getOperand(NumDefs).getSymbolName(); + if (AsmStr[0] == 0) + return; + } + + bool NewMemEncoding = MI->getParent() + ->getParent() + ->getSubtarget() + .getNewMemEncoding(); + if (MI->getOpcode() == SBF::LD_imm64) { + // If the insn is "r2 = LD_imm64 @", + // add this insn into the .BTF.ext FieldReloc subsection. + // Relocation looks like: + // . SecName: + // . InstOffset + // . TypeID + // . OffSetNameOff + // . RelocType + // Later, the insn is replaced with "r2 = " + // where "" equals to the offset based on current + // type definitions. + // + // If the insn is "r2 = LD_imm64 @", + // The LD_imm64 result will be replaced with a btf type id. + processGlobalValue(MI->getOperand(1)); + } else if (isCoreLoadOrStore(MI->getOpcode(), NewMemEncoding) || + MI->getOpcode() == SBF::CORE_SHIFT) { + // relocation insn is a load, store or shift insn. + processGlobalValue(MI->getOperand(3)); + } else if (MI->getOpcode() == SBF::JAL) { + // check extern function references + const MachineOperand &MO = MI->getOperand(0); + if (MO.isGlobal()) { + processFuncPrototypes(dyn_cast(MO.getGlobal())); + } + } + + if (!CurMI) // no debug info + return; + + // Skip this instruction if no DebugLoc or the DebugLoc + // is the same as the previous instruction. + const DebugLoc &DL = MI->getDebugLoc(); + if (!DL || PrevInstLoc == DL) { + // This instruction will be skipped, no LineInfo has + // been generated, construct one based on function signature. + if (LineInfoGenerated == false) { + auto *S = MI->getMF()->getFunction().getSubprogram(); + if (S) { + MCSymbol *FuncLabel = Asm->getFunctionBegin(); + constructLineInfo(S, FuncLabel, S->getLine(), 0); + LineInfoGenerated = true; + } + } + return; + } + + // Create a temporary label to remember the insn for lineinfo. + MCSymbol *LineSym = OS.getContext().createTempSymbol(); + OS.emitLabel(LineSym); + + // Construct the lineinfo. + auto SP = DL->getScope()->getSubprogram(); + constructLineInfo(SP, LineSym, DL.getLine(), DL.getCol()); + + LineInfoGenerated = true; + PrevInstLoc = DL; +} + +void BTFDebug::processGlobals(bool ProcessingMapDef) { + // Collect all types referenced by globals. + const Module *M = MMI->getModule(); + for (const GlobalVariable &Global : M->globals()) { + // Decide the section name. + StringRef SecName; + std::optional GVKind; + + if (!Global.isDeclarationForLinker()) + GVKind = TargetLoweringObjectFile::getKindForGlobal(&Global, Asm->TM); + + if (Global.isDeclarationForLinker()) + SecName = Global.hasSection() ? Global.getSection() : ""; + else if (GVKind->isCommon()) + SecName = ".bss"; + else { + TargetLoweringObjectFile *TLOF = Asm->TM.getObjFileLowering(); + MCSection *Sec = TLOF->SectionForGlobal(&Global, Asm->TM); + SecName = Sec->getName(); + } + + if (ProcessingMapDef != SecName.starts_with(".maps")) + continue; + + // Create a .rodata datasec if the global variable is an initialized + // constant with private linkage and if it won't be in .rodata.str<#> + // and .rodata.cst<#> sections. + if (SecName == ".rodata" && Global.hasPrivateLinkage() && + DataSecEntries.find(std::string(SecName)) == DataSecEntries.end()) { + // skip .rodata.str<#> and .rodata.cst<#> sections + if (!GVKind->isMergeableCString() && !GVKind->isMergeableConst()) { + DataSecEntries[std::string(SecName)] = + std::make_unique(Asm, std::string(SecName)); + } + } + + SmallVector GVs; + Global.getDebugInfo(GVs); + + // No type information, mostly internal, skip it. + if (GVs.size() == 0) + continue; + + uint32_t GVTypeId = 0; + DIGlobalVariable *DIGlobal = nullptr; + for (auto *GVE : GVs) { + DIGlobal = GVE->getVariable(); + if (SecName.starts_with(".maps")) + visitMapDefType(DIGlobal->getType(), GVTypeId); + else + visitTypeEntry(DIGlobal->getType(), GVTypeId, false, false); + break; + } + + // Only support the following globals: + // . static variables + // . non-static weak or non-weak global variables + // . weak or non-weak extern global variables + // Whether DataSec is readonly or not can be found from corresponding ELF + // section flags. Whether a BTF_KIND_VAR is a weak symbol or not + // can be found from the corresponding ELF symbol table. + auto Linkage = Global.getLinkage(); + if (Linkage != GlobalValue::InternalLinkage && + Linkage != GlobalValue::ExternalLinkage && + Linkage != GlobalValue::WeakAnyLinkage && + Linkage != GlobalValue::WeakODRLinkage && + Linkage != GlobalValue::ExternalWeakLinkage) + continue; + + uint32_t GVarInfo; + if (Linkage == GlobalValue::InternalLinkage) { + GVarInfo = BTF::VAR_STATIC; + } else if (Global.hasInitializer()) { + GVarInfo = BTF::VAR_GLOBAL_ALLOCATED; + } else { + GVarInfo = BTF::VAR_GLOBAL_EXTERNAL; + } + + auto VarEntry = + std::make_unique(Global.getName(), GVTypeId, GVarInfo); + uint32_t VarId = addType(std::move(VarEntry)); + + processDeclAnnotations(DIGlobal->getAnnotations(), VarId, -1); + + // An empty SecName means an extern variable without section attribute. + if (SecName.empty()) + continue; + + // Find or create a DataSec + auto [It, Inserted] = DataSecEntries.try_emplace(std::string(SecName)); + if (Inserted) + It->second = std::make_unique(Asm, std::string(SecName)); + + // Calculate symbol size + const DataLayout &DL = Global.getParent()->getDataLayout(); + uint32_t Size = DL.getTypeAllocSize(Global.getValueType()); + + It->second->addDataSecEntry(VarId, Asm->getSymbol(&Global), Size); + } +} + +/// Emit proper patchable instructions. +bool BTFDebug::InstLower(const MachineInstr *MI, MCInst &OutMI) { + bool NewMemEncoding = MI->getParent() + ->getParent() + ->getSubtarget() + .getNewMemEncoding(); + if (MI->getOpcode() == SBF::LD_imm64) { + const MachineOperand &MO = MI->getOperand(1); + if (MO.isGlobal()) { + const GlobalValue *GVal = MO.getGlobal(); + auto *GVar = dyn_cast(GVal); + if (GVar) { + // Emit "mov ri, " + int64_t Imm; + uint32_t Reloc; + if (GVar->hasAttribute(SBFCoreSharedInfo::AmaAttr) || + GVar->hasAttribute(SBFCoreSharedInfo::TypeIdAttr)) { + Imm = PatchImms[GVar].first; + Reloc = PatchImms[GVar].second; + } else { + return false; + } + + if (Reloc == SBFCoreSharedInfo::ENUM_VALUE_EXISTENCE || + Reloc == SBFCoreSharedInfo::ENUM_VALUE || + Reloc == SBFCoreSharedInfo::BTF_TYPE_ID_LOCAL || + Reloc == SBFCoreSharedInfo::BTF_TYPE_ID_REMOTE) + OutMI.setOpcode(SBF::LD_imm64); + else + OutMI.setOpcode(SBF::MOV_ri); + OutMI.addOperand(MCOperand::createReg(MI->getOperand(0).getReg())); + OutMI.addOperand(MCOperand::createImm(Imm)); + return true; + } + } + } else if (isCoreLoadOrStore(MI->getOpcode(), NewMemEncoding) || + MI->getOpcode() == SBF::CORE_SHIFT) { + const MachineOperand &MO = MI->getOperand(3); + if (MO.isGlobal()) { + const GlobalValue *GVal = MO.getGlobal(); + auto *GVar = dyn_cast(GVal); + if (GVar && GVar->hasAttribute(SBFCoreSharedInfo::AmaAttr)) { + uint32_t Imm = PatchImms[GVar].first; + OutMI.setOpcode(MI->getOperand(1).getImm()); + if (MI->getOperand(0).isImm()) + OutMI.addOperand(MCOperand::createImm(MI->getOperand(0).getImm())); + else + OutMI.addOperand(MCOperand::createReg(MI->getOperand(0).getReg())); + OutMI.addOperand(MCOperand::createReg(MI->getOperand(2).getReg())); + OutMI.addOperand(MCOperand::createImm(Imm)); + return true; + } + } + } + return false; +} + +void BTFDebug::processFuncPrototypes(const Function *F) { + if (!F) + return; + + const DISubprogram *SP = F->getSubprogram(); + if (!SP || SP->isDefinition()) + return; + + // Do not emit again if already emitted. + if (!ProtoFunctions.insert(F).second) + return; + + uint32_t ProtoTypeId; + const std::unordered_map FuncArgNames; + visitSubroutineType(SP->getType(), false, FuncArgNames, ProtoTypeId); + uint32_t FuncId = processDISubprogram(SP, ProtoTypeId, BTF::FUNC_EXTERN); + + if (F->hasSection()) { + StringRef SecName = F->getSection(); + + auto [It, Inserted] = DataSecEntries.try_emplace(std::string(SecName)); + if (Inserted) + It->second = std::make_unique(Asm, std::string(SecName)); + + // We really don't know func size, set it to 0. + It->second->addDataSecEntry(FuncId, Asm->getSymbol(F), 0); + } +} + +void BTFDebug::endModule() { + // Collect MapDef globals if not collected yet. + if (MapDefNotCollected) { + processGlobals(true); + MapDefNotCollected = false; + } + + // Collect global types/variables except MapDef globals. + processGlobals(false); + + for (auto &DataSec : DataSecEntries) + addType(std::move(DataSec.second)); + + // Fixups + for (auto &Fixup : FixupDerivedTypes) { + const DICompositeType *CTy = Fixup.first; + StringRef TypeName = CTy->getName(); + bool IsUnion = CTy->getTag() == dwarf::DW_TAG_union_type; + + // Search through struct types + uint32_t StructTypeId = 0; + for (const auto &StructType : StructTypes) { + if (StructType->getName() == TypeName) { + StructTypeId = StructType->getId(); + break; + } + } + + if (StructTypeId == 0) { + auto FwdTypeEntry = std::make_unique(TypeName, IsUnion); + StructTypeId = addType(std::move(FwdTypeEntry)); + } + + for (auto &TypeInfo : Fixup.second) { + const DIDerivedType *DTy = TypeInfo.first; + BTFTypeDerived *BDType = TypeInfo.second; + + int TmpTypeId = genBTFTypeTags(DTy, StructTypeId); + if (TmpTypeId >= 0) + BDType->setPointeeType(TmpTypeId); + else + BDType->setPointeeType(StructTypeId); + } + } + + // Complete BTF type cross refereences. + for (const auto &TypeEntry : TypeEntries) + TypeEntry->completeType(*this); + + // Emit BTF sections. + emitBTFSection(); + emitBTFExtSection(); +} diff --git a/llvm/lib/Target/SBF/BTFDebug.h b/llvm/lib/Target/SBF/BTFDebug.h new file mode 100644 index 0000000000000..802ff956757f3 --- /dev/null +++ b/llvm/lib/Target/SBF/BTFDebug.h @@ -0,0 +1,438 @@ +//===- BTFDebug.h -----------------------------------------------*- 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 +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// This file contains support for writing BTF debug info. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIB_TARGET_SBF_BTFDEBUG_H +#define LLVM_LIB_TARGET_SBF_BTFDEBUG_H + +#include "llvm/ADT/StringMap.h" +#include "llvm/CodeGen/DebugHandlerBase.h" +#include +#include +#include +#include +#include "BTF.h" + +namespace llvm { + +class AsmPrinter; +class DIType; +class GlobalVariable; +class MachineFunction; +class MachineInstr; +class MachineOperand; +class MCInst; +class MCStreamer; +class MCSymbol; + +namespace BTFX { + +class BTFDebug; + +/// The base class for BTF type generation. +class BTFTypeBase { +protected: + uint8_t Kind; + bool IsCompleted; + uint32_t Id; + struct BTF::CommonType BTFType; + +public: + BTFTypeBase() : IsCompleted(false) {} + virtual ~BTFTypeBase() = default; + void setId(uint32_t Id) { this->Id = Id; } + uint32_t getId() { return Id; } + uint32_t roundupToBytes(uint32_t NumBits) { return (NumBits + 7) >> 3; } + /// Get the size of this BTF type entry. + virtual uint32_t getSize() { return BTF::CommonTypeSize; } + /// Complete BTF type generation after all related DebugInfo types + /// have been visited so their BTF type id's are available + /// for cross referece. + virtual void completeType(BTFDebug &BDebug) {} + /// Emit types for this BTF type entry. + virtual void emitType(MCStreamer &OS); +}; + +/// Handle several derived types include pointer, const, +/// volatile, typedef and restrict. +class BTFTypeDerived : public BTFTypeBase { + const DIDerivedType *DTy; + bool NeedsFixup; + StringRef Name; + +public: + BTFTypeDerived(const DIDerivedType *Ty, unsigned Tag, bool NeedsFixup); + BTFTypeDerived(unsigned NextTypeId, unsigned Tag, StringRef Name); + void completeType(BTFDebug &BDebug) override; + void emitType(MCStreamer &OS) override; + void setPointeeType(uint32_t PointeeType); +}; + +/// Handle struct or union forward declaration. +class BTFTypeFwd : public BTFTypeBase { + StringRef Name; + +public: + BTFTypeFwd(StringRef Name, bool IsUnion); + void completeType(BTFDebug &BDebug) override; + void emitType(MCStreamer &OS) override; +}; + +/// Handle int type. +class BTFTypeInt : public BTFTypeBase { + StringRef Name; + uint32_t IntVal; ///< Encoding, offset, bits + +public: + BTFTypeInt(uint32_t Encoding, uint32_t SizeInBits, uint32_t OffsetInBits, + StringRef TypeName); + uint32_t getSize() override { return BTFTypeBase::getSize() + sizeof(uint32_t); } + void completeType(BTFDebug &BDebug) override; + void emitType(MCStreamer &OS) override; +}; + +/// Handle enumerate type. +class BTFTypeEnum : public BTFTypeBase { + const DICompositeType *ETy; + std::vector EnumValues; + +public: + BTFTypeEnum(const DICompositeType *ETy, uint32_t NumValues, bool IsSigned); + uint32_t getSize() override { + return BTFTypeBase::getSize() + EnumValues.size() * BTF::BTFEnumSize; + } + void completeType(BTFDebug &BDebug) override; + void emitType(MCStreamer &OS) override; +}; + +/// Handle array type. +class BTFTypeArray : public BTFTypeBase { + struct BTF::BTFArray ArrayInfo; + +public: + BTFTypeArray(uint32_t ElemTypeId, uint32_t NumElems); + uint32_t getSize() override { return BTFTypeBase::getSize() + BTF::BTFArraySize; } + void completeType(BTFDebug &BDebug) override; + void emitType(MCStreamer &OS) override; +}; + +/// Handle struct/union type. +class BTFTypeStruct : public BTFTypeBase { + const DICompositeType *STy; + bool HasBitField; + std::vector Members; + +public: + BTFTypeStruct(const DICompositeType *STy, bool IsStruct, bool HasBitField, + uint32_t NumMembers); + uint32_t getSize() override { + return BTFTypeBase::getSize() + Members.size() * BTF::BTFMemberSize; + } + void completeType(BTFDebug &BDebug) override; + void emitType(MCStreamer &OS) override; + std::string getName(); +}; + +/// Handle function pointer. +class BTFTypeFuncProto : public BTFTypeBase { + const DISubroutineType *STy; + std::unordered_map FuncArgNames; + std::vector Parameters; + +public: + BTFTypeFuncProto(const DISubroutineType *STy, uint32_t NumParams, + const std::unordered_map &FuncArgNames); + uint32_t getSize() override { + return BTFTypeBase::getSize() + Parameters.size() * BTF::BTFParamSize; + } + void completeType(BTFDebug &BDebug) override; + void emitType(MCStreamer &OS) override; +}; + +/// Handle subprogram +class BTFTypeFunc : public BTFTypeBase { + StringRef Name; + +public: + BTFTypeFunc(StringRef FuncName, uint32_t ProtoTypeId, uint32_t Scope); + uint32_t getSize() override { return BTFTypeBase::getSize(); } + void completeType(BTFDebug &BDebug) override; + void emitType(MCStreamer &OS) override; +}; + +/// Handle variable instances +class BTFKindVar : public BTFTypeBase { + StringRef Name; + uint32_t Info; + +public: + BTFKindVar(StringRef VarName, uint32_t TypeId, uint32_t VarInfo); + uint32_t getSize() override { return BTFTypeBase::getSize() + 4; } + void completeType(BTFDebug &BDebug) override; + void emitType(MCStreamer &OS) override; +}; + +/// Handle data sections +class BTFKindDataSec : public BTFTypeBase { + AsmPrinter *Asm; + std::string Name; + std::vector> Vars; + +public: + BTFKindDataSec(AsmPrinter *AsmPrt, std::string SecName); + uint32_t getSize() override { + return BTFTypeBase::getSize() + BTF::BTFDataSecVarSize * Vars.size(); + } + void addDataSecEntry(uint32_t Id, const MCSymbol *Sym, uint32_t Size) { + Vars.push_back(std::make_tuple(Id, Sym, Size)); + } + std::string getName() { return Name; } + void completeType(BTFDebug &BDebug) override; + void emitType(MCStreamer &OS) override; +}; + +/// Handle binary floating point type. +class BTFTypeFloat : public BTFTypeBase { + StringRef Name; + +public: + BTFTypeFloat(uint32_t SizeInBits, StringRef TypeName); + void completeType(BTFDebug &BDebug) override; +}; + +/// Handle decl tags. +class BTFTypeDeclTag : public BTFTypeBase { + uint32_t Info; + StringRef Tag; + +public: + BTFTypeDeclTag(uint32_t BaseTypeId, int ComponentId, StringRef Tag); + uint32_t getSize() override { return BTFTypeBase::getSize() + 4; } + void completeType(BTFDebug &BDebug) override; + void emitType(MCStreamer &OS) override; +}; + +/// Handle 64-bit enumerate type. +class BTFTypeEnum64 : public BTFTypeBase { + const DICompositeType *ETy; + std::vector EnumValues; + +public: + BTFTypeEnum64(const DICompositeType *ETy, uint32_t NumValues, bool IsSigned); + uint32_t getSize() override { + return BTFTypeBase::getSize() + EnumValues.size() * BTF::BTFEnum64Size; + } + void completeType(BTFDebug &BDebug) override; + void emitType(MCStreamer &OS) override; +}; + +class BTFTypeTypeTag : public BTFTypeBase { + const DIDerivedType *DTy; + StringRef Tag; + +public: + BTFTypeTypeTag(uint32_t NextTypeId, StringRef Tag); + BTFTypeTypeTag(const DIDerivedType *DTy, StringRef Tag); + void completeType(BTFDebug &BDebug) override; +}; + +/// String table. +class BTFStringTable { + /// String table size in bytes. + uint32_t Size; + /// A mapping from string table offset to the index + /// of the Table. It is used to avoid putting + /// duplicated strings in the table. + std::map OffsetToIdMap; + /// A vector of strings to represent the string table. + std::vector Table; + +public: + BTFStringTable() : Size(0) {} + uint32_t getSize() { return Size; } + std::vector &getTable() { return Table; } + /// Add a string to the string table and returns its offset + /// in the table. + uint32_t addString(StringRef S); +}; + +/// Represent one func and its type id. +struct BTFFuncInfo { + const MCSymbol *Label; ///< Func MCSymbol + uint32_t TypeId; ///< Type id referring to .BTF type section +}; + +/// Represent one line info. +struct BTFLineInfo { + MCSymbol *Label; ///< MCSymbol identifying insn for the lineinfo + uint32_t FileNameOff; ///< file name offset in the .BTF string table + uint32_t LineOff; ///< line offset in the .BTF string table + uint32_t LineNum; ///< the line number + uint32_t ColumnNum; ///< the column number +}; + +/// Represent one field relocation. +struct BTFFieldReloc { + const MCSymbol *Label; ///< MCSymbol identifying insn for the reloc + uint32_t TypeID; ///< Type ID + uint32_t OffsetNameOff; ///< The string to traverse types + uint32_t RelocKind; ///< What to patch the instruction +}; + +/// Collect and emit BTF information. +class BTFDebug : public DebugHandlerBase { + MCStreamer &OS; + bool SkipInstruction; + bool LineInfoGenerated; + uint32_t SecNameOff; + uint32_t ArrayIndexTypeId; + bool MapDefNotCollected; + BTFStringTable StringTable; + std::vector> TypeEntries; + std::unordered_map DIToIdMap; + std::map> FuncInfoTable; + std::map> LineInfoTable; + std::map> FieldRelocTable; + StringMap> FileContent; + std::map> DataSecEntries; + std::vector StructTypes; + std::map> PatchImms; + std::map>> + FixupDerivedTypes; + std::setProtoFunctions; + + /// Add types to TypeEntries. + /// @{ + /// Add types to TypeEntries and DIToIdMap. + uint32_t addType(std::unique_ptr TypeEntry, const DIType *Ty); + /// Add types to TypeEntries only and return type id. + uint32_t addType(std::unique_ptr TypeEntry); + /// @} + + /// IR type visiting functions. + /// @{ + void visitTypeEntry(const DIType *Ty); + void visitTypeEntry(const DIType *Ty, uint32_t &TypeId, bool CheckPointer, + bool SeenPointer); + void visitBasicType(const DIBasicType *BTy, uint32_t &TypeId); + void visitSubroutineType( + const DISubroutineType *STy, bool ForSubprog, + const std::unordered_map &FuncArgNames, + uint32_t &TypeId); + void visitFwdDeclType(const DICompositeType *CTy, bool IsUnion, + uint32_t &TypeId); + void visitCompositeType(const DICompositeType *CTy, uint32_t &TypeId); + void visitStructType(const DICompositeType *STy, bool IsStruct, + uint32_t &TypeId); + void visitArrayType(const DICompositeType *ATy, uint32_t &TypeId); + void visitEnumType(const DICompositeType *ETy, uint32_t &TypeId); + void visitDerivedType(const DIDerivedType *DTy, uint32_t &TypeId, + bool CheckPointer, bool SeenPointer); + void visitMapDefType(const DIType *Ty, uint32_t &TypeId); + /// @} + + /// Check whether the type is a forward declaration candidate or not. + bool IsForwardDeclCandidate(const DIType *Base); + + /// Get the file content for the subprogram. Certain lines of the file + /// later may be put into string table and referenced by line info. + std::string populateFileContent(const DISubprogram *SP); + + /// Construct a line info. + void constructLineInfo(const DISubprogram *SP, MCSymbol *Label, uint32_t Line, + uint32_t Column); + + /// Generate types and variables for globals. + void processGlobals(bool ProcessingMapDef); + + /// Generate types for function prototypes. + void processFuncPrototypes(const Function *); + + /// Generate types for decl annotations. + void processDeclAnnotations(DINodeArray Annotations, uint32_t BaseTypeId, + int ComponentId); + + /// Generate types for DISubprogram and it's arguments. + uint32_t processDISubprogram(const DISubprogram *SP, uint32_t ProtoTypeId, + uint8_t Scope); + + /// Generate BTF type_tag's. If BaseTypeId is nonnegative, the last + /// BTF type_tag in the chain points to BaseTypeId. Otherwise, it points to + /// the base type of DTy. Return the type id of the first BTF type_tag + /// in the chain. If no type_tag's are generated, a negative value + /// is returned. + int genBTFTypeTags(const DIDerivedType *DTy, int BaseTypeId); + + /// Generate one field relocation record. + void generatePatchImmReloc(const MCSymbol *ORSym, uint32_t RootId, + const GlobalVariable *, bool IsAma); + + /// Populating unprocessed type on demand. + unsigned populateType(const DIType *Ty); + + /// Process global variables referenced by relocation instructions + /// and extern function references. + void processGlobalValue(const MachineOperand &MO); + + /// Emit common header of .BTF and .BTF.ext sections. + void emitCommonHeader(); + + /// Emit the .BTF section. + void emitBTFSection(); + + /// Emit the .BTF.ext section. + void emitBTFExtSection(); + +protected: + /// Gather pre-function debug information. + void beginFunctionImpl(const MachineFunction *MF) override; + + /// Post process after all instructions in this function are processed. + void endFunctionImpl(const MachineFunction *MF) override; + +public: + BTFDebug(AsmPrinter *AP); + + /// + bool InstLower(const MachineInstr *MI, MCInst &OutMI); + + /// Get the special array index type id. + uint32_t getArrayIndexTypeId() { + assert(ArrayIndexTypeId); + return ArrayIndexTypeId; + } + + /// Add string to the string table. + size_t addString(StringRef S) { return StringTable.addString(S); } + + /// Get the type id for a particular DIType. + uint32_t getTypeId(const DIType *Ty) { + assert(Ty && "Invalid null Type"); + assert(DIToIdMap.find(Ty) != DIToIdMap.end() && + "DIType not added in the BDIToIdMap"); + return DIToIdMap[Ty]; + } + + void setSymbolSize(const MCSymbol *Symbol, uint64_t Size) override {} + + /// Process beginning of an instruction. + void beginInstruction(const MachineInstr *MI) override; + + /// Complete all the types and emit the BTF sections. + void endModule() override; +}; + +} // end namespace BTFX +} // end namespace llvm + +#endif diff --git a/llvm/lib/Target/SBF/CMakeLists.txt b/llvm/lib/Target/SBF/CMakeLists.txt new file mode 100644 index 0000000000000..f7202627b0d2a --- /dev/null +++ b/llvm/lib/Target/SBF/CMakeLists.txt @@ -0,0 +1,69 @@ +add_llvm_component_group(SBF) + +set(LLVM_TARGET_DEFINITIONS SBF.td) + +tablegen(LLVM SBFGenAsmMatcher.inc -gen-asm-matcher) +tablegen(LLVM SBFGenAsmWriter.inc -gen-asm-writer) +tablegen(LLVM SBFGenCallingConv.inc -gen-callingconv) +tablegen(LLVM SBFGenDAGISel.inc -gen-dag-isel) +tablegen(LLVM SBFGenDisassemblerTables.inc -gen-disassembler) +tablegen(LLVM SBFGenInstrInfo.inc -gen-instr-info) +tablegen(LLVM SBFGenMCCodeEmitter.inc -gen-emitter) +tablegen(LLVM SBFGenRegisterInfo.inc -gen-register-info) +tablegen(LLVM SBFGenSubtargetInfo.inc -gen-subtarget) +tablegen(LLVM SBFGenGlobalISel.inc -gen-global-isel) +tablegen(LLVM SBFGenRegisterBank.inc -gen-register-bank) + +add_public_tablegen_target(SBFCommonTableGen) + +add_llvm_target(SBFCodeGen + GISel/SBFCallLowering.cpp + GISel/SBFInstructionSelector.cpp + GISel/SBFRegisterBankInfo.cpp + GISel/SBFLegalizerInfo.cpp + SBFAbstractMemberAccess.cpp + SBFAsmPrinter.cpp + SBFCheckAndAdjustIR.cpp + SBFFrameLowering.cpp + SBFFunctionInfo.cpp + SBFInstrInfo.cpp + SBFIRPeephole.cpp + SBFISelDAGToDAG.cpp + SBFISelLowering.cpp + SBFMCInstLower.cpp + SBFPreserveDIType.cpp + SBFRegisterInfo.cpp + SBFSubtarget.cpp + SBFTargetMachine.cpp + SBFMIPeephole.cpp + SBFMIChecking.cpp + SBFMISimplifyPatchable.cpp + BTFDebug.cpp + + LINK_COMPONENTS + Analysis + AsmPrinter + CodeGen + CodeGenTypes + Core + GlobalISel + MC + SBFDesc + SBFInfo + IPO + Passes + Scalar + SelectionDAG + Support + Target + TargetParser + TransformUtils + + ADD_TO_COMPONENT + SBF + ) + +add_subdirectory(AsmParser) +add_subdirectory(Disassembler) +add_subdirectory(MCTargetDesc) +add_subdirectory(TargetInfo) diff --git a/llvm/lib/Target/SBF/Disassembler/CMakeLists.txt b/llvm/lib/Target/SBF/Disassembler/CMakeLists.txt new file mode 100644 index 0000000000000..66e8363906163 --- /dev/null +++ b/llvm/lib/Target/SBF/Disassembler/CMakeLists.txt @@ -0,0 +1,13 @@ +add_llvm_component_library(LLVMSBFDisassembler + SBFDisassembler.cpp + + LINK_COMPONENTS + MCDisassembler + MC + SBFInfo + Support + + ADD_TO_COMPONENT + SBF +) + diff --git a/llvm/lib/Target/SBF/Disassembler/SBFDisassembler.cpp b/llvm/lib/Target/SBF/Disassembler/SBFDisassembler.cpp new file mode 100644 index 0000000000000..377309414e462 --- /dev/null +++ b/llvm/lib/Target/SBF/Disassembler/SBFDisassembler.cpp @@ -0,0 +1,257 @@ +//===- SBFDisassembler.cpp - Disassembler for SBF ---------------*- 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 +// +//===----------------------------------------------------------------------===// +// +// This file is part of the SBF Disassembler. +// +//===----------------------------------------------------------------------===// + +#include "MCTargetDesc/SBFMCTargetDesc.h" +#include "TargetInfo/SBFTargetInfo.h" +#include "llvm/ADT/ArrayRef.h" +#include "llvm/MC/MCAsmInfo.h" +#include "llvm/MC/MCContext.h" +#include "llvm/MC/MCDecoderOps.h" +#include "llvm/MC/MCDisassembler/MCDisassembler.h" +#include "llvm/MC/MCInst.h" +#include "llvm/MC/TargetRegistry.h" +#include "llvm/Support/MathExtras.h" +#include + +using namespace llvm; + +#define DEBUG_TYPE "sbf-disassembler" + +typedef MCDisassembler::DecodeStatus DecodeStatus; + +namespace { + +/// A disassembler class for SBF. +class SBFDisassembler : public MCDisassembler { +public: + enum SBF_CLASS { + SBF_LD = 0x0, + SBF_LDX = 0x1, + SBF_ST = 0x2, + SBF_STX = 0x3, + SBF_ALU = 0x4, + SBF_JMP = 0x5, + SBF_PQR = 0x6, + SBF_ALU64 = 0x7 + }; + + enum SBF_SIZE { SBF_W = 0x0, SBF_H = 0x1, SBF_B = 0x2, SBF_DW = 0x3 }; + + enum SBF_MODE { + SBF_IMM = 0x0, + SBF_ABS = 0x1, + SBF_IND = 0x2, + SBF_MEM = 0x3, + SBF_LEN = 0x4, + SBF_MSH = 0x5, + SBF_ATOMIC = 0x6 + }; + + SBFDisassembler(const MCSubtargetInfo &STI, MCContext &Ctx) + : MCDisassembler(STI, Ctx) {} + ~SBFDisassembler() override = default; + + DecodeStatus getInstruction(MCInst &Instr, uint64_t &Size, + ArrayRef Bytes, uint64_t Address, + raw_ostream &CStream) const override; + + uint8_t getInstClass(uint64_t Inst) const { return (Inst >> 56) & 0x7; }; + uint8_t getInstSize(uint64_t Inst) const { return (Inst >> 59) & 0x3; }; + uint8_t getInstMode(uint64_t Inst) const { return (Inst >> 61) & 0x7; }; + bool isMov32(uint64_t Inst) const { return (Inst >> 56) == 0xb4; } + bool isNewMem(uint64_t Inst) const; + bool isSyscallOrExit(uint64_t Inst) const { return (Inst >> 56) == 0x95; } + bool isAlu32NewLoadStoreReg(uint64_t Inst) const; +}; + +} // end anonymous namespace + +static MCDisassembler *createSBFDisassembler(const Target &T, + const MCSubtargetInfo &STI, + MCContext &Ctx) { + return new SBFDisassembler(STI, Ctx); +} + +extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeSBFDisassembler() { + // Register the disassembler. + TargetRegistry::RegisterMCDisassembler(getTheSBFXTarget(), + createSBFDisassembler); +} + +static const unsigned GPRDecoderTable[] = { + SBF::R0, SBF::R1, SBF::R2, SBF::R3, SBF::R4, SBF::R5, + SBF::R6, SBF::R7, SBF::R8, SBF::R9, SBF::R10 +}; + +static DecodeStatus DecodeGPRRegisterClass(MCInst &Inst, unsigned RegNo, + uint64_t /*Address*/, + const MCDisassembler * /*Decoder*/) { + if (RegNo > 11) + return MCDisassembler::Fail; + + unsigned Reg = GPRDecoderTable[RegNo]; + Inst.addOperand(MCOperand::createReg(Reg)); + return MCDisassembler::Success; +} + +static const unsigned GPR32DecoderTable[] = { + SBF::W0, SBF::W1, SBF::W2, SBF::W3, SBF::W4, SBF::W5, + SBF::W6, SBF::W7, SBF::W8, SBF::W9, SBF::W10 +}; + +static DecodeStatus +DecodeGPR32RegisterClass(MCInst &Inst, unsigned RegNo, uint64_t /*Address*/, + const MCDisassembler * /*Decoder*/) { + if (RegNo > 10) + return MCDisassembler::Fail; + + unsigned Reg = GPR32DecoderTable[RegNo]; + Inst.addOperand(MCOperand::createReg(Reg)); + return MCDisassembler::Success; +} + +static DecodeStatus decodeMemoryOpValue(MCInst &Inst, unsigned Insn, + uint64_t Address, + const MCDisassembler *Decoder) { + unsigned Register = (Insn >> 16) & 0xf; + if (Register > 10) + return MCDisassembler::Fail; + + Inst.addOperand(MCOperand::createReg(GPRDecoderTable[Register])); + unsigned Offset = (Insn & 0xffff); + Inst.addOperand(MCOperand::createImm(SignExtend32<16>(Offset))); + + return MCDisassembler::Success; +} + +#include "SBFGenDisassemblerTables.inc" +static DecodeStatus readInstruction64(ArrayRef Bytes, uint64_t Address, + uint64_t &Size, uint64_t &Insn, + bool IsLittleEndian) { + uint64_t Lo, Hi; + + if (Bytes.size() < 8) { + Size = 0; + return MCDisassembler::Fail; + } + + Size = 8; + if (IsLittleEndian) { + Hi = + (Bytes[0] << 24) | (Bytes[1] << 16) | (Bytes[2] << 0) | (Bytes[3] << 8); + Lo = + (Bytes[4] << 0) | (Bytes[5] << 8) | (Bytes[6] << 16) | (Bytes[7] << 24); + } else { + Hi = (Bytes[0] << 24) | ((Bytes[1] & 0x0F) << 20) | + ((Bytes[1] & 0xF0) << 12) | (Bytes[2] << 8) | (Bytes[3] << 0); + Lo = + (Bytes[4] << 24) | (Bytes[5] << 16) | (Bytes[6] << 8) | (Bytes[7] << 0); + } + Insn = Make_64(Hi, Lo); + + return MCDisassembler::Success; +} + +bool SBFDisassembler::isNewMem(uint64_t Inst) const { + uint8_t OpCode = Inst >> 56; + + uint8_t LSB = OpCode & 0xf; + if (LSB != 0x7 && LSB != 0xc && LSB != 0xf) + return false; + + uint8_t MSB = OpCode >> 4; + + return MSB == 0x2 || MSB == 0x3 || MSB == 0x8 || MSB == 0x9; +} + +bool SBFDisassembler::isAlu32NewLoadStoreReg(uint64_t Inst) const { + bool IsNotDw = (Inst >> 60) != 0x9; + bool IsNotStoreImm = (Inst >> 56 & 0xf) != 0x7; + return isNewMem(Inst) && IsNotDw && IsNotStoreImm && + STI.hasFeature(SBF::FeatureNewMemEncoding) && + STI.hasFeature(SBF::ALU32); +} + +DecodeStatus SBFDisassembler::getInstruction(MCInst &Instr, uint64_t &Size, + ArrayRef Bytes, + uint64_t Address, + raw_ostream &CStream) const { + bool IsLittleEndian = getContext().getAsmInfo()->isLittleEndian(); + uint64_t Insn, Hi; + DecodeStatus Result; + + Result = readInstruction64(Bytes, Address, Size, Insn, IsLittleEndian); + if (Result == MCDisassembler::Fail) + return MCDisassembler::Fail; + + uint8_t InstClass = getInstClass(Insn); + uint8_t InstMode = getInstMode(Insn); + + if ((InstClass == SBF_LDX || InstClass == SBF_STX) && + getInstSize(Insn) != SBF_DW && + (InstMode == SBF_MEM || InstMode == SBF_ATOMIC) && + STI.hasFeature(SBF::ALU32)) + Result = decodeInstruction(DecoderTableSBFALU3264, Instr, Insn, Address, + this, STI); + else if (isMov32(Insn) && !STI.hasFeature(SBF::ALU32) && + STI.hasFeature(SBF::FeatureDisableLddw)) + Result = + decodeInstruction(DecoderTableSBFv264, Instr, Insn, Address, this, STI); + else if (isAlu32NewLoadStoreReg(Insn)) { + Result = + decodeInstruction(DecoderTableSBFALU32MEMv264, + Instr, Insn, Address, this, STI); + } + else if ((isNewMem(Insn) && STI.hasFeature(SBF::FeatureNewMemEncoding)) || + (isSyscallOrExit(Insn) && STI.hasFeature(SBF::FeatureStaticSyscalls))) { + Result = + decodeInstruction(DecoderTableSBFv264, + Instr, Insn, Address, this, STI); + } + else + Result = + decodeInstruction(DecoderTableSBF64, Instr, Insn, Address, this, STI); + + if (Result == MCDisassembler::Fail) + return MCDisassembler::Fail; + + switch (Instr.getOpcode()) { + case SBF::LD_imm64: + case SBF::LD_pseudo: { + if (Bytes.size() < 16) { + Size = 0; + return MCDisassembler::Fail; + } + Size = 16; + if (IsLittleEndian) + Hi = (Bytes[12] << 0) | (Bytes[13] << 8) | (Bytes[14] << 16) | + (Bytes[15] << 24); + else + Hi = (Bytes[12] << 24) | (Bytes[13] << 16) | (Bytes[14] << 8) | + (Bytes[15] << 0); + auto &Op = Instr.getOperand(1); + Op.setImm(Make_64(Hi, Op.getImm())); + break; + } + case SBF::JALX: { + if (STI.hasFeature(SBF::FeatureCallxRegSrc)) { + Result = decodeInstruction(DecoderTableSBFv264, Instr, Insn, Address, + this, STI); + } + } + } + + return Result; +} + +typedef DecodeStatus (*DecodeFunc)(MCInst &MI, unsigned insn, uint64_t Address, + const MCDisassembler *Decoder); diff --git a/llvm/lib/Target/SBF/GISel/SBFCallLowering.cpp b/llvm/lib/Target/SBF/GISel/SBFCallLowering.cpp new file mode 100644 index 0000000000000..fd893f5f4160a --- /dev/null +++ b/llvm/lib/Target/SBF/GISel/SBFCallLowering.cpp @@ -0,0 +1,46 @@ +//===-- BPFCallLowering.cpp - Call lowering for GlobalISel ------*- 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 +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// This file implements the lowering of LLVM calls to machine code calls for +/// GlobalISel. +/// +//===----------------------------------------------------------------------===// + +#include "SBFCallLowering.h" +#include "llvm/CodeGen/GlobalISel/MachineIRBuilder.h" +#include "llvm/Support/Debug.h" + +#define DEBUG_TYPE "sbf-call-lowering" + +using namespace llvm; + +SBFCallLowering::SBFCallLowering(const SBFTargetLowering &TLI) + : CallLowering(&TLI) {} + +bool SBFCallLowering::lowerReturn(MachineIRBuilder &MIRBuilder, + const Value *Val, ArrayRef VRegs, + FunctionLoweringInfo &FLI, + Register SwiftErrorVReg) const { + if (!VRegs.empty()) + return false; + MIRBuilder.buildInstr(SBF::RETURN_v3); + return true; +} + +bool SBFCallLowering::lowerFormalArguments(MachineIRBuilder &MIRBuilder, + const Function &F, + ArrayRef> VRegs, + FunctionLoweringInfo &FLI) const { + return VRegs.empty(); +} + +bool SBFCallLowering::lowerCall(MachineIRBuilder &MIRBuilder, + CallLoweringInfo &Info) const { + return false; +} diff --git a/llvm/lib/Target/SBF/GISel/SBFCallLowering.h b/llvm/lib/Target/SBF/GISel/SBFCallLowering.h new file mode 100644 index 0000000000000..4440ad498c202 --- /dev/null +++ b/llvm/lib/Target/SBF/GISel/SBFCallLowering.h @@ -0,0 +1,39 @@ +//===-- SBFCallLowering.h - Call lowering for GlobalISel --------*- 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 +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// This file describes how to lower LLVM calls to machine code calls. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIB_TARGET_SBF_GISEL_SBFCALLLOWERING_H +#define LLVM_LIB_TARGET_SBF_GISEL_SBFCALLLOWERING_H + +#include "SBFISelLowering.h" +#include "llvm/CodeGen/GlobalISel/CallLowering.h" +#include "llvm/IR/CallingConv.h" + +namespace llvm { + +class SBFTargetLowering; + +class SBFCallLowering : public CallLowering { +public: + SBFCallLowering(const SBFTargetLowering &TLI); + bool lowerReturn(MachineIRBuilder &MIRBuilder, const Value *Val, + ArrayRef VRegs, FunctionLoweringInfo &FLI, + Register SwiftErrorVReg) const override; + bool lowerFormalArguments(MachineIRBuilder &MIRBuilder, const Function &F, + ArrayRef> VRegs, + FunctionLoweringInfo &FLI) const override; + bool lowerCall(MachineIRBuilder &MIRBuilder, + CallLoweringInfo &Info) const override; +}; +} // namespace llvm + +#endif diff --git a/llvm/lib/Target/SBF/GISel/SBFInstructionSelector.cpp b/llvm/lib/Target/SBF/GISel/SBFInstructionSelector.cpp new file mode 100644 index 0000000000000..277601c902de5 --- /dev/null +++ b/llvm/lib/Target/SBF/GISel/SBFInstructionSelector.cpp @@ -0,0 +1,93 @@ +//===- BPFInstructionSelector.cpp --------------------------------*- 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 +// +//===----------------------------------------------------------------------===// +/// \file +/// This file implements the targeting of the InstructionSelector class for BPF. +//===----------------------------------------------------------------------===// + +#include "SBFInstrInfo.h" +#include "SBFSubtarget.h" +#include "SBFTargetMachine.h" +#include "SBFRegisterBankInfo.h" +#include "llvm/CodeGen/GlobalISel/GIMatchTableExecutorImpl.h" +#include "llvm/CodeGen/GlobalISel/InstructionSelector.h" +#include "llvm/CodeGen/GlobalISel/MachineIRBuilder.h" +#include "llvm/CodeGen/MachineFunction.h" +#include "llvm/IR/IntrinsicsBPF.h" +#include "llvm/Support/Debug.h" + +#define DEBUG_TYPE "SBF-gisel" + +using namespace llvm; + +namespace { + +#define GET_GLOBALISEL_PREDICATE_BITSET +#include "SBFGenGlobalISel.inc" +#undef GET_GLOBALISEL_PREDICATE_BITSET + +class SBFInstructionSelector : public InstructionSelector { +public: + SBFInstructionSelector(const SBFTargetMachine &TM, const SBFSubtarget &STI, + const SBFRegisterBankInfo &RBI); + + bool select(MachineInstr &I) override; + static const char *getName() { return DEBUG_TYPE; } + +private: + /// tblgen generated 'select' implementation that is used as the initial + /// selector for the patterns that do not require complex C++. + bool selectImpl(MachineInstr &I, CodeGenCoverage &CoverageInfo) const; + + const SBFInstrInfo &TII; + const SBFRegisterInfo &TRI; + const SBFRegisterBankInfo &RBI; + +#define GET_GLOBALISEL_PREDICATES_DECL +#include "SBFGenGlobalISel.inc" +#undef GET_GLOBALISEL_PREDICATES_DECL + +#define GET_GLOBALISEL_TEMPORARIES_DECL +#include "SBFGenGlobalISel.inc" +#undef GET_GLOBALISEL_TEMPORARIES_DECL +}; + +} // namespace + +#define GET_GLOBALISEL_IMPL +#include "SBFGenGlobalISel.inc" +#undef GET_GLOBALISEL_IMPL + +SBFInstructionSelector::SBFInstructionSelector(const SBFTargetMachine &TM, + const SBFSubtarget &STI, + const SBFRegisterBankInfo &RBI) + : TII(*STI.getInstrInfo()), TRI(*STI.getRegisterInfo()), RBI(RBI), +#define GET_GLOBALISEL_PREDICATES_INIT +#include "SBFGenGlobalISel.inc" +#undef GET_GLOBALISEL_PREDICATES_INIT +#define GET_GLOBALISEL_TEMPORARIES_INIT +#include "SBFGenGlobalISel.inc" +#undef GET_GLOBALISEL_TEMPORARIES_INIT +{ +} + +bool SBFInstructionSelector::select(MachineInstr &I) { + if (!isPreISelGenericOpcode(I.getOpcode())) + return true; + if (selectImpl(I, *CoverageInfo)) + return true; + return false; +} + +namespace llvm { +InstructionSelector * +createSBFInstructionSelector(const SBFTargetMachine &TM, + const SBFSubtarget &Subtarget, + const SBFRegisterBankInfo &RBI) { + return new SBFInstructionSelector(TM, Subtarget, RBI); +} +} // namespace llvm diff --git a/llvm/lib/Target/SBF/GISel/SBFLegalizerInfo.cpp b/llvm/lib/Target/SBF/GISel/SBFLegalizerInfo.cpp new file mode 100644 index 0000000000000..8eec29a387461 --- /dev/null +++ b/llvm/lib/Target/SBF/GISel/SBFLegalizerInfo.cpp @@ -0,0 +1,22 @@ +//===- SBFLegalizerInfo.h ----------------------------------------*- 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 +// +//===----------------------------------------------------------------------===// +/// \file +/// This file implements the targeting of the Machinelegalizer class for SBF +//===----------------------------------------------------------------------===// + +#include "SBFLegalizerInfo.h" +#include "llvm/Support/Debug.h" + +#define DEBUG_TYPE "SBF-legalinfo" + +using namespace llvm; +using namespace LegalizeActions; + +SBFLegalizerInfo::SBFLegalizerInfo(const SBFSubtarget &ST) { + getLegacyLegalizerInfo().computeTables(); +} diff --git a/llvm/lib/Target/SBF/GISel/SBFLegalizerInfo.h b/llvm/lib/Target/SBF/GISel/SBFLegalizerInfo.h new file mode 100644 index 0000000000000..fe1e91f68418c --- /dev/null +++ b/llvm/lib/Target/SBF/GISel/SBFLegalizerInfo.h @@ -0,0 +1,28 @@ +//===- SBFLegalizerInfo.h ----------------------------------------*- 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 +// +//===----------------------------------------------------------------------===// +/// \file +/// This file declares the targeting of the Machinelegalizer class for SBF +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIB_TARGET_SBF_GISEL_SBFMACHINELEGALIZER_H +#define LLVM_LIB_TARGET_SBF_GISEL_SBFMACHINELEGALIZER_H + +#include "llvm/CodeGen/GlobalISel/LegalizerInfo.h" + +namespace llvm { + +class SBFSubtarget; + +/// This class provides the information for the SBF target legalizer for +/// GlobalISel. +class SBFLegalizerInfo : public LegalizerInfo { +public: + SBFLegalizerInfo(const SBFSubtarget &ST); +}; +} // namespace llvm +#endif diff --git a/llvm/lib/Target/SBF/GISel/SBFRegisterBankInfo.cpp b/llvm/lib/Target/SBF/GISel/SBFRegisterBankInfo.cpp new file mode 100644 index 0000000000000..ca29efe58c5ff --- /dev/null +++ b/llvm/lib/Target/SBF/GISel/SBFRegisterBankInfo.cpp @@ -0,0 +1,25 @@ +//===- SBFRegisterBankInfo.cpp --------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// +/// \file +/// This file implements the targeting of the RegisterBankInfo class for SBF +//===----------------------------------------------------------------------===// + +#include "SBFRegisterBankInfo.h" +#include "llvm/CodeGen/MachineFunction.h" +#include "llvm/CodeGen/MachineRegisterInfo.h" +#include "llvm/Support/Debug.h" + +#define DEBUG_TYPE "SBF-reg-bank-info" + +#define GET_TARGET_REGBANK_IMPL +#include "SBFGenRegisterBank.inc" + +using namespace llvm; + +SBFRegisterBankInfo::SBFRegisterBankInfo(const TargetRegisterInfo &TRI) + : SBFGenRegisterBankInfo() {} diff --git a/llvm/lib/Target/SBF/GISel/SBFRegisterBankInfo.h b/llvm/lib/Target/SBF/GISel/SBFRegisterBankInfo.h new file mode 100644 index 0000000000000..3fe0becbf23f1 --- /dev/null +++ b/llvm/lib/Target/SBF/GISel/SBFRegisterBankInfo.h @@ -0,0 +1,39 @@ +//===-- SBFRegisterBankInfo.h -----------------------------------*- 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 +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// This file declares the targeting of the RegisterBankInfo class for SBF. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIB_TARGET_SBF_GISEL_SBFREGISTERBANKINFO_H +#define LLVM_LIB_TARGET_SBF_GISEL_SBFREGISTERBANKINFO_H + +#include "MCTargetDesc/SBFMCTargetDesc.h" +#include "llvm/CodeGen/RegisterBankInfo.h" +#include "llvm/CodeGen/TargetRegisterInfo.h" + +#define GET_REGBANK_DECLARATIONS +#include "SBFGenRegisterBank.inc" + +namespace llvm { +class TargetRegisterInfo; + +class SBFGenRegisterBankInfo : public RegisterBankInfo { +protected: +#define GET_TARGET_REGBANK_CLASS +#include "SBFGenRegisterBank.inc" +}; + +class SBFRegisterBankInfo final : public SBFGenRegisterBankInfo { +public: + SBFRegisterBankInfo(const TargetRegisterInfo &TRI); +}; +} // namespace llvm + +#endif diff --git a/llvm/lib/Target/SBF/GISel/SBFRegisterBanks.td b/llvm/lib/Target/SBF/GISel/SBFRegisterBanks.td new file mode 100644 index 0000000000000..037d4b5218076 --- /dev/null +++ b/llvm/lib/Target/SBF/GISel/SBFRegisterBanks.td @@ -0,0 +1,15 @@ +//===-- SBFRegisterBanks.td - Describe the SBF Banks -------*- tablegen -*-===// +// +// 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 +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// Define the SBF register banks used for GlobalISel. +/// +//===----------------------------------------------------------------------===// + +/// General Purpose Registers +def GPRRegBank : RegisterBank<"GPRB", [GPR]>; diff --git a/llvm/lib/Target/SBF/MCTargetDesc/CMakeLists.txt b/llvm/lib/Target/SBF/MCTargetDesc/CMakeLists.txt new file mode 100644 index 0000000000000..478bde55bd85b --- /dev/null +++ b/llvm/lib/Target/SBF/MCTargetDesc/CMakeLists.txt @@ -0,0 +1,17 @@ +add_llvm_component_library(LLVMSBFDesc + SBFMCTargetDesc.cpp + SBFAsmBackend.cpp + SBFInstPrinter.cpp + SBFMCAsmInfo.cpp + SBFMCCodeEmitter.cpp + SBFELFObjectWriter.cpp + + LINK_COMPONENTS + MC + SBFInfo + Support + TargetParser + + ADD_TO_COMPONENT + SBF + ) diff --git a/llvm/lib/Target/SBF/MCTargetDesc/SBFAsmBackend.cpp b/llvm/lib/Target/SBF/MCTargetDesc/SBFAsmBackend.cpp new file mode 100644 index 0000000000000..b13621623b99f --- /dev/null +++ b/llvm/lib/Target/SBF/MCTargetDesc/SBFAsmBackend.cpp @@ -0,0 +1,122 @@ +//===-- SBFAsmBackend.cpp - SBF Assembler Backend -------------------------===// +// +// 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 "MCTargetDesc/SBFMCTargetDesc.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/MC/MCAsmBackend.h" +#include "llvm/MC/MCAssembler.h" +#include "llvm/MC/MCContext.h" +#include "llvm/MC/MCFixup.h" +#include "llvm/MC/MCObjectWriter.h" +#include "llvm/MC/MCSubtargetInfo.h" +#include "llvm/Support/EndianStream.h" +#include +#include + +using namespace llvm; + +namespace { + +class SBFAsmBackend : public MCAsmBackend { +public: + SBFAsmBackend(endianness Endian, const MCSubtargetInfo &STI) + : MCAsmBackend(Endian), + relocAbs64(STI.hasFeature(SBF::FeatureRelocAbs64)) {} + ~SBFAsmBackend() override = default; + + void applyFixup(const MCAssembler &Asm, const MCFixup &Fixup, + const MCValue &Target, MutableArrayRef Data, + uint64_t Value, bool IsResolved, + const MCSubtargetInfo *STI) const override; + + std::unique_ptr + createObjectTargetWriter() const override; + + // No instruction requires relaxation + bool fixupNeedsRelaxation(const MCFixup &Fixup, uint64_t Value) + const override { + return false; + } + + unsigned getNumFixupKinds() const override { return 1; } + + bool writeNopData(raw_ostream &OS, uint64_t Count, + const MCSubtargetInfo *STI) const override; +private: + bool relocAbs64; +}; + +} // end anonymous namespace + +bool SBFAsmBackend::writeNopData(raw_ostream &OS, uint64_t Count, + const MCSubtargetInfo *STI) const { + if ((Count % 8) != 0) + return false; + + for (uint64_t i = 0; i < Count; i += 8) + support::endian::write(OS, 0x15000000, Endian); + + return true; +} + +void SBFAsmBackend::applyFixup(const MCAssembler &Asm, const MCFixup &Fixup, + const MCValue &Target, + MutableArrayRef Data, uint64_t Value, + bool IsResolved, + const MCSubtargetInfo *STI) const { + if (Fixup.getKind() == FK_SecRel_8) { + // The Value is 0 for global variables, and the in-section offset + // for static variables. Write to the immediate field of the inst. + assert(Value <= UINT32_MAX); + support::endian::write(&Data[Fixup.getOffset() + 4], + static_cast(Value), + Endian); + } else if (Fixup.getKind() == FK_Data_4) { + support::endian::write(&Data[Fixup.getOffset()], Value, Endian); + } else if (Fixup.getKind() == FK_Data_8) { + support::endian::write(&Data[Fixup.getOffset()], Value, Endian); + } else if (Fixup.getKind() == FK_PCRel_4) { + Value = (uint32_t)((Value - 8) / 8); + if (Endian == endianness::little) { + Data[Fixup.getOffset() + 1] = 0x10; + support::endian::write32le(&Data[Fixup.getOffset() + 4], Value); + } else { + Data[Fixup.getOffset() + 1] = 0x1; + support::endian::write32be(&Data[Fixup.getOffset() + 4], Value); + } + } else { + assert(Fixup.getKind() == FK_PCRel_2); + + int64_t ByteOff = (int64_t)Value - 8; + if (ByteOff > INT16_MAX * 8 || ByteOff < INT16_MIN * 8) + report_fatal_error("Branch target out of insn range"); + + Value = (uint16_t)((Value - 8) / 8); + support::endian::write(&Data[Fixup.getOffset() + 2], Value, + Endian); + } +} + +std::unique_ptr +SBFAsmBackend::createObjectTargetWriter() const { + return createSBFELFObjectWriter(0, relocAbs64); +} + +MCAsmBackend *llvm::createSBFAsmBackend(const Target &T, + const MCSubtargetInfo &STI, + const MCRegisterInfo &MRI, + const MCTargetOptions &) { + return new SBFAsmBackend(endianness::little, STI); +} + +MCAsmBackend *llvm::createSBFbeAsmBackend(const Target &T, + const MCSubtargetInfo &STI, + const MCRegisterInfo &MRI, + const MCTargetOptions &) { + return new SBFAsmBackend(endianness::big, STI); +} diff --git a/llvm/lib/Target/SBF/MCTargetDesc/SBFELFObjectWriter.cpp b/llvm/lib/Target/SBF/MCTargetDesc/SBFELFObjectWriter.cpp new file mode 100644 index 0000000000000..15c1ae681402d --- /dev/null +++ b/llvm/lib/Target/SBF/MCTargetDesc/SBFELFObjectWriter.cpp @@ -0,0 +1,113 @@ +//===-- SBFELFObjectWriter.cpp - SBF ELF Writer ---------------------------===// +// +// 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 "MCTargetDesc/SBFMCTargetDesc.h" +#include "llvm/BinaryFormat/ELF.h" +#include "llvm/MC/MCContext.h" +#include "llvm/MC/MCELFObjectWriter.h" +#include "llvm/MC/MCFixup.h" +#include "llvm/MC/MCObjectWriter.h" +#include "llvm/MC/MCValue.h" +#include "llvm/Support/ErrorHandling.h" +#include + +using namespace llvm; + +namespace { + +class SBFELFObjectWriter : public MCELFObjectTargetWriter { +public: + SBFELFObjectWriter(uint8_t OSABI, bool relocAbs64); + ~SBFELFObjectWriter() override = default; + +protected: + unsigned getRelocType(MCContext &Ctx, const MCValue &Target, + const MCFixup &Fixup, bool IsPCRel) const override; + + bool needsRelocateWithSymbol(const MCValue &Val, const MCSymbol &Sym, + unsigned Type) const override; +private: + bool relocAbs64; +}; + +} // end anonymous namespace + +// Avoid section relocations because the SBF backend can only handle +// section relocations with values (offset into the section containing +// the symbol being relocated). Forcing a relocation with a symbol +// will result in the symbol's index being used in the .o file instead. +bool SBFELFObjectWriter::needsRelocateWithSymbol(const MCValue &Val, + const MCSymbol &Sym, + unsigned Type) const { + return true; +} + +SBFELFObjectWriter::SBFELFObjectWriter(uint8_t OSABI, bool relocAbs64) + : MCELFObjectTargetWriter(/*Is64Bit*/ true, OSABI,ELF::EM_SBF, + /*HasRelocationAddend*/ false), + relocAbs64(relocAbs64) {} + +unsigned SBFELFObjectWriter::getRelocType(MCContext &Ctx, const MCValue &Target, + const MCFixup &Fixup, + bool IsPCRel) const { + // determine the type of the relocation + switch (Fixup.getKind()) { + default: + llvm_unreachable("invalid fixup kind!"); + case FK_SecRel_8: + // LD_imm64 instruction. + return ELF::R_SBF_64_64; + case FK_PCRel_4: + // CALL instruction. + return ELF::R_SBF_64_32; + case FK_PCRel_2: + // Branch instruction. + Ctx.reportError(Fixup.getLoc(), "2-byte relocations not supported"); + return ELF::R_SBF_NONE; + case FK_Data_8: + return relocAbs64 ? ELF::R_SBF_64_ABS64 : ELF::R_SBF_64_64; + case FK_Data_4: + if (const MCSymbolRefExpr *A = Target.getSymA()) { + const MCSymbol &Sym = A->getSymbol(); + + if (Sym.isDefined()) { + MCSection &Section = Sym.getSection(); + const MCSectionELF *SectionELF = dyn_cast(&Section); + assert(SectionELF && "Null section for reloc symbol"); + + unsigned Flags = SectionELF->getFlags(); + + if (Sym.isTemporary()) { + // .BTF.ext generates FK_Data_4 relocations for + // insn offset by creating temporary labels. + // The reloc symbol should be in text section. + // Use a different relocation to instruct ExecutionEngine + // RuntimeDyld not to do relocation for it, yet still to + // allow lld to do proper adjustment when merging sections. + if ((Flags & ELF::SHF_ALLOC) && (Flags & ELF::SHF_EXECINSTR)) + return ELF::R_SBF_64_NODYLD32; + } else { + // .BTF generates FK_Data_4 relocations for variable + // offset in DataSec kind. + // The reloc symbol should be in data section. + if ((Flags & ELF::SHF_ALLOC) && (Flags & ELF::SHF_WRITE)) + return ELF::R_SBF_64_NODYLD32; + } + // .debug_* sections + if (!(Flags & ELF::SHF_ALLOC)) + return ELF::R_SBF_64_ABS32; + } + } + return ELF::R_SBF_64_32; + } +} + +std::unique_ptr +llvm::createSBFELFObjectWriter(uint8_t OSABI, bool useRelocAbs64) { + return std::make_unique(OSABI, useRelocAbs64); +} diff --git a/llvm/lib/Target/SBF/MCTargetDesc/SBFInstPrinter.cpp b/llvm/lib/Target/SBF/MCTargetDesc/SBFInstPrinter.cpp new file mode 100644 index 0000000000000..d3d9ec4cd55fc --- /dev/null +++ b/llvm/lib/Target/SBF/MCTargetDesc/SBFInstPrinter.cpp @@ -0,0 +1,110 @@ +//===-- SBFInstPrinter.cpp - Convert SBF MCInst to asm syntax -------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// +// +// This class prints an SBF MCInst to a .s file. +// +//===----------------------------------------------------------------------===// + +#include "MCTargetDesc/SBFInstPrinter.h" +#include "llvm/MC/MCAsmInfo.h" +#include "llvm/MC/MCExpr.h" +#include "llvm/MC/MCInst.h" +#include "llvm/MC/MCRegister.h" +#include "llvm/MC/MCSymbol.h" +#include "llvm/Support/Casting.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/FormattedStream.h" +using namespace llvm; + +#define DEBUG_TYPE "asm-printer" + +// Include the auto-generated portion of the assembly writer. +#include "SBFGenAsmWriter.inc" + +void SBFInstPrinter::printInst(const MCInst *MI, uint64_t Address, + StringRef Annot, const MCSubtargetInfo &STI, + raw_ostream &O) { + printInstruction(MI, Address, O); + printAnnotation(O, Annot); +} + +static void printExpr(const MCExpr *Expr, raw_ostream &O) { +#ifndef NDEBUG + const MCSymbolRefExpr *SRE; + + if (const MCBinaryExpr *BE = dyn_cast(Expr)) + SRE = dyn_cast(BE->getLHS()); + else + SRE = dyn_cast(Expr); + assert(SRE && "Unexpected MCExpr type."); + + MCSymbolRefExpr::VariantKind Kind = SRE->getKind(); + + assert(Kind == MCSymbolRefExpr::VK_None); +#endif + O << *Expr; +} + +void SBFInstPrinter::printOperand(const MCInst *MI, unsigned OpNo, + raw_ostream &O, const char *Modifier) { + assert((Modifier == nullptr || Modifier[0] == 0) && "No modifiers supported"); + const MCOperand &Op = MI->getOperand(OpNo); + if (Op.isReg()) { + O << getRegisterName(Op.getReg()); + } else if (Op.isImm()) { + O << formatImm((int32_t)Op.getImm()); + } else { + assert(Op.isExpr() && "Expected an expression"); + printExpr(Op.getExpr(), O); + } +} + +void SBFInstPrinter::printMemOperand(const MCInst *MI, int OpNo, raw_ostream &O, + const char *Modifier) { + const MCOperand &RegOp = MI->getOperand(OpNo); + const MCOperand &OffsetOp = MI->getOperand(OpNo + 1); + + // register + assert(RegOp.isReg() && "Register operand not a register"); + O << getRegisterName(RegOp.getReg()); + + // offset + if (OffsetOp.isImm()) { + auto Imm = OffsetOp.getImm(); + if (Imm >= 0) + O << " + " << formatImm(Imm); + else + O << " - " << formatImm(-Imm); + } else { + assert(0 && "Expected an immediate"); + } +} + +void SBFInstPrinter::printImm64Operand(const MCInst *MI, unsigned OpNo, + raw_ostream &O) { + const MCOperand &Op = MI->getOperand(OpNo); + if (Op.isImm()) + O << formatImm(Op.getImm()); + else if (Op.isExpr()) + printExpr(Op.getExpr(), O); + else + O << Op; +} + +void SBFInstPrinter::printBrTargetOperand(const MCInst *MI, unsigned OpNo, + raw_ostream &O) { + const MCOperand &Op = MI->getOperand(OpNo); + if (Op.isImm()) { + int16_t Imm = Op.getImm(); + O << ((Imm >= 0) ? "+" : "") << formatImm(Imm); + } else if (Op.isExpr()) { + printExpr(Op.getExpr(), O); + } else { + O << Op; + } +} diff --git a/llvm/lib/Target/SBF/MCTargetDesc/SBFInstPrinter.h b/llvm/lib/Target/SBF/MCTargetDesc/SBFInstPrinter.h new file mode 100644 index 0000000000000..1dc53c59c3310 --- /dev/null +++ b/llvm/lib/Target/SBF/MCTargetDesc/SBFInstPrinter.h @@ -0,0 +1,42 @@ +//===-- SBFInstPrinter.h - Convert SBF MCInst to asm syntax -------*- 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 +// +//===----------------------------------------------------------------------===// +// +// This class prints a SBF MCInst to a .s file. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIB_TARGET_SBF_MCTARGETDESC_SBFINSTPRINTER_H +#define LLVM_LIB_TARGET_SBF_MCTARGETDESC_SBFINSTPRINTER_H + +#include "llvm/MC/MCInstPrinter.h" + +namespace llvm { +class SBFInstPrinter : public MCInstPrinter { +public: + SBFInstPrinter(const MCAsmInfo &MAI, const MCInstrInfo &MII, + const MCRegisterInfo &MRI) + : MCInstPrinter(MAI, MII, MRI) {} + + void printInst(const MCInst *MI, uint64_t Address, StringRef Annot, + const MCSubtargetInfo &STI, raw_ostream &O) override; + void printOperand(const MCInst *MI, unsigned OpNo, raw_ostream &O, + const char *Modifier = nullptr); + void printMemOperand(const MCInst *MI, int OpNo, raw_ostream &O, + const char *Modifier = nullptr); + void printImm64Operand(const MCInst *MI, unsigned OpNo, raw_ostream &O); + void printBrTargetOperand(const MCInst *MI, unsigned OpNo, raw_ostream &O); + + // Autogenerated by tblgen. + std::pair + getMnemonic(const MCInst &MI) const override; + void printInstruction(const MCInst *MI, uint64_t Address, raw_ostream &O); + static const char *getRegisterName(MCRegister Reg); +}; +} + +#endif diff --git a/llvm/lib/Target/SBF/MCTargetDesc/SBFMCAsmInfo.cpp b/llvm/lib/Target/SBF/MCTargetDesc/SBFMCAsmInfo.cpp new file mode 100644 index 0000000000000..5bf43703ef46d --- /dev/null +++ b/llvm/lib/Target/SBF/MCTargetDesc/SBFMCAsmInfo.cpp @@ -0,0 +1,40 @@ +//===-- SBFMCAsmInfo.cpp - SBF Asm properties -----------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// +// +// This file contains the declarations of the SBFMCAsmInfo properties. +// +//===----------------------------------------------------------------------===// + +#include "SBFMCAsmInfo.h" +#include "llvm/BinaryFormat/Dwarf.h" +#include "llvm/MC/MCStreamer.h" +#include "llvm/Support/CommandLine.h" + +using namespace llvm; + +SBFMCAsmInfo::SBFMCAsmInfo(const Triple &TT, const MCTargetOptions &Options) { + assert(AssemblerDialect == 0); + + PrivateGlobalPrefix = ".L"; + WeakRefDirective = "\t.weak\t"; + + UsesELFSectionDirectiveForBSS = true; + HasSingleParameterDotFile = true; + HasDotTypeDotSizeDirective = true; + + SupportsDebugInformation = true; + ExceptionsType = ExceptionHandling::DwarfCFI; + MinInstAlignment = 8; + + // The default is 4 and it only affects dwarf elf output. + // If not set correctly, the dwarf data will be + // messed up in random places by 4 bytes. .debug_line + // section will be parsable, but with odd offsets and + // line numbers, etc. + CodePointerSize = 8; +} diff --git a/llvm/lib/Target/SBF/MCTargetDesc/SBFMCAsmInfo.h b/llvm/lib/Target/SBF/MCTargetDesc/SBFMCAsmInfo.h new file mode 100644 index 0000000000000..4b114c44f7565 --- /dev/null +++ b/llvm/lib/Target/SBF/MCTargetDesc/SBFMCAsmInfo.h @@ -0,0 +1,36 @@ +//===-- SBFMCAsmInfo.h - SBF asm properties -------------------*- 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 +// +//===----------------------------------------------------------------------===// +// +// This file contains the declaration of the SBFMCAsmInfo class. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIB_TARGET_SBF_MCTARGETDESC_SBFMCASMINFO_H +#define LLVM_LIB_TARGET_SBF_MCTARGETDESC_SBFMCASMINFO_H + +#include "llvm/MC/MCAsmInfo.h" +#include "llvm/TargetParser/Triple.h" + +namespace llvm { + +// TODO: This should likely be subclassing MCAsmInfoELF. +class SBFMCAsmInfo : public MCAsmInfo { +public: + explicit SBFMCAsmInfo(const Triple &TT, const MCTargetOptions &Options); + + void setDwarfUsesRelocationsAcrossSections(bool enable) { + DwarfUsesRelocationsAcrossSections = enable; + } + + void setSupportsDebugInformation(bool enable) { + SupportsDebugInformation = enable; + } +}; + +} +#endif diff --git a/llvm/lib/Target/SBF/MCTargetDesc/SBFMCCodeEmitter.cpp b/llvm/lib/Target/SBF/MCTargetDesc/SBFMCCodeEmitter.cpp new file mode 100644 index 0000000000000..d790b9877c1b7 --- /dev/null +++ b/llvm/lib/Target/SBF/MCTargetDesc/SBFMCCodeEmitter.cpp @@ -0,0 +1,173 @@ +//===-- SBFMCCodeEmitter.cpp - Convert SBF code to machine code -----------===// +// +// 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 +// +//===----------------------------------------------------------------------===// +// +// This file implements the SBFMCCodeEmitter class. +// +//===----------------------------------------------------------------------===// + +#include "MCTargetDesc/SBFMCTargetDesc.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/MC/MCCodeEmitter.h" +#include "llvm/MC/MCExpr.h" +#include "llvm/MC/MCFixup.h" +#include "llvm/MC/MCInst.h" +#include "llvm/MC/MCInstrInfo.h" +#include "llvm/MC/MCRegisterInfo.h" +#include "llvm/MC/MCSubtargetInfo.h" +#include "llvm/Support/Endian.h" +#include "llvm/Support/EndianStream.h" +#include +#include + +using namespace llvm; + +#define DEBUG_TYPE "mccodeemitter" + +namespace { + +class SBFMCCodeEmitter : public MCCodeEmitter { + const MCRegisterInfo &MRI; + bool IsLittleEndian; + +public: + SBFMCCodeEmitter(const MCInstrInfo &, const MCRegisterInfo &mri, + bool IsLittleEndian) + : MRI(mri), IsLittleEndian(IsLittleEndian) {} + SBFMCCodeEmitter(const SBFMCCodeEmitter &) = delete; + void operator=(const SBFMCCodeEmitter &) = delete; + ~SBFMCCodeEmitter() override = default; + + // getBinaryCodeForInstr - TableGen'erated function for getting the + // binary encoding for an instruction. + uint64_t getBinaryCodeForInstr(const MCInst &MI, + SmallVectorImpl &Fixups, + const MCSubtargetInfo &STI) const; + + // getMachineOpValue - Return binary encoding of operand. If the machin + // operand requires relocation, record the relocation and return zero. + unsigned getMachineOpValue(const MCInst &MI, const MCOperand &MO, + SmallVectorImpl &Fixups, + const MCSubtargetInfo &STI) const; + + uint64_t getMemoryOpValue(const MCInst &MI, unsigned Op, + SmallVectorImpl &Fixups, + const MCSubtargetInfo &STI) const; + + void encodeInstruction(const MCInst &MI, SmallVectorImpl &CB, + SmallVectorImpl &Fixups, + const MCSubtargetInfo &STI) const override; +}; + +} // end anonymous namespace + +MCCodeEmitter *llvm::createSBFMCCodeEmitter(const MCInstrInfo &MCII, + MCContext &Ctx) { + return new SBFMCCodeEmitter(MCII, *Ctx.getRegisterInfo(), true); +} + +MCCodeEmitter *llvm::createSBFbeMCCodeEmitter(const MCInstrInfo &MCII, + MCContext &Ctx) { + return new SBFMCCodeEmitter(MCII, *Ctx.getRegisterInfo(), false); +} + +unsigned SBFMCCodeEmitter::getMachineOpValue(const MCInst &MI, + const MCOperand &MO, + SmallVectorImpl &Fixups, + const MCSubtargetInfo &STI) const { + if (MO.isReg()) + return MRI.getEncodingValue(MO.getReg()); + if (MO.isImm()) + return static_cast(MO.getImm()); + + assert(MO.isExpr()); + + const MCExpr *Expr = MO.getExpr(); + + assert(Expr->getKind() == MCExpr::SymbolRef); + + if (MI.getOpcode() == SBF::JAL) + // func call name + Fixups.push_back(MCFixup::create(0, Expr, FK_PCRel_4)); + else if (MI.getOpcode() == SBF::LD_imm64 || + MI.getOpcode() == SBF::MOV_32_64_addr) + Fixups.push_back(MCFixup::create(0, Expr, FK_SecRel_8)); + // In SBFv2, LD_imm64 is replaced by MOV_32_64_addr and HOR_addr when loading + // addresses. These two instructions always appear together, so if a + // relocation is necessary, we only insert it for one of them, in this case + // MOV_32_64. + else if (MI.getOpcode() != SBF::HOR_addr) + // bb label + Fixups.push_back(MCFixup::create(0, Expr, FK_PCRel_2)); + + return 0; +} + +static uint8_t SwapBits(uint8_t Val) { + return (Val & 0x0F) << 4 | (Val & 0xF0) >> 4; +} + +void SBFMCCodeEmitter::encodeInstruction(const MCInst &MI, + SmallVectorImpl &CB, + SmallVectorImpl &Fixups, + const MCSubtargetInfo &STI) const { + unsigned Opcode = MI.getOpcode(); + raw_svector_ostream OS(CB); + support::endian::Writer OSE(OS, + IsLittleEndian ? endianness::little : endianness::big); + + if (Opcode == SBF::LD_imm64 || Opcode == SBF::LD_pseudo) { + uint64_t Value = getBinaryCodeForInstr(MI, Fixups, STI); + CB.push_back(Value >> 56); + if (IsLittleEndian) + CB.push_back((Value >> 48) & 0xff); + else + CB.push_back(SwapBits((Value >> 48) & 0xff)); + OSE.write(0); + OSE.write(Value & 0xffffFFFF); + + const MCOperand &MO = MI.getOperand(1); + uint64_t Imm = MO.isImm() ? MO.getImm() : 0; + OSE.write(0); + OSE.write(0); + OSE.write(0); + OSE.write(Imm >> 32); + } else { + // Get instruction encoding and emit it + uint64_t Value = getBinaryCodeForInstr(MI, Fixups, STI); + CB.push_back(Value >> 56); + if (IsLittleEndian) + CB.push_back((Value >> 48) & 0xff); + else + CB.push_back(SwapBits((Value >> 48) & 0xff)); + OSE.write((Value >> 32) & 0xffff); + OSE.write(Value & 0xffffFFFF); + } +} + +// Encode SBF Memory Operand +uint64_t SBFMCCodeEmitter::getMemoryOpValue(const MCInst &MI, unsigned Op, + SmallVectorImpl &Fixups, + const MCSubtargetInfo &STI) const { + // For CMPXCHG instructions, output is implicitly in R0/W0, + // so memory operand starts from operand 0. + int MemOpStartIndex = 1, Opcode = MI.getOpcode(); + if (Opcode == SBF::CMPXCHGW32 || Opcode == SBF::CMPXCHGD) + MemOpStartIndex = 0; + + uint64_t Encoding; + const MCOperand Op1 = MI.getOperand(MemOpStartIndex); + assert(Op1.isReg() && "First operand is not register."); + Encoding = MRI.getEncodingValue(Op1.getReg()); + Encoding <<= 16; + MCOperand Op2 = MI.getOperand(MemOpStartIndex + 1); + assert(Op2.isImm() && "Second operand is not immediate."); + Encoding |= Op2.getImm() & 0xffff; + return Encoding; +} + +#include "SBFGenMCCodeEmitter.inc" diff --git a/llvm/lib/Target/SBF/MCTargetDesc/SBFMCTargetDesc.cpp b/llvm/lib/Target/SBF/MCTargetDesc/SBFMCTargetDesc.cpp new file mode 100644 index 0000000000000..8647172a8fd0b --- /dev/null +++ b/llvm/lib/Target/SBF/MCTargetDesc/SBFMCTargetDesc.cpp @@ -0,0 +1,160 @@ +//===-- SBFMCTargetDesc.cpp - SBF Target Descriptions ---------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// +// +// This file provides SBF specific target descriptions. +// +//===----------------------------------------------------------------------===// + +#include "MCTargetDesc/SBFMCTargetDesc.h" +#include "MCTargetDesc/SBFInstPrinter.h" +#include "MCTargetDesc/SBFMCAsmInfo.h" +#include "TargetInfo/SBFTargetInfo.h" +#include "llvm/BinaryFormat/ELF.h" +#include "llvm/MC/MCAsmBackend.h" +#include "llvm/MC/MCAssembler.h" +#include "llvm/MC/MCCodeEmitter.h" +#include "llvm/MC/MCContext.h" +#include "llvm/MC/MCELFObjectWriter.h" +#include "llvm/MC/MCELFStreamer.h" +#include "llvm/MC/MCInstrAnalysis.h" +#include "llvm/MC/MCInstrInfo.h" +#include "llvm/MC/MCObjectWriter.h" +#include "llvm/MC/MCRegisterInfo.h" +#include "llvm/MC/MCSubtargetInfo.h" +#include "llvm/MC/TargetRegistry.h" +#include "llvm/TargetParser/Host.h" + +#define GET_INSTRINFO_MC_DESC +#define ENABLE_INSTR_PREDICATE_VERIFIER +#include "SBFGenInstrInfo.inc" + +#define GET_SUBTARGETINFO_MC_DESC +#include "SBFGenSubtargetInfo.inc" + +#define GET_REGINFO_MC_DESC +#include "SBFGenRegisterInfo.inc" + +using namespace llvm; + +static MCInstrInfo *createSBFMCInstrInfo() { + MCInstrInfo *X = new MCInstrInfo(); + InitSBFMCInstrInfo(X); + return X; +} + +static MCRegisterInfo *createSBFMCRegisterInfo(const Triple &TT) { + MCRegisterInfo *X = new MCRegisterInfo(); + InitSBFMCRegisterInfo(X, SBF::R10 /* RAReg doesn't exist */); + return X; +} + +static MCSubtargetInfo *createSBFMCSubtargetInfo(const Triple &TT, + StringRef CPU, StringRef FS) { + std::string CpuStr = cpuFromSubArch(TT, CPU.str()); + StringRef CpuRef = CpuStr; + return createSBFMCSubtargetInfoImpl(TT, CpuRef, /*TuneCPU*/ CpuRef, FS); +} + +static MCStreamer *createSBFMCStreamer(const Triple &T, MCContext &Ctx, + std::unique_ptr &&MAB, + std::unique_ptr &&OW, + std::unique_ptr &&Emitter) { + MCELFStreamer *S = + new MCELFStreamer(Ctx, std::move(MAB), std::move(OW), std::move(Emitter)); + + const MCSubtargetInfo *STI = Ctx.getSubtargetInfo(); + + StringRef CPU = STI->getCPU(); + unsigned EFlag = llvm::ELF::EF_SBF_V0; + if (CPU == "v1") { + EFlag = llvm::ELF::EF_SBF_V1; + } else if (CPU == "v2") { + EFlag = llvm::ELF::EF_SBF_V2; + } else if (CPU == "v3") { + EFlag = llvm::ELF::EF_SBF_V3; + } else if (CPU == "v4") { + EFlag = llvm::ELF::EF_SBF_V4; + } + S->getWriter().setELFHeaderEFlags(EFlag); + + return S; +} + +static MCInstPrinter *createSBFMCInstPrinter(const Triple &T, + unsigned SyntaxVariant, + const MCAsmInfo &MAI, + const MCInstrInfo &MII, + const MCRegisterInfo &MRI) { + if (SyntaxVariant == 0) + return new SBFInstPrinter(MAI, MII, MRI); + + return nullptr; +} + +namespace { + +class SBFMCInstrAnalysis : public MCInstrAnalysis { +public: + explicit SBFMCInstrAnalysis(const MCInstrInfo *Info) + : MCInstrAnalysis(Info) {} + + bool evaluateBranch(const MCInst &Inst, uint64_t Addr, uint64_t Size, + uint64_t &Target) const override { + // The target is the 3rd operand of cond inst and the 1st of uncond inst. + int16_t Imm; + if (isConditionalBranch(Inst)) { + Imm = Inst.getOperand(2).getImm(); + } else if (isUnconditionalBranch(Inst)) + Imm = Inst.getOperand(0).getImm(); + else + return false; + + Target = Addr + Size + Imm * Size; + return true; + } +}; + +} // end anonymous namespace + +static MCInstrAnalysis *createSBFInstrAnalysis(const MCInstrInfo *Info) { + return new SBFMCInstrAnalysis(Info); +} + +extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeSBFTargetMC() { + for (Target *T : {&getTheSBFXTarget()}) { + // Register the MC asm info. + RegisterMCAsmInfo X(*T); + + // Register the MC instruction info. + TargetRegistry::RegisterMCInstrInfo(*T, createSBFMCInstrInfo); + + // Register the MC register info. + TargetRegistry::RegisterMCRegInfo(*T, createSBFMCRegisterInfo); + + // Register the MC subtarget info. + TargetRegistry::RegisterMCSubtargetInfo(*T, + createSBFMCSubtargetInfo); + + // Register the object streamer + TargetRegistry::RegisterELFStreamer(*T, createSBFMCStreamer); + + // Register the MCInstPrinter. + TargetRegistry::RegisterMCInstPrinter(*T, createSBFMCInstPrinter); + + // Register the MC instruction analyzer. + TargetRegistry::RegisterMCInstrAnalysis(*T, createSBFInstrAnalysis); + } + + // Register the MC code emitter + TargetRegistry::RegisterMCCodeEmitter(getTheSBFXTarget(), + createSBFMCCodeEmitter); + + // Register the ASM Backend + TargetRegistry::RegisterMCAsmBackend(getTheSBFXTarget(), + createSBFAsmBackend); +} diff --git a/llvm/lib/Target/SBF/MCTargetDesc/SBFMCTargetDesc.h b/llvm/lib/Target/SBF/MCTargetDesc/SBFMCTargetDesc.h new file mode 100644 index 0000000000000..99f04358160ed --- /dev/null +++ b/llvm/lib/Target/SBF/MCTargetDesc/SBFMCTargetDesc.h @@ -0,0 +1,64 @@ +//===-- SBFMCTargetDesc.h - SBF Target Descriptions -------------*- 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 +// +//===----------------------------------------------------------------------===// +// +// This file provides SBF specific target descriptions. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIB_TARGET_SBF_MCTARGETDESC_SBFMCTARGETDESC_H +#define LLVM_LIB_TARGET_SBF_MCTARGETDESC_SBFMCTARGETDESC_H + +#include "llvm/Config/config.h" +#include "llvm/MC/MCContext.h" +#include "llvm/Support/DataTypes.h" + +#include + +namespace llvm { +class MCAsmBackend; +class MCCodeEmitter; +class MCContext; +class MCInstrInfo; +class MCObjectTargetWriter; +class MCRegisterInfo; +class MCSubtargetInfo; +class MCTargetOptions; +class Target; + +MCCodeEmitter *createSBFMCCodeEmitter(const MCInstrInfo &MCII, + MCContext &Ctx); +MCCodeEmitter *createSBFbeMCCodeEmitter(const MCInstrInfo &MCII, + MCContext &Ctx); + +MCAsmBackend *createSBFAsmBackend(const Target &T, const MCSubtargetInfo &STI, + const MCRegisterInfo &MRI, + const MCTargetOptions &Options); +MCAsmBackend *createSBFbeAsmBackend(const Target &T, const MCSubtargetInfo &STI, + const MCRegisterInfo &MRI, + const MCTargetOptions &Options); + +std::unique_ptr +createSBFELFObjectWriter(uint8_t OSABI, bool useRelocAbs64); +} // namespace llvm + +// Defines symbolic names for SBF registers. This defines a mapping from +// register name to register number. +// +#define GET_REGINFO_ENUM +#include "SBFGenRegisterInfo.inc" + +// Defines symbolic names for the SBF instructions. +// +#define GET_INSTRINFO_ENUM +#define GET_INSTRINFO_MC_HELPER_DECLS +#include "SBFGenInstrInfo.inc" + +#define GET_SUBTARGETINFO_ENUM +#include "SBFGenSubtargetInfo.inc" + +#endif diff --git a/llvm/lib/Target/SBF/SBF.h b/llvm/lib/Target/SBF/SBF.h new file mode 100644 index 0000000000000..8880b1bdd285b --- /dev/null +++ b/llvm/lib/Target/SBF/SBF.h @@ -0,0 +1,73 @@ +//===-- SBF.h - Top-level interface for SBF representation ------*- 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 +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIB_TARGET_SBF_SBF_H +#define LLVM_LIB_TARGET_SBF_SBF_H + +#include "MCTargetDesc/SBFMCTargetDesc.h" +#include "llvm/IR/PassManager.h" +#include "llvm/Pass.h" +#include "llvm/Target/TargetMachine.h" + +namespace llvm { +class SBFRegisterBankInfo; +class SBFSubtarget; +class SBFTargetMachine; +class InstructionSelector; +class SBFTargetMachine; +class PassRegistry; + +ModulePass *createSBFCheckAndAdjustIR(); + +FunctionPass *createSBFISelDag(SBFTargetMachine &TM); +FunctionPass *createSBFMISimplifyPatchablePass(); +FunctionPass *createSBFMIPeepholePass(); +FunctionPass *createSBFMIPeepholeTruncElimPass(); +FunctionPass *createSBFMIPreEmitPeepholePass(CodeGenOptLevel OptLevel, + bool DisablePeephole); +FunctionPass *createSBFMIPreEmitCheckingPass(); + +InstructionSelector *createSBFInstructionSelector(const SBFTargetMachine &, + const SBFSubtarget &, + const SBFRegisterBankInfo &); + +void initializeSBFCheckAndAdjustIRPass(PassRegistry&); +void initializeSBFDAGToDAGISelLegacyPass(PassRegistry &); +void initializeSBFMIPeepholePass(PassRegistry&); +void initializeSBFMIPeepholeTruncElimPass(PassRegistry &); +void initializeSBFMIPreEmitCheckingPass(PassRegistry&); +void initializeSBFMIPreEmitPeepholePass(PassRegistry &); +void initializeSBFMISimplifyPatchablePass(PassRegistry &); + +class SBFAbstractMemberAccessPass + : public PassInfoMixin { + SBFTargetMachine *TM; + +public: + SBFAbstractMemberAccessPass(SBFTargetMachine *TM) : TM(TM) {} + PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM); + + static bool isRequired() { return true; } +}; + +class SBFPreserveDITypePass : public PassInfoMixin { +public: + PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM); + + static bool isRequired() { return true; } +}; + +class SBFIRPeepholePass : public PassInfoMixin { +public: + PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM); + + static bool isRequired() { return true; } +}; +} // namespace llvm + +#endif diff --git a/llvm/lib/Target/SBF/SBF.td b/llvm/lib/Target/SBF/SBF.td new file mode 100644 index 0000000000000..4b27f802beee0 --- /dev/null +++ b/llvm/lib/Target/SBF/SBF.td @@ -0,0 +1,48 @@ +//===-- SBF.td - Describe the SBF Target Machine -----------*- tablegen -*-===// +// +// 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/Target/Target.td" + +include "SBFRegisterInfo.td" +include "SBFCallingConv.td" +include "SBFInstrInfo.td" +include "GISel/SBFRegisterBanks.td" + +def SBFInstrInfo : InstrInfo; +//===----------------------------------------------------------------------===// +// Assembly printer +//===----------------------------------------------------------------------===// + +def SBFAsmWriter : AsmWriter { + string AsmWriterClassName = "InstPrinter"; + int Variant = 0; + bit isMCAsmWriter = 1; +} + +//===----------------------------------------------------------------------===// +// Assembly parser +//===----------------------------------------------------------------------===// + +def SBFAsmParser : AsmParser; + +def SBFAsmParserVariant : AsmParserVariant { + int Variant = 0; + string Name = "sbf"; + string BreakCharacters = "."; +} + +//===----------------------------------------------------------------------===// +// Target Declaration +//===----------------------------------------------------------------------===// + +def SBF : Target { + let InstructionSet = SBFInstrInfo; + let AssemblyWriters = [SBFAsmWriter]; + let AssemblyParsers = [SBFAsmParser]; + let AssemblyParserVariants = [SBFAsmParserVariant]; +} diff --git a/llvm/lib/Target/SBF/SBFAbstractMemberAccess.cpp b/llvm/lib/Target/SBF/SBFAbstractMemberAccess.cpp new file mode 100644 index 0000000000000..1c881a3f6deb2 --- /dev/null +++ b/llvm/lib/Target/SBF/SBFAbstractMemberAccess.cpp @@ -0,0 +1,1191 @@ +//===------ SBFAbstractMemberAccess.cpp - Abstracting Member Accesses -----===// +// +// 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 +// +//===----------------------------------------------------------------------===// +// +// This pass abstracted struct/union member accesses in order to support +// compile-once run-everywhere (CO-RE). The CO-RE intends to compile the program +// which can run on different kernels. In particular, if bpf program tries to +// access a particular kernel data structure member, the details of the +// intermediate member access will be remembered so bpf loader can do +// necessary adjustment right before program loading. +// +// For example, +// +// struct s { +// int a; +// int b; +// }; +// struct t { +// struct s c; +// int d; +// }; +// struct t e; +// +// For the member access e.c.b, the compiler will generate code +// &e + 4 +// +// The compile-once run-everywhere instead generates the following code +// r = 4 +// &e + r +// The "4" in "r = 4" can be changed based on a particular kernel version. +// For example, on a particular kernel version, if struct s is changed to +// +// struct s { +// int new_field; +// int a; +// int b; +// } +// +// By repeating the member access on the host, the bpf loader can +// adjust "r = 4" as "r = 8". +// +// This feature relies on the following three intrinsic calls: +// addr = preserve_array_access_index(base, dimension, index) +// addr = preserve_union_access_index(base, di_index) +// !llvm.preserve.access.index +// addr = preserve_struct_access_index(base, gep_index, di_index) +// !llvm.preserve.access.index +// +// Bitfield member access needs special attention. User cannot take the +// address of a bitfield acceess. To facilitate kernel verifier +// for easy bitfield code optimization, a new clang intrinsic is introduced: +// uint32_t __builtin_preserve_field_info(member_access, info_kind) +// In IR, a chain with two (or more) intrinsic calls will be generated: +// ... +// addr = preserve_struct_access_index(base, 1, 1) !struct s +// uint32_t result = bpf_preserve_field_info(addr, info_kind) +// +// Suppose the info_kind is FIELD_SIGNEDNESS, +// The above two IR intrinsics will be replaced with +// a relocatable insn: +// signness = /* signness of member_access */ +// and signness can be changed by bpf loader based on the +// types on the host. +// +// User can also test whether a field exists or not with +// uint32_t result = bpf_preserve_field_info(member_access, FIELD_EXISTENCE) +// The field will be always available (result = 1) during initial +// compilation, but bpf loader can patch with the correct value +// on the target host where the member_access may or may not be available +// +//===----------------------------------------------------------------------===// + +#include "SBF.h" +#include "SBFCORE.h" +#include "SBFTargetMachine.h" +#include "llvm/IR/DebugInfoMetadata.h" +#include "llvm/IR/GlobalVariable.h" +#include "llvm/IR/Instruction.h" +#include "llvm/IR/Instructions.h" +#include "llvm/IR/IntrinsicsBPF.h" // TODO: jle. +#include "llvm/IR/Module.h" +#include "llvm/IR/PassManager.h" +#include "llvm/IR/Type.h" +#include "llvm/IR/User.h" +#include "llvm/IR/Value.h" +#include "llvm/IR/ValueHandle.h" +#include "llvm/Pass.h" +#include "llvm/Transforms/Utils/BasicBlockUtils.h" +#include + +#define DEBUG_TYPE "sbf-abstract-member-access" + +namespace llvm { +constexpr StringRef SBFCoreSharedInfo::AmaAttr; +uint32_t SBFCoreSharedInfo::SeqNum; + +Instruction *SBFCoreSharedInfo::insertPassThrough(Module *M, BasicBlock *BB, + Instruction *Input, + Instruction *Before) { + Function *Fn = Intrinsic::getOrInsertDeclaration( + M, Intrinsic::bpf_passthrough, {Input->getType(), Input->getType()}); + Constant *SeqNumVal = ConstantInt::get(Type::getInt32Ty(BB->getContext()), + SBFCoreSharedInfo::SeqNum++); + + auto *NewInst = CallInst::Create(Fn, {SeqNumVal, Input}); + NewInst->insertBefore(Before->getIterator()); + return NewInst; +} +} // namespace llvm + +using namespace llvm; + +namespace { +class SBFAbstractMemberAccess final { +public: + SBFAbstractMemberAccess(SBFTargetMachine *TM) : TM(TM) {} + + bool run(Function &F); + + struct CallInfo { + uint32_t Kind; + uint32_t AccessIndex; + MaybeAlign RecordAlignment; + MDNode *Metadata; + WeakTrackingVH Base; + }; + typedef std::stack> CallInfoStack; + +private: + enum : uint32_t { + SBFPreserveArrayAI = 1, + SBFPreserveUnionAI = 2, + SBFPreserveStructAI = 3, + SBFPreserveFieldInfoAI = 4, + }; + + TargetMachine *TM; + const DataLayout *DL = nullptr; + Module *M = nullptr; + + static std::map GEPGlobals; + // A map to link preserve_*_access_index intrinsic calls. + std::map> AIChain; + // A map to hold all the base preserve_*_access_index intrinsic calls. + // The base call is not an input of any other preserve_* + // intrinsics. + std::map BaseAICalls; + // A map to hold relationships + std::map AnonRecords; + + void CheckAnonRecordType(DIDerivedType *ParentTy, DIType *Ty); + void CheckCompositeType(DIDerivedType *ParentTy, DICompositeType *CTy); + void CheckDerivedType(DIDerivedType *ParentTy, DIDerivedType *DTy); + void ResetMetadata(struct CallInfo &CInfo); + + bool doTransformation(Function &F); + + void traceAICall(CallInst *Call, CallInfo &ParentInfo); + void traceBitCast(BitCastInst *BitCast, CallInst *Parent, + CallInfo &ParentInfo); + void traceGEP(GetElementPtrInst *GEP, CallInst *Parent, + CallInfo &ParentInfo); + void collectAICallChains(Function &F); + + bool IsPreserveDIAccessIndexCall(const CallInst *Call, CallInfo &Cinfo); + bool IsValidAIChain(const MDNode *ParentMeta, uint32_t ParentAI, + const MDNode *ChildMeta); + bool removePreserveAccessIndexIntrinsic(Function &F); + void replaceWithGEP(std::vector &CallList, + uint32_t NumOfZerosIndex, uint32_t DIIndex); + bool HasPreserveFieldInfoCall(CallInfoStack &CallStack); + void GetStorageBitRange(DIDerivedType *MemberTy, Align RecordAlignment, + uint32_t &StartBitOffset, uint32_t &EndBitOffset); + uint32_t GetFieldInfo(uint32_t InfoKind, DICompositeType *CTy, + uint32_t AccessIndex, uint32_t PatchImm, + MaybeAlign RecordAlignment); + + Value *computeBaseAndAccessKey(CallInst *Call, CallInfo &CInfo, + std::string &AccessKey, MDNode *&BaseMeta); + MDNode *computeAccessKey(CallInst *Call, CallInfo &CInfo, + std::string &AccessKey, bool &IsInt32Ret); + uint64_t getConstant(const Value *IndexValue); + bool transformGEPChain(CallInst *Call, CallInfo &CInfo); +}; + +std::map SBFAbstractMemberAccess::GEPGlobals; + +} // End anonymous namespace + +bool SBFAbstractMemberAccess::run(Function &F) { + LLVM_DEBUG(dbgs() << "********** Abstract Member Accesses **********\n"); + + M = F.getParent(); + if (!M) + return false; + + // Bail out if no debug info. + if (M->debug_compile_units().empty()) + return false; + + // For each argument/return/local_variable type, trace the type + // pattern like '[derived_type]* [composite_type]' to check + // and remember (anon record -> typedef) relations where the + // anon record is defined as + // typedef [const/volatile/restrict]* [anon record] + DISubprogram *SP = F.getSubprogram(); + if (SP && SP->isDefinition()) { + for (DIType *Ty: SP->getType()->getTypeArray()) + CheckAnonRecordType(nullptr, Ty); + for (const DINode *DN : SP->getRetainedNodes()) { + if (const auto *DV = dyn_cast(DN)) + CheckAnonRecordType(nullptr, DV->getType()); + } + } + + DL = &M->getDataLayout(); + return doTransformation(F); +} + +void SBFAbstractMemberAccess::ResetMetadata(struct CallInfo &CInfo) { + if (auto Ty = dyn_cast(CInfo.Metadata)) { + auto It = AnonRecords.find(Ty); + if (It != AnonRecords.end() && It->second != nullptr) + CInfo.Metadata = It->second; + } +} + +void SBFAbstractMemberAccess::CheckCompositeType(DIDerivedType *ParentTy, + DICompositeType *CTy) { + if (!CTy->getName().empty() || !ParentTy || + ParentTy->getTag() != dwarf::DW_TAG_typedef) + return; + + auto [It, Inserted] = AnonRecords.try_emplace(CTy, ParentTy); + + // Two or more typedef's may point to the same anon record. + // If this is the case, set the typedef DIType to be nullptr + // to indicate the duplication case. + if (!Inserted && It->second != ParentTy) + It->second = nullptr; +} + +void SBFAbstractMemberAccess::CheckDerivedType(DIDerivedType *ParentTy, + DIDerivedType *DTy) { + DIType *BaseType = DTy->getBaseType(); + if (!BaseType) + return; + + unsigned Tag = DTy->getTag(); + if (Tag == dwarf::DW_TAG_pointer_type) + CheckAnonRecordType(nullptr, BaseType); + else if (Tag == dwarf::DW_TAG_typedef) + CheckAnonRecordType(DTy, BaseType); + else + CheckAnonRecordType(ParentTy, BaseType); +} + +void SBFAbstractMemberAccess::CheckAnonRecordType(DIDerivedType *ParentTy, + DIType *Ty) { + if (!Ty) + return; + + if (auto *CTy = dyn_cast(Ty)) + return CheckCompositeType(ParentTy, CTy); + else if (auto *DTy = dyn_cast(Ty)) + return CheckDerivedType(ParentTy, DTy); +} + +static bool SkipDIDerivedTag(unsigned Tag, bool skipTypedef) { + if (Tag != dwarf::DW_TAG_typedef && Tag != dwarf::DW_TAG_const_type && + Tag != dwarf::DW_TAG_volatile_type && + Tag != dwarf::DW_TAG_restrict_type && + Tag != dwarf::DW_TAG_member) + return false; + if (Tag == dwarf::DW_TAG_typedef && !skipTypedef) + return false; + return true; +} + +static DIType * stripQualifiers(DIType *Ty, bool skipTypedef = true) { + while (auto *DTy = dyn_cast(Ty)) { + if (!SkipDIDerivedTag(DTy->getTag(), skipTypedef)) + break; + Ty = DTy->getBaseType(); + } + return Ty; +} + +static const DIType * stripQualifiers(const DIType *Ty) { + while (auto *DTy = dyn_cast(Ty)) { + if (!SkipDIDerivedTag(DTy->getTag(), true)) + break; + Ty = DTy->getBaseType(); + } + return Ty; +} + +static uint32_t calcArraySize(const DICompositeType *CTy, uint32_t StartDim) { + DINodeArray Elements = CTy->getElements(); + uint32_t DimSize = 1; + for (uint32_t I = StartDim; I < Elements.size(); ++I) { + if (auto *Element = dyn_cast_or_null(Elements[I])) + if (Element->getTag() == dwarf::DW_TAG_subrange_type) { + const DISubrange *SR = cast(Element); + auto *CI = dyn_cast(SR->getCount()); + DimSize *= CI->getSExtValue(); + } + } + + return DimSize; +} + +static Type *getBaseElementType(const CallInst *Call) { + // Element type is stored in an elementtype() attribute on the first param. + return Call->getParamElementType(0); +} + +/// Check whether a call is a preserve_*_access_index intrinsic call or not. +bool SBFAbstractMemberAccess::IsPreserveDIAccessIndexCall(const CallInst *Call, + CallInfo &CInfo) { + if (!Call) + return false; + + const auto *GV = dyn_cast(Call->getCalledOperand()); + if (!GV) + return false; + if (GV->getName().starts_with("llvm.preserve.array.access.index")) { + CInfo.Kind = SBFPreserveArrayAI; + CInfo.Metadata = Call->getMetadata(LLVMContext::MD_preserve_access_index); + if (!CInfo.Metadata) + report_fatal_error("Missing metadata for llvm.preserve.array.access.index intrinsic"); + CInfo.AccessIndex = getConstant(Call->getArgOperand(2)); + CInfo.Base = Call->getArgOperand(0); + CInfo.RecordAlignment = DL->getABITypeAlign(getBaseElementType(Call)); + return true; + } + if (GV->getName().starts_with("llvm.preserve.union.access.index")) { + CInfo.Kind = SBFPreserveUnionAI; + CInfo.Metadata = Call->getMetadata(LLVMContext::MD_preserve_access_index); + if (!CInfo.Metadata) + report_fatal_error("Missing metadata for llvm.preserve.union.access.index intrinsic"); + ResetMetadata(CInfo); + CInfo.AccessIndex = getConstant(Call->getArgOperand(1)); + CInfo.Base = Call->getArgOperand(0); + return true; + } + if (GV->getName().starts_with("llvm.preserve.struct.access.index")) { + CInfo.Kind = SBFPreserveStructAI; + CInfo.Metadata = Call->getMetadata(LLVMContext::MD_preserve_access_index); + if (!CInfo.Metadata) + report_fatal_error("Missing metadata for llvm.preserve.struct.access.index intrinsic"); + ResetMetadata(CInfo); + CInfo.AccessIndex = getConstant(Call->getArgOperand(2)); + CInfo.Base = Call->getArgOperand(0); + CInfo.RecordAlignment = DL->getABITypeAlign(getBaseElementType(Call)); + return true; + } + if (GV->getName().starts_with("llvm.bpf.preserve.field.info")) { + CInfo.Kind = SBFPreserveFieldInfoAI; + CInfo.Metadata = nullptr; + // Check validity of info_kind as clang did not check this. + uint64_t InfoKind = getConstant(Call->getArgOperand(1)); + if (InfoKind >= SBFCoreSharedInfo::MAX_FIELD_RELOC_KIND) + report_fatal_error("Incorrect info_kind for llvm.bpf.preserve.field.info intrinsic"); + CInfo.AccessIndex = InfoKind; + return true; + } + if (GV->getName().starts_with("llvm.bpf.preserve.type.info")) { + CInfo.Kind = SBFPreserveFieldInfoAI; + CInfo.Metadata = Call->getMetadata(LLVMContext::MD_preserve_access_index); + if (!CInfo.Metadata) + report_fatal_error("Missing metadata for llvm.preserve.type.info intrinsic"); + uint64_t Flag = getConstant(Call->getArgOperand(1)); + if (Flag >= SBFCoreSharedInfo::MAX_PRESERVE_TYPE_INFO_FLAG) + report_fatal_error("Incorrect flag for llvm.bpf.preserve.type.info intrinsic"); + if (Flag == SBFCoreSharedInfo::PRESERVE_TYPE_INFO_EXISTENCE) + CInfo.AccessIndex = SBFCoreSharedInfo::TYPE_EXISTENCE; + else if (Flag == SBFCoreSharedInfo::PRESERVE_TYPE_INFO_MATCH) + CInfo.AccessIndex = SBFCoreSharedInfo::TYPE_MATCH; + else + CInfo.AccessIndex = SBFCoreSharedInfo::TYPE_SIZE; + return true; + } + if (GV->getName().starts_with("llvm.bpf.preserve.enum.value")) { + CInfo.Kind = SBFPreserveFieldInfoAI; + CInfo.Metadata = Call->getMetadata(LLVMContext::MD_preserve_access_index); + if (!CInfo.Metadata) + report_fatal_error("Missing metadata for llvm.preserve.enum.value intrinsic"); + uint64_t Flag = getConstant(Call->getArgOperand(2)); + if (Flag >= SBFCoreSharedInfo::MAX_PRESERVE_ENUM_VALUE_FLAG) + report_fatal_error("Incorrect flag for llvm.bpf.preserve.enum.value intrinsic"); + if (Flag == SBFCoreSharedInfo::PRESERVE_ENUM_VALUE_EXISTENCE) + CInfo.AccessIndex = SBFCoreSharedInfo::ENUM_VALUE_EXISTENCE; + else + CInfo.AccessIndex = SBFCoreSharedInfo::ENUM_VALUE; + return true; + } + + return false; +} + +void SBFAbstractMemberAccess::replaceWithGEP(std::vector &CallList, + uint32_t DimensionIndex, + uint32_t GEPIndex) { + for (auto *Call : CallList) { + uint32_t Dimension = 1; + if (DimensionIndex > 0) + Dimension = getConstant(Call->getArgOperand(DimensionIndex)); + + Constant *Zero = + ConstantInt::get(Type::getInt32Ty(Call->getParent()->getContext()), 0); + SmallVector IdxList; + for (unsigned I = 0; I < Dimension; ++I) + IdxList.push_back(Zero); + IdxList.push_back(Call->getArgOperand(GEPIndex)); + + auto *GEP = GetElementPtrInst::CreateInBounds( + getBaseElementType(Call), Call->getArgOperand(0), IdxList, "", Call->getIterator()); + Call->replaceAllUsesWith(GEP); + Call->eraseFromParent(); + } +} + +bool SBFAbstractMemberAccess::removePreserveAccessIndexIntrinsic(Function &F) { + std::vector PreserveArrayIndexCalls; + std::vector PreserveUnionIndexCalls; + std::vector PreserveStructIndexCalls; + bool Found = false; + + for (auto &BB : F) + for (auto &I : BB) { + auto *Call = dyn_cast(&I); + CallInfo CInfo; + if (!IsPreserveDIAccessIndexCall(Call, CInfo)) + continue; + + Found = true; + if (CInfo.Kind == SBFPreserveArrayAI) + PreserveArrayIndexCalls.push_back(Call); + else if (CInfo.Kind == SBFPreserveUnionAI) + PreserveUnionIndexCalls.push_back(Call); + else + PreserveStructIndexCalls.push_back(Call); + } + + // do the following transformation: + // . addr = preserve_array_access_index(base, dimension, index) + // is transformed to + // addr = GEP(base, dimenion's zero's, index) + // . addr = preserve_union_access_index(base, di_index) + // is transformed to + // addr = base, i.e., all usages of "addr" are replaced by "base". + // . addr = preserve_struct_access_index(base, gep_index, di_index) + // is transformed to + // addr = GEP(base, 0, gep_index) + replaceWithGEP(PreserveArrayIndexCalls, 1, 2); + replaceWithGEP(PreserveStructIndexCalls, 0, 1); + for (auto *Call : PreserveUnionIndexCalls) { + Call->replaceAllUsesWith(Call->getArgOperand(0)); + Call->eraseFromParent(); + } + + return Found; +} + +/// Check whether the access index chain is valid. We check +/// here because there may be type casts between two +/// access indexes. We want to ensure memory access still valid. +bool SBFAbstractMemberAccess::IsValidAIChain(const MDNode *ParentType, + uint32_t ParentAI, + const MDNode *ChildType) { + if (!ChildType) + return true; // preserve_field_info, no type comparison needed. + + const DIType *PType = stripQualifiers(cast(ParentType)); + const DIType *CType = stripQualifiers(cast(ChildType)); + + // Child is a derived/pointer type, which is due to type casting. + // Pointer type cannot be in the middle of chain. + if (isa(CType)) + return false; + + // Parent is a pointer type. + if (const auto *PtrTy = dyn_cast(PType)) { + if (PtrTy->getTag() != dwarf::DW_TAG_pointer_type) + return false; + return stripQualifiers(PtrTy->getBaseType()) == CType; + } + + // Otherwise, struct/union/array types + const auto *PTy = dyn_cast(PType); + const auto *CTy = dyn_cast(CType); + assert(PTy && CTy && "ParentType or ChildType is null or not composite"); + + uint32_t PTyTag = PTy->getTag(); + assert(PTyTag == dwarf::DW_TAG_array_type || + PTyTag == dwarf::DW_TAG_structure_type || + PTyTag == dwarf::DW_TAG_union_type); + + uint32_t CTyTag = CTy->getTag(); + assert(CTyTag == dwarf::DW_TAG_array_type || + CTyTag == dwarf::DW_TAG_structure_type || + CTyTag == dwarf::DW_TAG_union_type); + + // Multi dimensional arrays, base element should be the same + if (PTyTag == dwarf::DW_TAG_array_type && PTyTag == CTyTag) + return PTy->getBaseType() == CTy->getBaseType(); + + DIType *Ty; + if (PTyTag == dwarf::DW_TAG_array_type) + Ty = PTy->getBaseType(); + else + Ty = dyn_cast(PTy->getElements()[ParentAI]); + + return dyn_cast(stripQualifiers(Ty)) == CTy; +} + +void SBFAbstractMemberAccess::traceAICall(CallInst *Call, + CallInfo &ParentInfo) { + for (User *U : Call->users()) { + Instruction *Inst = dyn_cast(U); + if (!Inst) + continue; + + if (auto *BI = dyn_cast(Inst)) { + traceBitCast(BI, Call, ParentInfo); + } else if (auto *CI = dyn_cast(Inst)) { + CallInfo ChildInfo; + + if (IsPreserveDIAccessIndexCall(CI, ChildInfo) && + IsValidAIChain(ParentInfo.Metadata, ParentInfo.AccessIndex, + ChildInfo.Metadata)) { + AIChain[CI] = std::make_pair(Call, ParentInfo); + traceAICall(CI, ChildInfo); + } else { + BaseAICalls[Call] = ParentInfo; + } + } else if (auto *GI = dyn_cast(Inst)) { + if (GI->hasAllZeroIndices()) + traceGEP(GI, Call, ParentInfo); + else + BaseAICalls[Call] = ParentInfo; + } else { + BaseAICalls[Call] = ParentInfo; + } + } +} + +void SBFAbstractMemberAccess::traceBitCast(BitCastInst *BitCast, + CallInst *Parent, + CallInfo &ParentInfo) { + for (User *U : BitCast->users()) { + Instruction *Inst = dyn_cast(U); + if (!Inst) + continue; + + if (auto *BI = dyn_cast(Inst)) { + traceBitCast(BI, Parent, ParentInfo); + } else if (auto *CI = dyn_cast(Inst)) { + CallInfo ChildInfo; + if (IsPreserveDIAccessIndexCall(CI, ChildInfo) && + IsValidAIChain(ParentInfo.Metadata, ParentInfo.AccessIndex, + ChildInfo.Metadata)) { + AIChain[CI] = std::make_pair(Parent, ParentInfo); + traceAICall(CI, ChildInfo); + } else { + BaseAICalls[Parent] = ParentInfo; + } + } else if (auto *GI = dyn_cast(Inst)) { + if (GI->hasAllZeroIndices()) + traceGEP(GI, Parent, ParentInfo); + else + BaseAICalls[Parent] = ParentInfo; + } else { + BaseAICalls[Parent] = ParentInfo; + } + } +} + +void SBFAbstractMemberAccess::traceGEP(GetElementPtrInst *GEP, CallInst *Parent, + CallInfo &ParentInfo) { + for (User *U : GEP->users()) { + Instruction *Inst = dyn_cast(U); + if (!Inst) + continue; + + if (auto *BI = dyn_cast(Inst)) { + traceBitCast(BI, Parent, ParentInfo); + } else if (auto *CI = dyn_cast(Inst)) { + CallInfo ChildInfo; + if (IsPreserveDIAccessIndexCall(CI, ChildInfo) && + IsValidAIChain(ParentInfo.Metadata, ParentInfo.AccessIndex, + ChildInfo.Metadata)) { + AIChain[CI] = std::make_pair(Parent, ParentInfo); + traceAICall(CI, ChildInfo); + } else { + BaseAICalls[Parent] = ParentInfo; + } + } else if (auto *GI = dyn_cast(Inst)) { + if (GI->hasAllZeroIndices()) + traceGEP(GI, Parent, ParentInfo); + else + BaseAICalls[Parent] = ParentInfo; + } else { + BaseAICalls[Parent] = ParentInfo; + } + } +} + +void SBFAbstractMemberAccess::collectAICallChains(Function &F) { + AIChain.clear(); + BaseAICalls.clear(); + + for (auto &BB : F) + for (auto &I : BB) { + CallInfo CInfo; + auto *Call = dyn_cast(&I); + if (!IsPreserveDIAccessIndexCall(Call, CInfo) || + AIChain.find(Call) != AIChain.end()) + continue; + + traceAICall(Call, CInfo); + } +} + +uint64_t SBFAbstractMemberAccess::getConstant(const Value *IndexValue) { + const ConstantInt *CV = dyn_cast(IndexValue); + assert(CV); + return CV->getValue().getZExtValue(); +} + +/// Get the start and the end of storage offset for \p MemberTy. +void SBFAbstractMemberAccess::GetStorageBitRange(DIDerivedType *MemberTy, + Align RecordAlignment, + uint32_t &StartBitOffset, + uint32_t &EndBitOffset) { + uint32_t MemberBitSize = MemberTy->getSizeInBits(); + uint32_t MemberBitOffset = MemberTy->getOffsetInBits(); + + if (RecordAlignment > 8) { + // If the Bits are within an aligned 8-byte, set the RecordAlignment + // to 8, other report the fatal error. + if (MemberBitOffset / 64 != (MemberBitOffset + MemberBitSize) / 64) + report_fatal_error("Unsupported field expression for llvm.bpf.preserve.field.info, " + "requiring too big alignment"); + RecordAlignment = Align(8); + } + + uint32_t AlignBits = RecordAlignment.value() * 8; + if (MemberBitSize > AlignBits) + report_fatal_error("Unsupported field expression for llvm.bpf.preserve.field.info, " + "bitfield size greater than record alignment"); + + StartBitOffset = MemberBitOffset & ~(AlignBits - 1); + if ((StartBitOffset + AlignBits) < (MemberBitOffset + MemberBitSize)) + report_fatal_error("Unsupported field expression for llvm.bpf.preserve.field.info, " + "cross alignment boundary"); + EndBitOffset = StartBitOffset + AlignBits; +} + +uint32_t SBFAbstractMemberAccess::GetFieldInfo(uint32_t InfoKind, + DICompositeType *CTy, + uint32_t AccessIndex, + uint32_t PatchImm, + MaybeAlign RecordAlignment) { + if (InfoKind == SBFCoreSharedInfo::FIELD_EXISTENCE) + return 1; + + uint32_t Tag = CTy->getTag(); + if (InfoKind == SBFCoreSharedInfo::FIELD_BYTE_OFFSET) { + if (Tag == dwarf::DW_TAG_array_type) { + auto *EltTy = stripQualifiers(CTy->getBaseType()); + PatchImm += AccessIndex * calcArraySize(CTy, 1) * + (EltTy->getSizeInBits() >> 3); + } else if (Tag == dwarf::DW_TAG_structure_type) { + auto *MemberTy = cast(CTy->getElements()[AccessIndex]); + if (!MemberTy->isBitField()) { + PatchImm += MemberTy->getOffsetInBits() >> 3; + } else { + unsigned SBitOffset, NextSBitOffset; + GetStorageBitRange(MemberTy, *RecordAlignment, SBitOffset, + NextSBitOffset); + PatchImm += SBitOffset >> 3; + } + } + return PatchImm; + } + + if (InfoKind == SBFCoreSharedInfo::FIELD_BYTE_SIZE) { + if (Tag == dwarf::DW_TAG_array_type) { + auto *EltTy = stripQualifiers(CTy->getBaseType()); + return calcArraySize(CTy, 1) * (EltTy->getSizeInBits() >> 3); + } else { + auto *MemberTy = cast(CTy->getElements()[AccessIndex]); + uint32_t SizeInBits = MemberTy->getSizeInBits(); + if (!MemberTy->isBitField()) + return SizeInBits >> 3; + + unsigned SBitOffset, NextSBitOffset; + GetStorageBitRange(MemberTy, *RecordAlignment, SBitOffset, + NextSBitOffset); + SizeInBits = NextSBitOffset - SBitOffset; + if (SizeInBits & (SizeInBits - 1)) + report_fatal_error("Unsupported field expression for llvm.bpf.preserve.field.info"); + return SizeInBits >> 3; + } + } + + if (InfoKind == SBFCoreSharedInfo::FIELD_SIGNEDNESS) { + const DIType *BaseTy; + if (Tag == dwarf::DW_TAG_array_type) { + // Signedness only checked when final array elements are accessed. + if (CTy->getElements().size() != 1) + report_fatal_error("Invalid array expression for llvm.bpf.preserve.field.info"); + BaseTy = stripQualifiers(CTy->getBaseType()); + } else { + auto *MemberTy = cast(CTy->getElements()[AccessIndex]); + BaseTy = stripQualifiers(MemberTy->getBaseType()); + } + + // Only basic types and enum types have signedness. + const auto *BTy = dyn_cast(BaseTy); + while (!BTy) { + const auto *CompTy = dyn_cast(BaseTy); + // Report an error if the field expression does not have signedness. + if (!CompTy || CompTy->getTag() != dwarf::DW_TAG_enumeration_type) + report_fatal_error("Invalid field expression for llvm.bpf.preserve.field.info"); + BaseTy = stripQualifiers(CompTy->getBaseType()); + BTy = dyn_cast(BaseTy); + } + uint32_t Encoding = BTy->getEncoding(); + return (Encoding == dwarf::DW_ATE_signed || Encoding == dwarf::DW_ATE_signed_char); + } + + if (InfoKind == SBFCoreSharedInfo::FIELD_LSHIFT_U64) { + // The value is loaded into a value with FIELD_BYTE_SIZE size, + // and then zero or sign extended to U64. + // FIELD_LSHIFT_U64 and FIELD_RSHIFT_U64 are operations + // to extract the original value. + const Triple &Triple = TM->getTargetTriple(); + DIDerivedType *MemberTy = nullptr; + bool IsBitField = false; + uint32_t SizeInBits; + + if (Tag == dwarf::DW_TAG_array_type) { + auto *EltTy = stripQualifiers(CTy->getBaseType()); + SizeInBits = calcArraySize(CTy, 1) * EltTy->getSizeInBits(); + } else { + MemberTy = cast(CTy->getElements()[AccessIndex]); + SizeInBits = MemberTy->getSizeInBits(); + IsBitField = MemberTy->isBitField(); + } + + if (!IsBitField) { + if (SizeInBits > 64) + report_fatal_error("too big field size for llvm.bpf.preserve.field.info"); + return 64 - SizeInBits; + } + + unsigned SBitOffset, NextSBitOffset; + GetStorageBitRange(MemberTy, *RecordAlignment, SBitOffset, NextSBitOffset); + if (NextSBitOffset - SBitOffset > 64) + report_fatal_error("too big field size for llvm.bpf.preserve.field.info"); + + unsigned OffsetInBits = MemberTy->getOffsetInBits(); + if (Triple.getArch() == Triple::bpfel || Triple.getArch() == Triple::sbf) + return SBitOffset + 64 - OffsetInBits - SizeInBits; + else + return OffsetInBits + 64 - NextSBitOffset; + } + + if (InfoKind == SBFCoreSharedInfo::FIELD_RSHIFT_U64) { + DIDerivedType *MemberTy = nullptr; + bool IsBitField = false; + uint32_t SizeInBits; + if (Tag == dwarf::DW_TAG_array_type) { + auto *EltTy = stripQualifiers(CTy->getBaseType()); + SizeInBits = calcArraySize(CTy, 1) * EltTy->getSizeInBits(); + } else { + MemberTy = cast(CTy->getElements()[AccessIndex]); + SizeInBits = MemberTy->getSizeInBits(); + IsBitField = MemberTy->isBitField(); + } + + if (!IsBitField) { + if (SizeInBits > 64) + report_fatal_error("too big field size for llvm.bpf.preserve.field.info"); + return 64 - SizeInBits; + } + + unsigned SBitOffset, NextSBitOffset; + GetStorageBitRange(MemberTy, *RecordAlignment, SBitOffset, NextSBitOffset); + if (NextSBitOffset - SBitOffset > 64) + report_fatal_error("too big field size for llvm.bpf.preserve.field.info"); + + return 64 - SizeInBits; + } + + llvm_unreachable("Unknown llvm.bpf.preserve.field.info info kind"); +} + +bool SBFAbstractMemberAccess::HasPreserveFieldInfoCall(CallInfoStack &CallStack) { + // This is called in error return path, no need to maintain CallStack. + while (CallStack.size()) { + auto StackElem = CallStack.top(); + if (StackElem.second.Kind == SBFPreserveFieldInfoAI) + return true; + CallStack.pop(); + } + return false; +} + +/// Compute the base of the whole preserve_* intrinsics chains, i.e., the base +/// pointer of the first preserve_*_access_index call, and construct the access +/// string, which will be the name of a global variable. +Value *SBFAbstractMemberAccess::computeBaseAndAccessKey(CallInst *Call, + CallInfo &CInfo, + std::string &AccessKey, + MDNode *&TypeMeta) { + Value *Base = nullptr; + std::string TypeName; + CallInfoStack CallStack; + + // Put the access chain into a stack with the top as the head of the chain. + while (Call) { + CallStack.push(std::make_pair(Call, CInfo)); + CInfo = AIChain[Call].second; + Call = AIChain[Call].first; + } + + // The access offset from the base of the head of chain is also + // calculated here as all debuginfo types are available. + + // Get type name and calculate the first index. + // We only want to get type name from typedef, structure or union. + // If user wants a relocation like + // int *p; ... __builtin_preserve_access_index(&p[4]) ... + // or + // int a[10][20]; ... __builtin_preserve_access_index(&a[2][3]) ... + // we will skip them. + uint32_t FirstIndex = 0; + uint32_t PatchImm = 0; // AccessOffset or the requested field info + uint32_t InfoKind = SBFCoreSharedInfo::FIELD_BYTE_OFFSET; + while (CallStack.size()) { + auto StackElem = CallStack.top(); + Call = StackElem.first; + CInfo = StackElem.second; + + if (!Base) + Base = CInfo.Base; + + DIType *PossibleTypeDef = stripQualifiers(cast(CInfo.Metadata), + false); + DIType *Ty = stripQualifiers(PossibleTypeDef); + if (CInfo.Kind == SBFPreserveUnionAI || + CInfo.Kind == SBFPreserveStructAI) { + // struct or union type. If the typedef is in the metadata, always + // use the typedef. + TypeName = std::string(PossibleTypeDef->getName()); + TypeMeta = PossibleTypeDef; + PatchImm += FirstIndex * (Ty->getSizeInBits() >> 3); + break; + } + + assert(CInfo.Kind == SBFPreserveArrayAI); + + // Array entries will always be consumed for accumulative initial index. + CallStack.pop(); + + // SBFPreserveArrayAI + uint64_t AccessIndex = CInfo.AccessIndex; + + DIType *BaseTy = nullptr; + bool CheckElemType = false; + if (const auto *CTy = dyn_cast(Ty)) { + // array type + assert(CTy->getTag() == dwarf::DW_TAG_array_type); + + + FirstIndex += AccessIndex * calcArraySize(CTy, 1); + BaseTy = stripQualifiers(CTy->getBaseType()); + CheckElemType = CTy->getElements().size() == 1; + } else { + // pointer type + auto *DTy = cast(Ty); + assert(DTy->getTag() == dwarf::DW_TAG_pointer_type); + + BaseTy = stripQualifiers(DTy->getBaseType()); + CTy = dyn_cast(BaseTy); + if (!CTy) { + CheckElemType = true; + } else if (CTy->getTag() != dwarf::DW_TAG_array_type) { + FirstIndex += AccessIndex; + CheckElemType = true; + } else { + FirstIndex += AccessIndex * calcArraySize(CTy, 0); + } + } + + if (CheckElemType) { + auto *CTy = dyn_cast(BaseTy); + if (!CTy) { + if (HasPreserveFieldInfoCall(CallStack)) + report_fatal_error("Invalid field access for llvm.preserve.field.info intrinsic"); + return nullptr; + } + + unsigned CTag = CTy->getTag(); + if (CTag == dwarf::DW_TAG_structure_type || CTag == dwarf::DW_TAG_union_type) { + TypeName = std::string(CTy->getName()); + } else { + if (HasPreserveFieldInfoCall(CallStack)) + report_fatal_error("Invalid field access for llvm.preserve.field.info intrinsic"); + return nullptr; + } + TypeMeta = CTy; + PatchImm += FirstIndex * (CTy->getSizeInBits() >> 3); + break; + } + } + assert(TypeName.size()); + AccessKey += std::to_string(FirstIndex); + + // Traverse the rest of access chain to complete offset calculation + // and access key construction. + while (CallStack.size()) { + auto StackElem = CallStack.top(); + CInfo = StackElem.second; + CallStack.pop(); + + if (CInfo.Kind == SBFPreserveFieldInfoAI) { + InfoKind = CInfo.AccessIndex; + if (InfoKind == SBFCoreSharedInfo::FIELD_EXISTENCE) + PatchImm = 1; + break; + } + + // If the next Call (the top of the stack) is a SBFPreserveFieldInfoAI, + // the action will be extracting field info. + if (CallStack.size()) { + auto StackElem2 = CallStack.top(); + CallInfo CInfo2 = StackElem2.second; + if (CInfo2.Kind == SBFPreserveFieldInfoAI) { + InfoKind = CInfo2.AccessIndex; + assert(CallStack.size() == 1); + } + } + + // Access Index + uint64_t AccessIndex = CInfo.AccessIndex; + AccessKey += ":" + std::to_string(AccessIndex); + + MDNode *MDN = CInfo.Metadata; + // At this stage, it cannot be pointer type. + auto *CTy = cast(stripQualifiers(cast(MDN))); + PatchImm = GetFieldInfo(InfoKind, CTy, AccessIndex, PatchImm, + CInfo.RecordAlignment); + } + + // Access key is the + // "llvm." + type name + ":" + reloc type + ":" + patched imm + "$" + + // access string, + // uniquely identifying one relocation. + // The prefix "llvm." indicates this is a temporary global, which should + // not be emitted to ELF file. + AccessKey = "llvm." + TypeName + ":" + std::to_string(InfoKind) + ":" + + std::to_string(PatchImm) + "$" + AccessKey; + + return Base; +} + +MDNode *SBFAbstractMemberAccess::computeAccessKey(CallInst *Call, + CallInfo &CInfo, + std::string &AccessKey, + bool &IsInt32Ret) { + DIType *Ty = stripQualifiers(cast(CInfo.Metadata), false); + assert(!Ty->getName().empty()); + + int64_t PatchImm; + std::string AccessStr("0"); + if (CInfo.AccessIndex == SBFCoreSharedInfo::TYPE_EXISTENCE || + CInfo.AccessIndex == SBFCoreSharedInfo::TYPE_MATCH) { + PatchImm = 1; + } else if (CInfo.AccessIndex == SBFCoreSharedInfo::TYPE_SIZE) { + // typedef debuginfo type has size 0, get the eventual base type. + DIType *BaseTy = stripQualifiers(Ty, true); + PatchImm = BaseTy->getSizeInBits() / 8; + } else { + // ENUM_VALUE_EXISTENCE and ENUM_VALUE + IsInt32Ret = false; + + // The argument could be a global variable or a getelementptr with base to + // a global variable depending on whether the clang option `opaque-options` + // is set or not. + const GlobalVariable *GV = + cast(Call->getArgOperand(1)->stripPointerCasts()); + assert(GV->hasInitializer()); + const ConstantDataArray *DA = cast(GV->getInitializer()); + assert(DA->isString()); + StringRef ValueStr = DA->getAsString(); + + // ValueStr format: : + size_t Separator = ValueStr.find_first_of(':'); + StringRef EnumeratorStr = ValueStr.substr(0, Separator); + + // Find enumerator index in the debuginfo + DIType *BaseTy = stripQualifiers(Ty, true); + const auto *CTy = cast(BaseTy); + assert(CTy->getTag() == dwarf::DW_TAG_enumeration_type); + int EnumIndex = 0; + for (const auto Element : CTy->getElements()) { + const auto *Enum = cast(Element); + if (Enum->getName() == EnumeratorStr) { + AccessStr = std::to_string(EnumIndex); + break; + } + EnumIndex++; + } + + if (CInfo.AccessIndex == SBFCoreSharedInfo::ENUM_VALUE) { + StringRef EValueStr = ValueStr.substr(Separator + 1); + PatchImm = std::stoll(std::string(EValueStr)); + } else { + PatchImm = 1; + } + } + + AccessKey = "llvm." + Ty->getName().str() + ":" + + std::to_string(CInfo.AccessIndex) + std::string(":") + + std::to_string(PatchImm) + std::string("$") + AccessStr; + + return Ty; +} + +/// Call/Kind is the base preserve_*_access_index() call. Attempts to do +/// transformation to a chain of relocable GEPs. +bool SBFAbstractMemberAccess::transformGEPChain(CallInst *Call, + CallInfo &CInfo) { + std::string AccessKey; + MDNode *TypeMeta; + Value *Base = nullptr; + bool IsInt32Ret; + + IsInt32Ret = CInfo.Kind == SBFPreserveFieldInfoAI; + if (CInfo.Kind == SBFPreserveFieldInfoAI && CInfo.Metadata) { + TypeMeta = computeAccessKey(Call, CInfo, AccessKey, IsInt32Ret); + } else { + Base = computeBaseAndAccessKey(Call, CInfo, AccessKey, TypeMeta); + if (!Base) + return false; + } + + BasicBlock *BB = Call->getParent(); + GlobalVariable *GV; + + if (GEPGlobals.find(AccessKey) == GEPGlobals.end()) { + IntegerType *VarType; + if (IsInt32Ret) + VarType = Type::getInt32Ty(BB->getContext()); // 32bit return value + else + VarType = Type::getInt64Ty(BB->getContext()); // 64bit ptr or enum value + + GV = new GlobalVariable(*M, VarType, false, GlobalVariable::ExternalLinkage, + nullptr, AccessKey); + GV->addAttribute(SBFCoreSharedInfo::AmaAttr); + GV->setMetadata(LLVMContext::MD_preserve_access_index, TypeMeta); + GEPGlobals[AccessKey] = GV; + } else { + GV = GEPGlobals[AccessKey]; + } + + if (CInfo.Kind == SBFPreserveFieldInfoAI) { + // Load the global variable which represents the returned field info. + LoadInst *LDInst; + if (IsInt32Ret) + LDInst = new LoadInst(Type::getInt32Ty(BB->getContext()), GV, "", Call->getIterator()); + else + LDInst = new LoadInst(Type::getInt64Ty(BB->getContext()), GV, "", Call->getIterator()); + + Instruction *PassThroughInst = + SBFCoreSharedInfo::insertPassThrough(M, BB, LDInst, Call); + Call->replaceAllUsesWith(PassThroughInst); + Call->eraseFromParent(); + return true; + } + + // For any original GEP Call and Base %2 like + // %4 = bitcast %struct.net_device** %dev1 to i64* + // it is transformed to: + // %6 = load llvm.sk_buff:0:50$0:0:0:2:0 + // %7 = bitcast %struct.sk_buff* %2 to i8* + // %8 = getelementptr i8, i8* %7, %6 + // %9 = bitcast i8* %8 to i64* + // using %9 instead of %4 + // The original Call inst is removed. + + // Load the global variable. + auto *LDInst = new LoadInst(Type::getInt64Ty(BB->getContext()), GV, "", Call->getIterator()); + + // Generate a BitCast + auto *BCInst = + new BitCastInst( + Base, PointerType::get(BB->getContext(), + Base->getType()->getPointerAddressSpace())); + BCInst->insertBefore(Call->getIterator()); + + // Generate a GetElementPtr + auto *GEP = GetElementPtrInst::Create(Type::getInt8Ty(BB->getContext()), + BCInst, LDInst); + GEP->insertBefore(Call->getIterator()); + + // Generate a BitCast + auto *BCInst2 = new BitCastInst(GEP, Call->getType()); + BCInst2->insertBefore(Call->getIterator()); + + // For the following code, + // Block0: + // ... + // if (...) goto Block1 else ... + // Block1: + // %6 = load llvm.sk_buff:0:50$0:0:0:2:0 + // %7 = bitcast %struct.sk_buff* %2 to i8* + // %8 = getelementptr i8, i8* %7, %6 + // ... + // goto CommonExit + // Block2: + // ... + // if (...) goto Block3 else ... + // Block3: + // %6 = load llvm.bpf_map:0:40$0:0:0:2:0 + // %7 = bitcast %struct.sk_buff* %2 to i8* + // %8 = getelementptr i8, i8* %7, %6 + // ... + // goto CommonExit + // CommonExit + // SimplifyCFG may generate: + // Block0: + // ... + // if (...) goto Block_Common else ... + // Block2: + // ... + // if (...) goto Block_Common else ... + // Block_Common: + // PHI = [llvm.sk_buff:0:50$0:0:0:2:0, llvm.bpf_map:0:40$0:0:0:2:0] + // %6 = load PHI + // %7 = bitcast %struct.sk_buff* %2 to i8* + // %8 = getelementptr i8, i8* %7, %6 + // ... + // goto CommonExit + // For the above code, we cannot perform proper relocation since + // "load PHI" has two possible relocations. + // + // To prevent above tail merging, we use __builtin_bpf_passthrough() + // where one of its parameters is a seq_num. Since two + // __builtin_bpf_passthrough() funcs will always have different seq_num, + // tail merging cannot happen. The __builtin_bpf_passthrough() will be + // removed in the beginning of Target IR passes. + // + // This approach is also used in other places when global var + // representing a relocation is used. + Instruction *PassThroughInst = + SBFCoreSharedInfo::insertPassThrough(M, BB, BCInst2, Call); + Call->replaceAllUsesWith(PassThroughInst); + Call->eraseFromParent(); + + return true; +} + +bool SBFAbstractMemberAccess::doTransformation(Function &F) { + bool Transformed = false; + + // Collect PreserveDIAccessIndex Intrinsic call chains. + // The call chains will be used to generate the access + // patterns similar to GEP. + collectAICallChains(F); + + for (auto &C : BaseAICalls) + Transformed = transformGEPChain(C.first, C.second) || Transformed; + + return removePreserveAccessIndexIntrinsic(F) || Transformed; +} + +PreservedAnalyses +SBFAbstractMemberAccessPass::run(Function &F, FunctionAnalysisManager &AM) { + return SBFAbstractMemberAccess(TM).run(F) ? PreservedAnalyses::none() + : PreservedAnalyses::all(); +} diff --git a/llvm/lib/Target/SBF/SBFAsmPrinter.cpp b/llvm/lib/Target/SBF/SBFAsmPrinter.cpp new file mode 100644 index 0000000000000..b37cf78c7a8b0 --- /dev/null +++ b/llvm/lib/Target/SBF/SBFAsmPrinter.cpp @@ -0,0 +1,162 @@ +//===-- SBFAsmPrinter.cpp - SBF LLVM assembly writer ----------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// +// +// This file contains a printer that converts from our internal representation +// of machine-dependent LLVM code to the SBF assembly language. +// +//===----------------------------------------------------------------------===// + +#include "SBF.h" +#include "SBFInstrInfo.h" +#include "SBFMCInstLower.h" +#include "BTFDebug.h" +#include "MCTargetDesc/SBFInstPrinter.h" +#include "MCTargetDesc/SBFMCTargetDesc.h" +#include "TargetInfo/SBFTargetInfo.h" +#include "llvm/CodeGen/AsmPrinter.h" +#include "llvm/CodeGen/MachineConstantPool.h" +#include "llvm/CodeGen/MachineInstr.h" +#include "llvm/CodeGen/MachineModuleInfo.h" +#include "llvm/IR/Module.h" +#include "llvm/MC/MCAsmInfo.h" +#include "llvm/MC/MCInst.h" +#include "llvm/MC/MCStreamer.h" +#include "llvm/MC/MCSymbol.h" +#include "llvm/MC/TargetRegistry.h" +#include "llvm/Support/raw_ostream.h" +using namespace llvm; + +#define DEBUG_TYPE "asm-printer" + +static cl::opt SBFEnableBTFEmission( + "sbf-enable-btf-emission", cl::Hidden, cl::init(false), + cl::desc("Enable BTF debuginfo sections to be emitted")); + +namespace { +class SBFAsmPrinter : public AsmPrinter { +public: + explicit SBFAsmPrinter(TargetMachine &TM, + std::unique_ptr Streamer) + : AsmPrinter(TM, std::move(Streamer)), BTF(nullptr) {} + + StringRef getPassName() const override { return "SBF Assembly Printer"; } + bool doInitialization(Module &M) override; + void printOperand(const MachineInstr *MI, int OpNum, raw_ostream &O); + bool PrintAsmOperand(const MachineInstr *MI, unsigned OpNo, + const char *ExtraCode, raw_ostream &O) override; + bool PrintAsmMemoryOperand(const MachineInstr *MI, unsigned OpNum, + const char *ExtraCode, raw_ostream &O) override; + + void emitInstruction(const MachineInstr *MI) override; + +private: + BTFX::BTFDebug *BTF; +}; +} // namespace + +bool SBFAsmPrinter::doInitialization(Module &M) { + AsmPrinter::doInitialization(M); + + // Only emit BTF when debuginfo available. + // Unsupported for Solana: + // https://github.com/anza-xyz/llvm-project/issues/37 + if (MAI->doesSupportDebugInformation() && !M.debug_compile_units().empty() && + SBFEnableBTFEmission) { + BTF = new BTFX::BTFDebug(this); + Handlers.push_back(std::unique_ptr(BTF)); + } + + return false; +} + +void SBFAsmPrinter::printOperand(const MachineInstr *MI, int OpNum, + raw_ostream &O) { + const MachineOperand &MO = MI->getOperand(OpNum); + + switch (MO.getType()) { + case MachineOperand::MO_Register: + O << SBFInstPrinter::getRegisterName(MO.getReg()); + break; + + case MachineOperand::MO_Immediate: + O << MO.getImm(); + break; + + case MachineOperand::MO_MachineBasicBlock: + O << *MO.getMBB()->getSymbol(); + break; + + case MachineOperand::MO_GlobalAddress: + O << *getSymbol(MO.getGlobal()); + break; + + case MachineOperand::MO_BlockAddress: { + MCSymbol *BA = GetBlockAddressSymbol(MO.getBlockAddress()); + O << BA->getName(); + break; + } + + case MachineOperand::MO_ExternalSymbol: + O << *GetExternalSymbolSymbol(MO.getSymbolName()); + break; + + case MachineOperand::MO_JumpTableIndex: + case MachineOperand::MO_ConstantPoolIndex: + default: + llvm_unreachable(""); + } +} + +bool SBFAsmPrinter::PrintAsmOperand(const MachineInstr *MI, unsigned OpNo, + const char *ExtraCode, raw_ostream &O) { + if (ExtraCode && ExtraCode[0]) + return AsmPrinter::PrintAsmOperand(MI, OpNo, ExtraCode, O); + + printOperand(MI, OpNo, O); + return false; +} + +bool SBFAsmPrinter::PrintAsmMemoryOperand(const MachineInstr *MI, + unsigned OpNum, const char *ExtraCode, + raw_ostream &O) { + assert(OpNum + 1 < MI->getNumOperands() && "Insufficient operands"); + const MachineOperand &BaseMO = MI->getOperand(OpNum); + const MachineOperand &OffsetMO = MI->getOperand(OpNum + 1); + assert(BaseMO.isReg() && "Unexpected base pointer for inline asm memory operand."); + assert(OffsetMO.isImm() && "Unexpected offset for inline asm memory operand."); + int Offset = OffsetMO.getImm(); + + if (ExtraCode) + return true; // Unknown modifier. + + O << SBFInstPrinter::getRegisterName(BaseMO.getReg()); + if (Offset < 0) + O << " - " << -Offset; + else + O << " + " << Offset; + + return false; +} + +void SBFAsmPrinter::emitInstruction(const MachineInstr *MI) { + SBF_MC::verifyInstructionPredicates(MI->getOpcode(), + getSubtargetInfo().getFeatureBits()); + + MCInst TmpInst; + + if (!BTF || !BTF->InstLower(MI, TmpInst)) { + SBFMCInstLower MCInstLowering(OutContext, *this); + MCInstLowering.Lower(MI, TmpInst); + } + EmitToStreamer(*OutStreamer, TmpInst); +} + +// Force static initialization. +extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeSBFAsmPrinter() { + RegisterAsmPrinter XX(getTheSBFXTarget()); +} diff --git a/llvm/lib/Target/SBF/SBFCORE.h b/llvm/lib/Target/SBF/SBFCORE.h new file mode 100644 index 0000000000000..a6041218bea32 --- /dev/null +++ b/llvm/lib/Target/SBF/SBFCORE.h @@ -0,0 +1,78 @@ +//===- SBFCORE.h - Common info for Compile-Once Run-EveryWhere -*- 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 +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIB_TARGET_SBF_SBFCORE_H +#define LLVM_LIB_TARGET_SBF_SBFCORE_H + +#include "llvm/ADT/StringRef.h" + +namespace llvm { + +class BasicBlock; +class Instruction; +class Module; + +class SBFCoreSharedInfo { +public: + enum PatchableRelocKind : uint32_t { + FIELD_BYTE_OFFSET = 0, + FIELD_BYTE_SIZE, + FIELD_EXISTENCE, + FIELD_SIGNEDNESS, + FIELD_LSHIFT_U64, + FIELD_RSHIFT_U64, + BTF_TYPE_ID_LOCAL, + BTF_TYPE_ID_REMOTE, + TYPE_EXISTENCE, + TYPE_SIZE, + ENUM_VALUE_EXISTENCE, + ENUM_VALUE, + TYPE_MATCH, + + MAX_FIELD_RELOC_KIND, + }; + + enum BTFTypeIdFlag : uint32_t { + BTF_TYPE_ID_LOCAL_RELOC = 0, + BTF_TYPE_ID_REMOTE_RELOC, + + MAX_BTF_TYPE_ID_FLAG, + }; + + enum PreserveTypeInfo : uint32_t { + PRESERVE_TYPE_INFO_EXISTENCE = 0, + PRESERVE_TYPE_INFO_SIZE, + PRESERVE_TYPE_INFO_MATCH, + + MAX_PRESERVE_TYPE_INFO_FLAG, + }; + + enum PreserveEnumValue : uint32_t { + PRESERVE_ENUM_VALUE_EXISTENCE = 0, + PRESERVE_ENUM_VALUE, + + MAX_PRESERVE_ENUM_VALUE_FLAG, + }; + + /// The attribute attached to globals representing a field access + static constexpr StringRef AmaAttr = "btf_ama"; + /// The attribute attached to globals representing a type id + static constexpr StringRef TypeIdAttr = "btf_type_id"; + + /// llvm.bpf.passthrough builtin seq number + static uint32_t SeqNum; + + /// Insert a bpf passthrough builtin function. + static Instruction *insertPassThrough(Module *M, BasicBlock *BB, + Instruction *Input, + Instruction *Before); +}; + +} // namespace llvm + +#endif diff --git a/llvm/lib/Target/SBF/SBFCallingConv.td b/llvm/lib/Target/SBF/SBFCallingConv.td new file mode 100644 index 0000000000000..877c8bdb92c82 --- /dev/null +++ b/llvm/lib/Target/SBF/SBFCallingConv.td @@ -0,0 +1,68 @@ +//===-- SBFCallingConv.td - Calling Conventions SBF --------*- tablegen -*-===// +// +// 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 +// +//===----------------------------------------------------------------------===// +// +// This describes the calling conventions for the SBF architecture. +// +//===----------------------------------------------------------------------===// + +// SBF 64-bit C return-value convention. +def RetCC_SBF64 : CallingConv<[CCIfType<[i64], CCAssignToReg<[R0]>>]>; + +// SBF 64-bit C Calling convention. +def CC_SBF64 : CallingConv<[ + // Promote i8/i16/i32 args to i64 + CCIfType<[ i8, i16, i32 ], CCPromoteToType>, + + // All arguments get passed in integer registers if there is space. + CCIfType<[i64], CCAssignToReg<[ R1, R2, R3, R4, R5 ]>>, + + // Could be assigned to the stack in 8-byte aligned units, but unsupported + CCAssignToStack<8, 8> +]>; + +def CC_SBF64_X : CallingConv<[ + CCIfType<[ i8, i16, i32 ], CCPromoteToType>, + + // Skip R5 register, reserved for passing frame pointer. + CCIfType<[i64], CCAssignToReg<[R1, R2, R3, R4]>>, + + CCAssignToStack<8, 8> +]>; + +// Return-value convention when -mattr=+alu32 enabled +def RetCC_SBF32 : CallingConv<[ + CCIfType<[i32], CCAssignToRegWithShadow<[W0], [R0]>>, + CCIfType<[i64], CCAssignToRegWithShadow<[R0], [W0]>> +]>; + +// Calling convention when -mattr=+alu32 enabled +def CC_SBF32 : CallingConv<[ + // Promote i8/i16/i32 args to i64 + CCIfType<[i32], CCAssignToRegWithShadow<[W1, W2, W3, W4, W5], + [R1, R2, R3, R4, R5]>>, + + // All arguments get passed in integer registers if there is space. + CCIfType<[i64], CCAssignToRegWithShadow<[R1, R2, R3, R4, R5], + [W1, W2, W3, W4, W5]>>, + + // Could be assigned to the stack in 8-byte aligned units, but unsupported + CCAssignToStack<8, 8> +]>; + +def CC_SBF32_X : CallingConv<[ + // Skip R5 register, reserved for passing frame pointer. + CCIfType<[i32], CCAssignToRegWithShadow<[W1, W2, W3, W4], + [R1, R2, R3, R4]>>, + + CCIfType<[i64], CCAssignToRegWithShadow<[R1, R2, R3, R4], + [W1, W2, W3, W4]>>, + + CCAssignToStack<8, 8> +]>; + +def CSR : CalleeSavedRegs<(add R6, R7, R8, R9, R10)>; diff --git a/llvm/lib/Target/SBF/SBFCheckAndAdjustIR.cpp b/llvm/lib/Target/SBF/SBFCheckAndAdjustIR.cpp new file mode 100644 index 0000000000000..4313726891005 --- /dev/null +++ b/llvm/lib/Target/SBF/SBFCheckAndAdjustIR.cpp @@ -0,0 +1,125 @@ +//===------------ SBFCheckAndAdjustIR.cpp - Check and Adjust IR -----------===// +// +// 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 +// +//===----------------------------------------------------------------------===// +// +// Check IR and adjust IR for verifier friendly codes. +// The following are done for IR checking: +// - no relocation globals in PHI node. +// The following are done for IR adjustment: +// - remove __builtin_bpf_passthrough builtins. Target independent IR +// optimizations are done and those builtins can be removed. +// +//===----------------------------------------------------------------------===// + +#include "SBF.h" +#include "SBFCORE.h" +#include "llvm/IR/DebugInfoMetadata.h" +#include "llvm/IR/GlobalVariable.h" +#include "llvm/IR/Instructions.h" +#include "llvm/IR/Module.h" +#include "llvm/IR/Value.h" +#include "llvm/Pass.h" + +#define DEBUG_TYPE "sbf-check-and-opt-ir" + +using namespace llvm; + +namespace { + +class SBFCheckAndAdjustIR final : public ModulePass { + bool runOnModule(Module &F) override; + +public: + static char ID; + SBFCheckAndAdjustIR() : ModulePass(ID) {} + +private: + void checkIR(Module &M); + bool adjustIR(Module &M); + bool removePassThroughBuiltin(Module &M); +}; +} // End anonymous namespace + +char SBFCheckAndAdjustIR::ID = 0; +INITIALIZE_PASS(SBFCheckAndAdjustIR, DEBUG_TYPE, "SBF Check And Adjust IR", + false, false) + +ModulePass *llvm::createSBFCheckAndAdjustIR() { + return new SBFCheckAndAdjustIR(); +} + +void SBFCheckAndAdjustIR::checkIR(Module &M) { + // Ensure relocation global won't appear in PHI node + // This may happen if the compiler generated the following code: + // B1: + // g1 = @llvm.skb_buff:0:1... + // ... + // goto B_COMMON + // B2: + // g2 = @llvm.skb_buff:0:2... + // ... + // goto B_COMMON + // B_COMMON: + // g = PHI(g1, g2) + // x = load g + // ... + // If anything likes the above "g = PHI(g1, g2)", issue a fatal error. + for (Function &F : M) + for (auto &BB : F) + for (auto &I : BB) { + PHINode *PN = dyn_cast(&I); + if (!PN || PN->use_empty()) + continue; + for (int i = 0, e = PN->getNumIncomingValues(); i < e; ++i) { + auto *GV = dyn_cast(PN->getIncomingValue(i)); + if (!GV) + continue; + if (GV->hasAttribute(SBFCoreSharedInfo::AmaAttr) || + GV->hasAttribute(SBFCoreSharedInfo::TypeIdAttr)) + report_fatal_error("relocation global in PHI node"); + } + } +} + +bool SBFCheckAndAdjustIR::removePassThroughBuiltin(Module &M) { + // Remove __builtin_bpf_passthrough()'s which are used to prevent + // certain IR optimizations. Now major IR optimizations are done, + // remove them. + bool Changed = false; + CallInst *ToBeDeleted = nullptr; + for (Function &F : M) + for (auto &BB : F) + for (auto &I : BB) { + if (ToBeDeleted) { + ToBeDeleted->eraseFromParent(); + ToBeDeleted = nullptr; + } + + auto *Call = dyn_cast(&I); + if (!Call) + continue; + auto *GV = dyn_cast(Call->getCalledOperand()); + if (!GV) + continue; + if (!GV->getName().starts_with("llvm.bpf.passthrough")) + continue; + Changed = true; + Value *Arg = Call->getArgOperand(1); + Call->replaceAllUsesWith(Arg); + ToBeDeleted = Call; + } + return Changed; +} + +bool SBFCheckAndAdjustIR::adjustIR(Module &M) { + return removePassThroughBuiltin(M); +} + +bool SBFCheckAndAdjustIR::runOnModule(Module &M) { + checkIR(M); + return adjustIR(M); +} diff --git a/llvm/lib/Target/SBF/SBFFrameLowering.cpp b/llvm/lib/Target/SBF/SBFFrameLowering.cpp new file mode 100644 index 0000000000000..f8df8175b96cc --- /dev/null +++ b/llvm/lib/Target/SBF/SBFFrameLowering.cpp @@ -0,0 +1,51 @@ +//===-- SBFFrameLowering.cpp - SBF Frame Information ----------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// +// +// This file contains the SBF implementation of TargetFrameLowering class. +// +//===----------------------------------------------------------------------===// + +#include "SBFFrameLowering.h" +#include "SBFSubtarget.h" +#include "llvm/CodeGen/MachineFrameInfo.h" +#include "llvm/CodeGen/MachineFunction.h" + +using namespace llvm; + +bool SBFFrameLowering::hasFPImpl(const MachineFunction &MF) const { return true; } + +void SBFFrameLowering::emitPrologue(MachineFunction &MF, + MachineBasicBlock &MBB) const { + if (!MF.getSubtarget().getHasDynamicFrames()) { + return; + } + MachineBasicBlock::iterator MBBI = MBB.begin(); + MachineFrameInfo &MFI = MF.getFrameInfo(); + int NumBytes = (int)MFI.getStackSize(); + if (NumBytes || MF.getSubtarget().getHasStaticSyscalls()) { + DebugLoc Dl = MBBI->getDebugLoc(); + const SBFInstrInfo &TII = + *static_cast(MF.getSubtarget().getInstrInfo()); + BuildMI(MBB, MBBI, Dl, TII.get(SBF::ADD_ri), SBF::R10) + .addReg(SBF::R10) + .addImm(-NumBytes); + } +} + +void SBFFrameLowering::emitEpilogue(MachineFunction &MF, + MachineBasicBlock &MBB) const {} + +void SBFFrameLowering::determineCalleeSaves(MachineFunction &MF, + BitVector &SavedRegs, + RegScavenger *RS) const { + TargetFrameLowering::determineCalleeSaves(MF, SavedRegs, RS); + SavedRegs.reset(SBF::R6); + SavedRegs.reset(SBF::R7); + SavedRegs.reset(SBF::R8); + SavedRegs.reset(SBF::R9); +} diff --git a/llvm/lib/Target/SBF/SBFFrameLowering.h b/llvm/lib/Target/SBF/SBFFrameLowering.h new file mode 100644 index 0000000000000..192513ca20260 --- /dev/null +++ b/llvm/lib/Target/SBF/SBFFrameLowering.h @@ -0,0 +1,44 @@ +//===-- SBFFrameLowering.h - Define frame lowering for SBF -----*- 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 +// +//===----------------------------------------------------------------------===// +// +// This class implements SBF-specific bits of TargetFrameLowering class. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIB_TARGET_SBF_SBFFRAMELOWERING_H +#define LLVM_LIB_TARGET_SBF_SBFFRAMELOWERING_H + +#include "llvm/CodeGen/TargetFrameLowering.h" + +namespace llvm { +class SBFSubtarget; + +class SBFFrameLowering : public TargetFrameLowering { +public: + explicit SBFFrameLowering(const SBFSubtarget &sti) + : TargetFrameLowering( + TargetFrameLowering::StackGrowsDown, + Align(64), + 0, + Align(64)) {} + + void emitPrologue(MachineFunction &MF, MachineBasicBlock &MBB) const override; + void emitEpilogue(MachineFunction &MF, MachineBasicBlock &MBB) const override; + + bool hasFPImpl(const MachineFunction &MF) const override; + void determineCalleeSaves(MachineFunction &MF, BitVector &SavedRegs, + RegScavenger *RS) const override; + + MachineBasicBlock::iterator + eliminateCallFramePseudoInstr(MachineFunction &MF, MachineBasicBlock &MBB, + MachineBasicBlock::iterator MI) const override { + return MBB.erase(MI); + } +}; +} +#endif diff --git a/llvm/lib/Target/SBF/SBFFunctionInfo.cpp b/llvm/lib/Target/SBF/SBFFunctionInfo.cpp new file mode 100644 index 0000000000000..d3c494ae2f347 --- /dev/null +++ b/llvm/lib/Target/SBF/SBFFunctionInfo.cpp @@ -0,0 +1,28 @@ +//=- SBFFunctionInfo.cpp - SBF Machine Function Info ---------=// + +// +// 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 +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// This file implements SBF-specific per-machine-function +/// information. +/// +//===----------------------------------------------------------------------===// + +#include "SBFFunctionInfo.h" + +namespace llvm { + +void SBFFunctionInfo::storeFrameIndexArgument(int FI) { + frameIndexes.insert(FI); +} + +bool SBFFunctionInfo::containsFrameIndex(int FI) const { + return frameIndexes.find(FI) != frameIndexes.end(); +} + +} // namespace llvm \ No newline at end of file diff --git a/llvm/lib/Target/SBF/SBFFunctionInfo.h b/llvm/lib/Target/SBF/SBFFunctionInfo.h new file mode 100644 index 0000000000000..2316d965366b7 --- /dev/null +++ b/llvm/lib/Target/SBF/SBFFunctionInfo.h @@ -0,0 +1,32 @@ +//=- SBFFunctionInfo.h - SBF machine function info -*- 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 +// +//===----------------------------------------------------------------------===// +// +// This file declares SBF-specific per-machine-function information. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_SBFFUNCTIONINFO_H +#define LLVM_SBFFUNCTIONINFO_H + +#include "SBFSubtarget.h" +#include + +namespace llvm { + +class SBFFunctionInfo final : public MachineFunctionInfo { + std::unordered_set frameIndexes; + +public: + SBFFunctionInfo(const Function &F, const SBFSubtarget *STI){}; + + void storeFrameIndexArgument(int FI); + bool containsFrameIndex(int FI) const; +}; +} // namespace llvm + +#endif // LLVM_SBFFUNCTIONINFO_H \ No newline at end of file diff --git a/llvm/lib/Target/SBF/SBFIRPeephole.cpp b/llvm/lib/Target/SBF/SBFIRPeephole.cpp new file mode 100644 index 0000000000000..f51de89cc5ad7 --- /dev/null +++ b/llvm/lib/Target/SBF/SBFIRPeephole.cpp @@ -0,0 +1,101 @@ +//===------------ SBFIRPeephole.cpp - IR Peephole Transformation ----------===// +// +// 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 +// +//===----------------------------------------------------------------------===// +// +// IR level peephole optimization, specifically removing @llvm.stacksave() and +// @llvm.stackrestore(). +// +//===----------------------------------------------------------------------===// + +#include "SBF.h" +#include "llvm/IR/Instruction.h" +#include "llvm/IR/Instructions.h" +#include "llvm/IR/Module.h" +#include "llvm/IR/PassManager.h" +#include "llvm/IR/Value.h" +#include "llvm/Pass.h" + +#define DEBUG_TYPE "sbf-ir-peephole" + +using namespace llvm; + +namespace { + +static bool SBFIRPeepholeImpl(Function &F) { + LLVM_DEBUG(dbgs() << "******** SBF IR Peephole ********\n"); + + bool Changed = false; + Instruction *ToErase = nullptr; + for (auto &BB : F) { + for (auto &I : BB) { + // The following code pattern is handled: + // %3 = call i8* @llvm.stacksave() + // store i8* %3, i8** %saved_stack, align 8 + // ... + // %4 = load i8*, i8** %saved_stack, align 8 + // call void @llvm.stackrestore(i8* %4) + // ... + // The goal is to remove the above four instructions, + // so we won't have instructions with r11 (stack pointer) + // if eventually there is no variable length stack allocation. + // InstrCombine also tries to remove the above instructions, + // if it is proven safe (constant alloca etc.), but depending + // on code pattern, it may still miss some. + // + // With unconditionally removing these instructions, if alloca is + // constant, we are okay then. Otherwise, SelectionDag will complain + // since SBF does not support dynamic allocation yet. + if (ToErase) { + ToErase->eraseFromParent(); + ToErase = nullptr; + } + + if (auto *Call = dyn_cast(&I)) { + if (auto *GV = dyn_cast(Call->getCalledOperand())) { + if (GV->getName() != "llvm.stacksave") + continue; + if (!Call->hasOneUser()) + continue; + auto *Inst = cast(*Call->user_begin()); + LLVM_DEBUG(dbgs() << "Remove:"; I.dump()); + LLVM_DEBUG(dbgs() << "Remove:"; Inst->dump(); dbgs() << '\n'); + Changed = true; + Inst->eraseFromParent(); + ToErase = &I; + } + continue; + } + + if (auto *LD = dyn_cast(&I)) { + if (!LD->hasOneUser()) + continue; + auto *Call = dyn_cast(*LD->user_begin()); + if (!Call) + continue; + auto *GV = dyn_cast(Call->getCalledOperand()); + if (!GV) + continue; + if (GV->getName() != "llvm.stackrestore") + continue; + LLVM_DEBUG(dbgs() << "Remove:"; I.dump()); + LLVM_DEBUG(dbgs() << "Remove:"; Call->dump(); dbgs() << '\n'); + Changed = true; + Call->eraseFromParent(); + ToErase = &I; + } + } + } + + return Changed; +} +} // End anonymous namespace + +PreservedAnalyses SBFIRPeepholePass::run(Function &F, + FunctionAnalysisManager &AM) { + return SBFIRPeepholeImpl(F) ? PreservedAnalyses::none() + : PreservedAnalyses::all(); +} diff --git a/llvm/lib/Target/SBF/SBFISelDAGToDAG.cpp b/llvm/lib/Target/SBF/SBFISelDAGToDAG.cpp new file mode 100644 index 0000000000000..898bb23c8c425 --- /dev/null +++ b/llvm/lib/Target/SBF/SBFISelDAGToDAG.cpp @@ -0,0 +1,478 @@ +//===-- SBFISelDAGToDAG.cpp - A dag to dag inst selector for SBF ----------===// +// +// 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 +// +//===----------------------------------------------------------------------===// +// +// This file defines a DAG pattern matching instruction selector for SBF, +// converting from a legalized dag to a SBF dag. +// +//===----------------------------------------------------------------------===// + +#include "SBF.h" +#include "SBFSubtarget.h" +#include "SBFTargetMachine.h" +#include "llvm/CodeGen/FunctionLoweringInfo.h" +#include "llvm/CodeGen/MachineConstantPool.h" +#include "llvm/CodeGen/MachineFrameInfo.h" +#include "llvm/CodeGen/MachineFunction.h" +#include "llvm/CodeGen/SelectionDAGISel.h" +#include "llvm/IR/Constants.h" +#include "llvm/IR/IntrinsicInst.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/Endian.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/raw_ostream.h" + +using namespace llvm; + +#define DEBUG_TYPE "sbf-isel" +#define PASS_NAME "SBF DAG->DAG Pattern Instruction Selection" + +// Instruction Selector Implementation +namespace { + +class SBFDAGToDAGISel : public SelectionDAGISel { + + /// Subtarget - Keep a pointer to the SBFSubtarget around so that we can + /// make the right decision when generating code for different subtargets. + const SBFSubtarget *Subtarget; + +public: + SBFDAGToDAGISel() = delete; + + explicit SBFDAGToDAGISel(SBFTargetMachine &TM) + : SelectionDAGISel(TM), Subtarget(nullptr) {} + + bool runOnMachineFunction(MachineFunction &MF) override { + // Reset the subtarget each time through. + Subtarget = &MF.getSubtarget(); + return SelectionDAGISel::runOnMachineFunction(MF); + } + + void PreprocessISelDAG() override; + + bool SelectInlineAsmMemoryOperand(const SDValue &Op, + InlineAsm::ConstraintCode ConstraintCode, + std::vector &OutOps) override; + + +private: +// Include the pieces autogenerated from the target description. +#include "SBFGenDAGISel.inc" + + void Select(SDNode *N) override; + + // Complex Pattern for address selection. + bool SelectAddr(SDValue Addr, SDValue &Base, SDValue &Offset); + bool SelectFIAddr(SDValue Addr, SDValue &Base, SDValue &Offset); + + // Node preprocessing cases + void PreprocessLoad(SDNode *Node, SelectionDAG::allnodes_iterator &I); + + // Find constants from a constant structure + typedef std::vector val_vec_type; + bool fillGenericConstant(const DataLayout &DL, const Constant *CV, + val_vec_type &Vals, uint64_t Offset); + bool fillConstantDataArray(const DataLayout &DL, const ConstantDataArray *CDA, + val_vec_type &Vals, int Offset); + bool fillConstantArray(const DataLayout &DL, const ConstantArray *CA, + val_vec_type &Vals, int Offset); + bool fillConstantStruct(const DataLayout &DL, const ConstantStruct *CS, + val_vec_type &Vals, int Offset); + bool getConstantFieldValue(const GlobalAddressSDNode *Node, uint64_t Offset, + uint64_t Size, unsigned char *ByteSeq); + // Mapping from ConstantStruct global value to corresponding byte-list values + std::map cs_vals_; +}; + +class SBFDAGToDAGISelLegacy : public SelectionDAGISelLegacy { +public: + static char ID; + SBFDAGToDAGISelLegacy(SBFTargetMachine &TM) + : SelectionDAGISelLegacy(ID, std::make_unique(TM)) {} +}; +} // namespace + +char SBFDAGToDAGISelLegacy::ID = 0; + +INITIALIZE_PASS(SBFDAGToDAGISelLegacy, DEBUG_TYPE, PASS_NAME, false, false) + +// ComplexPattern used on SBF Load/Store instructions +bool SBFDAGToDAGISel::SelectAddr(SDValue Addr, SDValue &Base, SDValue &Offset) { + // if Address is FI, get the TargetFrameIndex. + SDLoc DL(Addr); + if (auto *FIN = dyn_cast(Addr)) { + Base = CurDAG->getTargetFrameIndex(FIN->getIndex(), MVT::i64); + Offset = CurDAG->getTargetConstant(0, DL, MVT::i64); + return true; + } + + if (Addr.getOpcode() == ISD::TargetExternalSymbol || + Addr.getOpcode() == ISD::TargetGlobalAddress) + return false; + + // Addresses of the form Addr+const or Addr|const + if (CurDAG->isBaseWithConstantOffset(Addr)) { + auto *CN = cast(Addr.getOperand(1)); + if (isInt<16>(CN->getSExtValue())) { + // If the first operand is a FI, get the TargetFI Node + if (auto *FIN = dyn_cast(Addr.getOperand(0))) + Base = CurDAG->getTargetFrameIndex(FIN->getIndex(), MVT::i64); + else + Base = Addr.getOperand(0); + + Offset = CurDAG->getTargetConstant(CN->getSExtValue(), DL, MVT::i64); + return true; + } + } + + Base = Addr; + Offset = CurDAG->getTargetConstant(0, DL, MVT::i64); + return true; +} + +// ComplexPattern used on SBF FI instruction +bool SBFDAGToDAGISel::SelectFIAddr(SDValue Addr, SDValue &Base, + SDValue &Offset) { + SDLoc DL(Addr); + + if (!CurDAG->isBaseWithConstantOffset(Addr)) + return false; + + // Addresses of the form Addr+const or Addr|const + auto *CN = cast(Addr.getOperand(1)); + if (isInt<16>(CN->getSExtValue())) { + // If the first operand is a FI, get the TargetFI Node + if (auto *FIN = dyn_cast(Addr.getOperand(0))) + Base = CurDAG->getTargetFrameIndex(FIN->getIndex(), MVT::i64); + else + return false; + + Offset = CurDAG->getTargetConstant(CN->getSExtValue(), DL, MVT::i64); + return true; + } + + return false; +} + +bool SBFDAGToDAGISel::SelectInlineAsmMemoryOperand( + const SDValue &Op, InlineAsm::ConstraintCode ConstraintCode, + std::vector &OutOps) { + SDValue Op0, Op1; + switch (ConstraintCode) { + default: + return true; + case InlineAsm::ConstraintCode::m: // memory + if (!SelectAddr(Op, Op0, Op1)) + return true; + break; + } + + SDLoc DL(Op); + SDValue AluOp = CurDAG->getTargetConstant(ISD::ADD, DL, MVT::i32); + OutOps.push_back(Op0); + OutOps.push_back(Op1); + OutOps.push_back(AluOp); + return false; +} + +void SBFDAGToDAGISel::Select(SDNode *Node) { + unsigned Opcode = Node->getOpcode(); + + // If we have a custom node, we already have selected! + if (Node->isMachineOpcode()) { + LLVM_DEBUG(dbgs() << "== "; Node->dump(CurDAG); dbgs() << '\n'); + return; + } + + // tablegen selection should be handled here. + switch (Opcode) { + default: + break; + + case ISD::FrameIndex: { + int FI = cast(Node)->getIndex(); + EVT VT = Node->getValueType(0); + SDValue TFI = CurDAG->getTargetFrameIndex(FI, VT); + unsigned Opc = SBF::MOV_rr; + if (Node->hasOneUse()) { + CurDAG->SelectNodeTo(Node, Opc, VT, TFI); + return; + } + ReplaceNode(Node, CurDAG->getMachineNode(Opc, SDLoc(Node), VT, TFI)); + return; + } + } + + // Select the default instruction + SelectCode(Node); +} + +void SBFDAGToDAGISel::PreprocessLoad(SDNode *Node, + SelectionDAG::allnodes_iterator &I) { + union { + uint8_t c[8]; + uint16_t s; + uint32_t i; + uint64_t d; + } new_val; // hold up the constant values replacing loads. + bool to_replace = false; + SDLoc DL(Node); + const LoadSDNode *LD = cast(Node); + if (!LD->getMemOperand()->getSize().hasValue()) + return; + uint64_t size = LD->getMemOperand()->getSize().getValue(); + + if (!size || size > 8 || (size & (size - 1)) || !LD->isSimple()) + return; + + SDNode *LDAddrNode = LD->getOperand(1).getNode(); + // Match LDAddr against either global_addr or (global_addr + offset) + unsigned opcode = LDAddrNode->getOpcode(); + if (opcode == ISD::ADD) { + SDValue OP1 = LDAddrNode->getOperand(0); + SDValue OP2 = LDAddrNode->getOperand(1); + + // We want to find the pattern global_addr + offset + SDNode *OP1N = OP1.getNode(); + if (OP1N->getOpcode() <= ISD::BUILTIN_OP_END || OP1N->getNumOperands() == 0) + return; + + LLVM_DEBUG(dbgs() << "Check candidate load: "; LD->dump(); dbgs() << '\n'); + + const GlobalAddressSDNode *GADN = + dyn_cast(OP1N->getOperand(0).getNode()); + const ConstantSDNode *CDN = dyn_cast(OP2.getNode()); + if (GADN && CDN) + to_replace = + getConstantFieldValue(GADN, CDN->getZExtValue(), size, new_val.c); + } else if (LDAddrNode->getOpcode() > ISD::BUILTIN_OP_END && + LDAddrNode->getNumOperands() > 0) { + LLVM_DEBUG(dbgs() << "Check candidate load: "; LD->dump(); dbgs() << '\n'); + + SDValue OP1 = LDAddrNode->getOperand(0); + if (const GlobalAddressSDNode *GADN = + dyn_cast(OP1.getNode())) + to_replace = getConstantFieldValue(GADN, 0, size, new_val.c); + } + + if (!to_replace) + return; + + // replacing the old with a new value + uint64_t val; + if (size == 1) + val = new_val.c[0]; + else if (size == 2) + val = new_val.s; + else if (size == 4) + val = new_val.i; + else { + val = new_val.d; + } + + LLVM_DEBUG(dbgs() << "Replacing load of size " << size << " with constant " + << val << '\n'); + + /* Some load nodes have edges from TokenFactor nodes. In this case + replacing the load with a constant makes the DAG disconnected. + The following checks if any of the load operands are TokenFactor + nodes, and if another TokenFactor is a user of the load, the + operand TokenFactor is connected to the user, so that the DAG + remains connected after replacing the load node by a constant. + */ + for (unsigned I = 0, E = Node->getNumOperands(); I != E; ++I) { + const SDValue &OpV = Node->getOperand(I); + SDNode *Op = OpV.getNode(); + if (Op->getOpcode() == ISD::TokenFactor) { + for (SDNode::use_iterator UI = Node->use_begin(), UE = Node->use_end(); UI != UE; ++UI) { + SDNode *User = UI->getUser(); + if (User->getOpcode() == ISD::TokenFactor) { + SmallVector ExtendedOps; + bool NotExtended = true; + for (unsigned UOI = 0, UOE = User->getNumOperands(); UOI != UOE; ++UOI) { + const SDValue &Operand = User->getOperand(UOI); + if (OpV == Operand) { + NotExtended = false; + break; + } + ExtendedOps.push_back(Operand); + } + if (NotExtended) { + ExtendedOps.push_back(OpV); + SDValue ExtendedTokenFactor = CurDAG->getTokenFactor(SDLoc(User), ExtendedOps); + I--; + SDValue From[] = {SDValue(User, 0)}; + SDValue To[] = {ExtendedTokenFactor}; + CurDAG->ReplaceAllUsesOfValuesWith(From, To, 1); + I++; + CurDAG->DeleteNode(User); + } + } + } + } + } + + SDValue NVal = CurDAG->getConstant(val, DL, LD->getValueType(0)); + + // After replacement, the current node is dead, we need to + // go backward one step to make iterator still work + I--; + SDValue From[] = {SDValue(Node, 0), SDValue(Node, 1)}; + SDValue To[] = {NVal, NVal}; + CurDAG->ReplaceAllUsesOfValuesWith(From, To, 2); + I++; + // It is safe to delete node now + CurDAG->DeleteNode(Node); +} + +void SBFDAGToDAGISel::PreprocessISelDAG() { + // Iterate through all nodes, interested in the following case: + // + // . loads from ConstantStruct or ConstantArray of constructs + // which can be turns into constant itself, with this we can + // avoid reading from read-only section at runtime. + // + // . Removing redundant AND for intrinsic narrow loads. + for (SelectionDAG::allnodes_iterator I = CurDAG->allnodes_begin(), + E = CurDAG->allnodes_end(); + I != E;) { + SDNode *Node = &*I++; + unsigned Opcode = Node->getOpcode(); + if (Opcode == ISD::LOAD) + PreprocessLoad(Node, I); + } +} + +bool SBFDAGToDAGISel::getConstantFieldValue(const GlobalAddressSDNode *Node, + uint64_t Offset, uint64_t Size, + unsigned char *ByteSeq) { + const GlobalVariable *V = dyn_cast(Node->getGlobal()); + + if (!V || !V->hasInitializer() || !V->isConstant()) + return false; + + const Constant *Init = V->getInitializer(); + const DataLayout &DL = CurDAG->getDataLayout(); + val_vec_type TmpVal; + + auto it = cs_vals_.find(static_cast(Init)); + if (it != cs_vals_.end()) { + TmpVal = it->second; + } else { + uint64_t total_size = 0; + if (const ConstantStruct *CS = dyn_cast(Init)) + total_size = + DL.getStructLayout(cast(CS->getType()))->getSizeInBytes(); + else if (const ConstantArray *CA = dyn_cast(Init)) + total_size = DL.getTypeAllocSize(CA->getType()->getElementType()) * + CA->getNumOperands(); + else + return false; + + val_vec_type Vals(total_size, 0); + if (fillGenericConstant(DL, Init, Vals, 0) == false) + return false; + cs_vals_[static_cast(Init)] = Vals; + TmpVal = std::move(Vals); + } + + // test whether host endianness matches target + union { + uint8_t c[2]; + uint16_t s; + } test_buf; + uint16_t test_val = 0x2345; + if (DL.isLittleEndian()) + support::endian::write16le(test_buf.c, test_val); + else + support::endian::write16be(test_buf.c, test_val); + + bool endian_match = test_buf.s == test_val; + for (uint64_t i = Offset, j = 0; i < Offset + Size; i++, j++) + ByteSeq[j] = endian_match ? TmpVal[i] : TmpVal[Offset + Size - 1 - j]; + + return true; +} + +bool SBFDAGToDAGISel::fillGenericConstant(const DataLayout &DL, + const Constant *CV, + val_vec_type &Vals, uint64_t Offset) { + uint64_t Size = DL.getTypeAllocSize(CV->getType()); + + if (isa(CV) || isa(CV)) + return true; // already done + + if (const ConstantInt *CI = dyn_cast(CV)) { + uint64_t val = CI->getZExtValue(); + LLVM_DEBUG(dbgs() << "Byte array at offset " << Offset << " with value " + << val << '\n'); + + if (Size > 8 || (Size & (Size - 1))) + return false; + + // Store based on target endian + for (uint64_t i = 0; i < Size; ++i) { + Vals[Offset + i] = DL.isLittleEndian() + ? ((val >> (i * 8)) & 0xFF) + : ((val >> ((Size - i - 1) * 8)) & 0xFF); + } + return true; + } + + if (const ConstantDataArray *CDA = dyn_cast(CV)) + return fillConstantDataArray(DL, CDA, Vals, Offset); + + if (const ConstantArray *CA = dyn_cast(CV)) + return fillConstantArray(DL, CA, Vals, Offset); + + if (const ConstantStruct *CVS = dyn_cast(CV)) + return fillConstantStruct(DL, CVS, Vals, Offset); + + return false; +} + +bool SBFDAGToDAGISel::fillConstantDataArray(const DataLayout &DL, + const ConstantDataArray *CDA, + val_vec_type &Vals, int Offset) { + for (unsigned i = 0, e = CDA->getNumElements(); i != e; ++i) { + if (fillGenericConstant(DL, CDA->getElementAsConstant(i), Vals, Offset) == + false) + return false; + Offset += DL.getTypeAllocSize(CDA->getElementAsConstant(i)->getType()); + } + + return true; +} + +bool SBFDAGToDAGISel::fillConstantArray(const DataLayout &DL, + const ConstantArray *CA, + val_vec_type &Vals, int Offset) { + for (unsigned i = 0, e = CA->getNumOperands(); i != e; ++i) { + if (fillGenericConstant(DL, CA->getOperand(i), Vals, Offset) == false) + return false; + Offset += DL.getTypeAllocSize(CA->getOperand(i)->getType()); + } + + return true; +} + +bool SBFDAGToDAGISel::fillConstantStruct(const DataLayout &DL, + const ConstantStruct *CS, + val_vec_type &Vals, int Offset) { + const StructLayout *Layout = DL.getStructLayout(CS->getType()); + for (unsigned i = 0, e = CS->getNumOperands(); i != e; ++i) { + const Constant *Field = CS->getOperand(i); + uint64_t SizeSoFar = Layout->getElementOffset(i); + if (fillGenericConstant(DL, Field, Vals, Offset + SizeSoFar) == false) + return false; + } + return true; +} + +FunctionPass *llvm::createSBFISelDag(SBFTargetMachine &TM) { + return new SBFDAGToDAGISelLegacy(TM); +} diff --git a/llvm/lib/Target/SBF/SBFISelLowering.cpp b/llvm/lib/Target/SBF/SBFISelLowering.cpp new file mode 100644 index 0000000000000..5ad919e636075 --- /dev/null +++ b/llvm/lib/Target/SBF/SBFISelLowering.cpp @@ -0,0 +1,1125 @@ +//===-- SBFISelLowering.cpp - SBF DAG Lowering Implementation ------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// +// +// This file defines the interfaces that SBF uses to lower LLVM code into a +// selection DAG. +// +//===----------------------------------------------------------------------===// + +#include "SBFFunctionInfo.h" +#include "SBFRegisterInfo.h" +#include "SBFSubtarget.h" +#include "llvm/CodeGen/CallingConvLower.h" +#include "llvm/CodeGen/MachineFrameInfo.h" +#include "llvm/CodeGen/MachineFunction.h" +#include "llvm/CodeGen/MachineInstrBuilder.h" +#include "llvm/CodeGen/MachineRegisterInfo.h" +#include "llvm/CodeGen/TargetLoweringObjectFileImpl.h" +#include "llvm/CodeGen/ValueTypes.h" +#include "llvm/IR/DiagnosticInfo.h" +#include "llvm/IR/DiagnosticPrinter.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/raw_ostream.h" +using namespace llvm; + +#define DEBUG_TYPE "sbf-lower" + +static void fail(const SDLoc &DL, SelectionDAG &DAG, const Twine &Msg) { + MachineFunction &MF = DAG.getMachineFunction(); + DAG.getContext()->diagnose( + DiagnosticInfoUnsupported(MF.getFunction(), Msg, DL.getDebugLoc())); +} + +SBFTargetLowering::SBFTargetLowering(const TargetMachine &TM, + const SBFSubtarget &STI) + : TargetLowering(TM), Subtarget(&STI) { + + // Set up the register classes. + addRegisterClass(MVT::i64, &SBF::GPRRegClass); + if (STI.getHasAlu32()) + addRegisterClass(MVT::i32, &SBF::GPR32RegClass); + + // Compute derived properties from the register classes + computeRegisterProperties(STI.getRegisterInfo()); + + setStackPointerRegisterToSaveRestore(SBF::R10); + + setOperationAction(ISD::BR_CC, MVT::i64, Custom); + setOperationAction(ISD::BR_JT, MVT::Other, Expand); + setOperationAction(ISD::BRIND, MVT::Other, Expand); + setOperationAction(ISD::BRCOND, MVT::Other, Expand); + + setOperationAction({ISD::GlobalAddress, ISD::ConstantPool}, MVT::i64, Custom); + + setOperationAction(ISD::DYNAMIC_STACKALLOC, MVT::i64, Custom); + setOperationAction(ISD::STACKSAVE, MVT::Other, Expand); + setOperationAction(ISD::STACKRESTORE, MVT::Other, Expand); + + setOperationAction(ISD::INTRINSIC_W_CHAIN, MVT::Other, Custom); + + for (auto VT : {MVT::i8, MVT::i16, MVT::i32, MVT::i64}) { + // Implement custom lowering for all atomic operations + setOperationAction(ISD::ATOMIC_SWAP, VT, Custom); + setOperationAction(ISD::ATOMIC_CMP_SWAP_WITH_SUCCESS, VT, Custom); + setOperationAction(ISD::ATOMIC_CMP_SWAP, VT, Custom); + setOperationAction(ISD::ATOMIC_LOAD_ADD, VT, Custom); + setOperationAction(ISD::ATOMIC_LOAD_AND, VT, Custom); + setOperationAction(ISD::ATOMIC_LOAD_MAX, VT, Custom); + setOperationAction(ISD::ATOMIC_LOAD_MIN, VT, Custom); + setOperationAction(ISD::ATOMIC_LOAD_NAND, VT, Custom); + setOperationAction(ISD::ATOMIC_LOAD_OR, VT, Custom); + setOperationAction(ISD::ATOMIC_LOAD_SUB, VT, Custom); + setOperationAction(ISD::ATOMIC_LOAD_UMAX, VT, Custom); + setOperationAction(ISD::ATOMIC_LOAD_UMIN, VT, Custom); + setOperationAction(ISD::ATOMIC_LOAD_XOR, VT, Custom); + setOperationAction(ISD::ATOMIC_LOAD, VT, Expand); + setOperationAction(ISD::ATOMIC_STORE, VT, Expand); + } + + for (auto VT : { MVT::i32, MVT::i64 }) { + if (VT == MVT::i32 && !STI.getHasAlu32()) + continue; + + if (!STI.getHasPqrClass()) { + setOperationAction(ISD::SDIV, VT, Expand); + setOperationAction(ISD::SREM, VT, Expand); + setOperationAction(ISD::MULHU, VT, Expand); + setOperationAction(ISD::MULHS, VT, Expand); + } + + setOperationAction(ISD::SDIVREM, VT, Expand); + setOperationAction(ISD::UDIVREM, VT, Expand); + setOperationAction(ISD::UMUL_LOHI, VT, Expand); + setOperationAction(ISD::SMUL_LOHI, VT, Expand); + setOperationAction(ISD::ROTR, VT, Expand); + setOperationAction(ISD::ROTL, VT, Expand); + setOperationAction(ISD::SHL_PARTS, VT, Expand); + setOperationAction(ISD::SRL_PARTS, VT, Expand); + setOperationAction(ISD::SRA_PARTS, VT, Expand); + setOperationAction(ISD::CTPOP, VT, Expand); + setOperationAction(ISD::CTTZ, VT, Expand); + setOperationAction(ISD::CTLZ, VT, Expand); + setOperationAction(ISD::CTTZ_ZERO_UNDEF, VT, Expand); + setOperationAction(ISD::CTLZ_ZERO_UNDEF, VT, Expand); + + setOperationAction(ISD::SETCC, VT, Expand); + setOperationAction(ISD::SELECT, VT, Expand); + setOperationAction(ISD::SELECT_CC, VT, Custom); + } + + if (STI.getHasPqrClass() && STI.getHasAlu32()) { + setOperationAction(ISD::MULHU, MVT::i32, Expand); + setOperationAction(ISD::MULHS, MVT::i32, Expand); + } + + if (STI.getHasAlu32()) { + setOperationAction(ISD::BSWAP, MVT::i32, Promote); + setOperationAction(ISD::BR_CC, MVT::i32, Custom); + setOperationAction(ISD::CTTZ, MVT::i32, Expand); + setOperationAction(ISD::CTLZ, MVT::i32, Expand); + setOperationAction(ISD::CTTZ_ZERO_UNDEF, MVT::i32, Expand); + setOperationAction(ISD::CTLZ_ZERO_UNDEF, MVT::i32, Expand); + } + + setOperationAction(ISD::SIGN_EXTEND_INREG, MVT::i1, Expand); + setOperationAction(ISD::SIGN_EXTEND_INREG, MVT::i8, Expand); + setOperationAction(ISD::SIGN_EXTEND_INREG, MVT::i16, Expand); + setOperationAction(ISD::SIGN_EXTEND_INREG, MVT::i32, Expand); + + // Extended load operations for i1 types must be promoted + for (MVT VT : MVT::integer_valuetypes()) { + setLoadExtAction(ISD::EXTLOAD, VT, MVT::i1, Promote); + setLoadExtAction(ISD::ZEXTLOAD, VT, MVT::i1, Promote); + setLoadExtAction(ISD::SEXTLOAD, VT, MVT::i1, Promote); + + setLoadExtAction(ISD::SEXTLOAD, VT, MVT::i8, Expand); + setLoadExtAction(ISD::SEXTLOAD, VT, MVT::i16, Expand); + setLoadExtAction(ISD::SEXTLOAD, VT, MVT::i32, Expand); + } + + setBooleanContents(ZeroOrOneBooleanContent); + + // Function alignments + setMinFunctionAlignment(Align(8)); + setPrefFunctionAlignment(Align(8)); + + // A syscall consumes at least 10 CUs, so we should only invoke it when + // the number of instructions is at least 10. + + // Memset translates to stdw or stdxw, so the maximum should be 10. + MaxStoresPerMemset = MaxStoresPerMemsetOptSize = 10; + // Each store in memcpy follows a load, so the maximum is 5. + MaxStoresPerMemcpy = MaxStoresPerMemcpyOptSize = 5; + // Each store in memmove follows a load, so the maximum is 5. + MaxStoresPerMemmove = MaxStoresPerMemmoveOptSize = 5; + // Memcmp expands to three instructions for each load: + // 1. One load for each pointer being compared. + // 2. One jne for each load. + // There is also a 3 CUs overhead for adjusting the arguments to memcmp. + // We need at least three mov64 to set them. + // A syscall takes at least 10 + 3 CUs. + // The limit here should be four, since 3*4 = 12; + MaxLoadsPerMemcmp = MaxLoadsPerMemcmpOptSize = 4; + + // CPU/Feature control + HasAlu32 = STI.getHasAlu32(); + HasJmpExt = STI.getHasJmpExt(); + SBFRegisterInfo::FrameLength = 4096; +} + +bool SBFTargetLowering::allowsMisalignedMemoryAccesses( + EVT VT, unsigned, Align, MachineMemOperand::Flags, unsigned *Fast) const { + if (!VT.isSimple()) { + return false; + } + + if (Fast) { + *Fast = 1; + } + return true; +} + +bool SBFTargetLowering::isOffsetFoldingLegal( + const GlobalAddressSDNode *GA) const { + return false; +} + +bool SBFTargetLowering::isTruncateFree(Type *Ty1, Type *Ty2) const { + if (!Ty1->isIntegerTy() || !Ty2->isIntegerTy()) + return false; + unsigned NumBits1 = Ty1->getPrimitiveSizeInBits(); + unsigned NumBits2 = Ty2->getPrimitiveSizeInBits(); + return NumBits1 > NumBits2; +} + +bool SBFTargetLowering::isTruncateFree(EVT VT1, EVT VT2) const { + if (!VT1.isInteger() || !VT2.isInteger()) + return false; + unsigned NumBits1 = VT1.getSizeInBits(); + unsigned NumBits2 = VT2.getSizeInBits(); + return NumBits1 > NumBits2; +} + +bool SBFTargetLowering::isZExtFree(Type *Ty1, Type *Ty2) const { + if (!getHasAlu32() || !Ty1->isIntegerTy() || !Ty2->isIntegerTy()) + return false; + unsigned NumBits1 = Ty1->getPrimitiveSizeInBits(); + unsigned NumBits2 = Ty2->getPrimitiveSizeInBits(); + return NumBits1 == 32 && NumBits2 == 64; +} + +bool SBFTargetLowering::isZExtFree(EVT VT1, EVT VT2) const { + if (!getHasAlu32() || !VT1.isInteger() || !VT2.isInteger()) + return false; + unsigned NumBits1 = VT1.getSizeInBits(); + unsigned NumBits2 = VT2.getSizeInBits(); + return NumBits1 == 32 && NumBits2 == 64; +} + +SBFTargetLowering::ConstraintType +SBFTargetLowering::getConstraintType(StringRef Constraint) const { + if (Constraint.size() == 1) { + switch (Constraint[0]) { + default: + break; + case 'w': + return C_RegisterClass; + } + } + + return TargetLowering::getConstraintType(Constraint); +} + +std::pair +SBFTargetLowering::getRegForInlineAsmConstraint(const TargetRegisterInfo *TRI, + StringRef Constraint, + MVT VT) const { + if (Constraint.size() == 1) + // GCC Constraint Letters + switch (Constraint[0]) { + case 'r': // GENERAL_REGS + return std::make_pair(0U, &SBF::GPRRegClass); + case 'w': + if (HasAlu32) + return std::make_pair(0U, &SBF::GPR32RegClass); + break; + default: + break; + } + + return TargetLowering::getRegForInlineAsmConstraint(TRI, Constraint, VT); +} + +void SBFTargetLowering::ReplaceNodeResults(SDNode *N, + SmallVectorImpl &Results, + SelectionDAG &DAG) const { + const char *err_msg; + uint32_t Opcode = N->getOpcode(); + switch (Opcode) { + default: + report_fatal_error("Unhandled custom legalization"); + case ISD::ATOMIC_SWAP: + case ISD::ATOMIC_CMP_SWAP_WITH_SUCCESS: + case ISD::ATOMIC_CMP_SWAP: + case ISD::ATOMIC_LOAD_ADD: + case ISD::ATOMIC_LOAD_AND: + case ISD::ATOMIC_LOAD_MAX: + case ISD::ATOMIC_LOAD_MIN: + case ISD::ATOMIC_LOAD_NAND: + case ISD::ATOMIC_LOAD_OR: + case ISD::ATOMIC_LOAD_SUB: + case ISD::ATOMIC_LOAD_UMAX: + case ISD::ATOMIC_LOAD_UMIN: + case ISD::ATOMIC_LOAD_XOR: + // We do lowering during legalization, see LowerOperation() + return; + } + + SDLoc DL(N); + fail(DL, DAG, err_msg); +} + +SDValue SBFTargetLowering::LowerOperation(SDValue Op, SelectionDAG &DAG) const { + switch (Op.getOpcode()) { + case ISD::BR_CC: + return LowerBR_CC(Op, DAG); + case ISD::GlobalAddress: + return LowerGlobalAddress(Op, DAG); + case ISD::SELECT_CC: + return LowerSELECT_CC(Op, DAG); + case ISD::ConstantPool: + return LowerConstantPool(Op, DAG); + case ISD::ATOMIC_SWAP: + case ISD::ATOMIC_CMP_SWAP_WITH_SUCCESS: + case ISD::ATOMIC_CMP_SWAP: + case ISD::ATOMIC_LOAD_ADD: + case ISD::ATOMIC_LOAD_AND: + case ISD::ATOMIC_LOAD_MAX: + case ISD::ATOMIC_LOAD_MIN: + case ISD::ATOMIC_LOAD_NAND: + case ISD::ATOMIC_LOAD_OR: + case ISD::ATOMIC_LOAD_SUB: + case ISD::ATOMIC_LOAD_UMAX: + case ISD::ATOMIC_LOAD_UMIN: + case ISD::ATOMIC_LOAD_XOR: + return LowerATOMICRMW(Op, DAG); + case ISD::INTRINSIC_W_CHAIN: + // continue the expansion as defined with tablegen + return SDValue(); + case ISD::DYNAMIC_STACKALLOC: + report_fatal_error("Unsupported dynamic stack allocation"); + default: + llvm_unreachable("unimplemented operation"); + } +} + +// Calling Convention Implementation +#include "SBFGenCallingConv.inc" + +SDValue SBFTargetLowering::LowerFormalArguments( + SDValue Chain, CallingConv::ID CallConv, bool IsVarArg, + const SmallVectorImpl &Ins, const SDLoc &DL, + SelectionDAG &DAG, SmallVectorImpl &InVals) const { + switch (CallConv) { + default: + report_fatal_error("Unsupported calling convention"); + case CallingConv::C: + case CallingConv::Fast: + break; + } + + MachineFunction &MF = DAG.getMachineFunction(); + MachineRegisterInfo &RegInfo = MF.getRegInfo(); + + // Assign locations to all of the incoming arguments. + SmallVector ArgLocs; + CCState CCInfo(CallConv, IsVarArg, MF, ArgLocs, *DAG.getContext()); + if (!Subtarget->getHasDynamicFrames() && Ins.size() > MaxArgs) { + // Pass args 1-4 via registers, remaining args via stack, referenced via + // SBF::R5 + CCInfo.AnalyzeFormalArguments(Ins, + getHasAlu32() ? CC_SBF32_X : CC_SBF64_X); + } else { + // Pass args 1-5 via registers, remaining args via stack, if any. + CCInfo.AnalyzeFormalArguments(Ins, getHasAlu32() ? CC_SBF32 : CC_SBF64); + } + + for (auto &VA : ArgLocs) { + if (VA.isRegLoc()) { + // Argument passed in registers + EVT RegVT = VA.getLocVT(); + MVT::SimpleValueType SimpleTy = RegVT.getSimpleVT().SimpleTy; + switch (SimpleTy) { + default: { + errs() << "LowerFormalArguments Unhandled argument type: " + << RegVT.getEVTString() << '\n'; + llvm_unreachable(nullptr); + } + case MVT::i32: + case MVT::i64: + Register VReg = RegInfo.createVirtualRegister( + SimpleTy == MVT::i64 ? &SBF::GPRRegClass : &SBF::GPR32RegClass); + RegInfo.addLiveIn(VA.getLocReg(), VReg); + SDValue ArgValue = DAG.getCopyFromReg(Chain, DL, VReg, RegVT); + + // If this is a value that has been promoted to a wider type, insert an + // assert[sz]ext to capture this, then truncate to the right size. + if (VA.getLocInfo() == CCValAssign::SExt) + ArgValue = DAG.getNode(ISD::AssertSext, DL, RegVT, ArgValue, + DAG.getValueType(VA.getValVT())); + else if (VA.getLocInfo() == CCValAssign::ZExt) + ArgValue = DAG.getNode(ISD::AssertZext, DL, RegVT, ArgValue, + DAG.getValueType(VA.getValVT())); + + if (VA.getLocInfo() != CCValAssign::Full) + ArgValue = DAG.getNode(ISD::TRUNCATE, DL, VA.getValVT(), ArgValue); + + InVals.push_back(ArgValue); + + break; + } + } else { + // Argument passed via stack + assert(VA.isMemLoc() && "Should be isMemLoc"); + + EVT PtrVT = DAG.getTargetLoweringInfo().getPointerTy(DAG.getDataLayout()); + EVT LocVT = VA.getLocVT(); + + SDValue SDV; + if (Subtarget->getHasDynamicFrames()) { + // In the new convention, arguments are in at the end of the callee + // frame. + uint64_t Size = VA.getLocVT().getFixedSizeInBits() / 8; + int64_t Offset = -static_cast(VA.getLocMemOffset() + Size); + int FrameIndex = + MF.getFrameInfo().CreateFixedObject(Size, Offset, false); + SDValue DstAddr = DAG.getFrameIndex(FrameIndex, PtrVT); + MachinePointerInfo DstInfo = + MachinePointerInfo::getFixedStack(MF, FrameIndex, Offset); + SDV = DAG.getLoad(LocVT, DL, Chain, DstAddr, DstInfo); + } else { + unsigned Offset = SBFRegisterInfo::FrameLength - VA.getLocMemOffset(); + + // Arguments relative to SBF::R5 + unsigned reg = MF.addLiveIn(SBF::R5, &SBF::GPRRegClass); + SDValue Const = DAG.getConstant(Offset, DL, MVT::i64); + SDV = DAG.getCopyFromReg(Chain, DL, reg, + getPointerTy(MF.getDataLayout())); + SDV = DAG.getNode(ISD::SUB, DL, PtrVT, SDV, Const); + SDV = DAG.getLoad(LocVT, DL, Chain, SDV, MachinePointerInfo()); + } + + InVals.push_back(SDV); + } + } + + if (IsVarArg) { + fail(DL, DAG, "Functions with VarArgs are not supported"); + } + + return Chain; +} + +const unsigned SBFTargetLowering::MaxArgs = 5; + +SDValue SBFTargetLowering::LowerCall(TargetLowering::CallLoweringInfo &CLI, + SmallVectorImpl &InVals) const { + SelectionDAG &DAG = CLI.DAG; + auto &Outs = CLI.Outs; + auto &OutVals = CLI.OutVals; + auto &Ins = CLI.Ins; + SDValue Chain = CLI.Chain; + SDValue Callee = CLI.Callee; + bool &IsTailCall = CLI.IsTailCall; + CallingConv::ID CallConv = CLI.CallConv; + bool IsVarArg = CLI.IsVarArg; + MachineFunction &MF = DAG.getMachineFunction(); + + // SBF target does not support tail call optimization. + IsTailCall = false; + + switch (CallConv) { + default: + report_fatal_error("Unsupported calling convention"); + case CallingConv::Fast: + case CallingConv::C: + break; + } + + // Analyze operands of the call, assigning locations to each operand. + SmallVector ArgLocs; + CCState CCInfo(CallConv, IsVarArg, MF, ArgLocs, *DAG.getContext()); + if (Outs.size() > MaxArgs) { + if (Subtarget->getHasDynamicFrames()) { + // Pass args 1-5 via registers, remaining args via stack + CCInfo.AnalyzeCallOperands(Outs, getHasAlu32() ? CC_SBF32 : CC_SBF64); + } else { + // Pass args 1-4 via registers, remaining args via stack, referenced via + // SBF::R5 + CCInfo.AnalyzeCallOperands(Outs, getHasAlu32() ? CC_SBF32_X : CC_SBF64_X); + } + } else { + // Pass all args via registers + CCInfo.AnalyzeCallOperands(Outs, getHasAlu32() ? CC_SBF32 : CC_SBF64); + } + + unsigned NumBytes = CCInfo.getStackSize(); + + + auto PtrVT = getPointerTy(MF.getDataLayout()); + Chain = DAG.getCALLSEQ_START(Chain, NumBytes, 0, CLI.DL); + + SmallVector, MaxArgs> RegsToPass; + + // Walk arg assignments + unsigned i; + SmallVector MemOpChain; + SBFFunctionInfo * SBFFuncInfo = MF.getInfo(); + + for (i = 0; i < ArgLocs.size(); i++) { + CCValAssign &VA = ArgLocs[i]; + SDValue Arg = OutVals[i]; + + // Promote the value if needed. + switch (VA.getLocInfo()) { + default: + llvm_unreachable("Unknown loc info"); + case CCValAssign::Full: + break; + case CCValAssign::SExt: + Arg = DAG.getNode(ISD::SIGN_EXTEND, CLI.DL, VA.getLocVT(), Arg); + break; + case CCValAssign::ZExt: + Arg = DAG.getNode(ISD::ZERO_EXTEND, CLI.DL, VA.getLocVT(), Arg); + break; + case CCValAssign::AExt: + Arg = DAG.getNode(ISD::ANY_EXTEND, CLI.DL, VA.getLocVT(), Arg); + break; + } + + // Push arguments into RegsToPass vector + if (VA.isRegLoc()) + RegsToPass.push_back(std::make_pair(VA.getLocReg(), Arg)); + else if (VA.isMemLoc()) { + CCValAssign &VA = ArgLocs[i]; + SDValue Arg = OutVals[i]; + + int64_t Offset = static_cast(VA.getLocMemOffset()); + uint64_t Size = VA.getLocVT().getFixedSizeInBits() / 8; + if (Subtarget->getHasDynamicFrames()) { + // In the new call convention, arguments are stored in the callee frame + // We must increase the offset, simply because offset zero belongs to + // the caller. + Offset += Size; + } + + int FrameIndex = MF.getFrameInfo().CreateFixedObject( + Size, Offset, false); + SBFFuncInfo->storeFrameIndexArgument(FrameIndex); + SDValue DstAddr = DAG.getFrameIndex(FrameIndex, PtrVT); + MachinePointerInfo DstInfo = MachinePointerInfo::getFixedStack(MF, FrameIndex, Offset); + SDValue Store = DAG.getStore(Chain, CLI.DL, Arg, DstAddr, DstInfo); + MemOpChain.push_back(Store); + + } else + llvm_unreachable("call arg pass bug"); + } + + SDValue InGlue; + + if (!MemOpChain.empty()) { + Chain = DAG.getNode(ISD::TokenFactor, CLI.DL, MVT::Other, MemOpChain); + if (!Subtarget->getHasDynamicFrames()) { + // Pass the current stack frame pointer via SBF::R5, gluing the + // instruction to instructions passing the first 4 arguments in + // registers below. + SDValue FramePtr = DAG.getCopyFromReg( + Chain, CLI.DL, Subtarget->getRegisterInfo()->getFrameRegister(MF), + getPointerTy(MF.getDataLayout())); + Chain = DAG.getCopyToReg(Chain, CLI.DL, SBF::R5, FramePtr, InGlue); + InGlue = Chain.getValue(1); + } + } + + // Build a sequence of copy-to-reg nodes chained together with token chain and + // flag operands which copy the outgoing args into registers. The InGlue is + // necessary since all emitted instructions must be stuck together. + for (auto &Reg : RegsToPass) { + Chain = DAG.getCopyToReg(Chain, CLI.DL, Reg.first, Reg.second, InGlue); + InGlue = Chain.getValue(1); + } + + // If the callee is a GlobalAddress node (quite common, every direct call is) + // turn it into a TargetGlobalAddress node so that legalize doesn't hack it. + // Likewise ExternalSymbol -> TargetExternalSymbol. + if (GlobalAddressSDNode *G = dyn_cast(Callee)) { + Callee = DAG.getTargetGlobalAddress(G->getGlobal(), CLI.DL, PtrVT, + G->getOffset(), 0); + } else if (ExternalSymbolSDNode *E = dyn_cast(Callee)) { + Callee = DAG.getTargetExternalSymbol(E->getSymbol(), PtrVT, 0); + } + + // Returns a chain & a flag for retval copy to use. + SDVTList NodeTys = DAG.getVTList(MVT::Other, MVT::Glue); + SmallVector Ops; + Ops.push_back(Chain); + Ops.push_back(Callee); + + // Add argument registers to the end of the list so that they are + // known live into the call. + for (auto &Reg : RegsToPass) + Ops.push_back(DAG.getRegister(Reg.first, Reg.second.getValueType())); + + if (!MemOpChain.empty() && !Subtarget->getHasDynamicFrames()) { + Ops.push_back(DAG.getRegister(SBF::R5, MVT::i64)); + } + + if (InGlue.getNode()) + Ops.push_back(InGlue); + + Chain = DAG.getNode(SBFISD::CALL, CLI.DL, NodeTys, Ops); + InGlue = Chain.getValue(1); + + DAG.addNoMergeSiteInfo(Chain.getNode(), CLI.NoMerge); + + // Create the CALLSEQ_END node. + Chain = DAG.getCALLSEQ_END(Chain, NumBytes, 0, InGlue, CLI.DL); + InGlue = Chain.getValue(1); + + // Handle result values, copying them out of physregs into vregs that we + // return. + return LowerCallResult(Chain, InGlue, CallConv, IsVarArg, Ins, CLI.DL, DAG, + InVals); +} + +bool SBFTargetLowering::shouldSignExtendTypeInLibCall(Type* Ty, + bool IsSigned) const { + return IsSigned || Ty->isIntegerTy(32); +} + +bool SBFTargetLowering::CanLowerReturn( + CallingConv::ID CallConv, MachineFunction &MF, bool IsVarArg, + const SmallVectorImpl &Outs, LLVMContext &Context, + const Type *RetTy) const { + // At minimal return Outs.size() <= 1, or check valid types in CC. + SmallVector RVLocs; + CCState CCInfo(CallConv, IsVarArg, MF, RVLocs, Context); + return CCInfo.CheckReturn(Outs, getHasAlu32() ? RetCC_SBF32 : RetCC_SBF64); +} + +SDValue +SBFTargetLowering::LowerReturn(SDValue Chain, CallingConv::ID CallConv, + bool IsVarArg, + const SmallVectorImpl &Outs, + const SmallVectorImpl &OutVals, + const SDLoc &DL, SelectionDAG &DAG) const { + unsigned Opc = SBFISD::RET_GLUE; + + // CCValAssign - represent the assignment of the return value to a location + SmallVector RVLocs; + MachineFunction &MF = DAG.getMachineFunction(); + + // CCState - Info about the registers and stack slot. + CCState CCInfo(CallConv, IsVarArg, MF, RVLocs, *DAG.getContext()); + + if (Outs.size() > 1) { + fail(DL, DAG, "Only a single return supported"); + assert(false); + } + + // Analize return values. + CCInfo.AnalyzeReturn(Outs, getHasAlu32() ? RetCC_SBF32 : RetCC_SBF64); + + SDValue Flag; + SmallVector RetOps(1, Chain); + + // Copy the result values into the output registers. + for (unsigned i = 0; i != RVLocs.size(); ++i) { + CCValAssign &VA = RVLocs[i]; + assert(VA.isRegLoc() && "Can only return in registers!"); + + Chain = DAG.getCopyToReg(Chain, DL, VA.getLocReg(), OutVals[i], Flag); + + // Guarantee that all emitted copies are stuck together, + // avoiding something bad. + Flag = Chain.getValue(1); + RetOps.push_back(DAG.getRegister(VA.getLocReg(), VA.getLocVT())); + } + + RetOps[0] = Chain; // Update chain. + + // Add the flag if we have it. + if (Flag.getNode()) + RetOps.push_back(Flag); + + return DAG.getNode(Opc, DL, MVT::Other, RetOps); +} + +SDValue SBFTargetLowering::LowerCallResult( + SDValue Chain, SDValue InGlue, CallingConv::ID CallConv, bool IsVarArg, + const SmallVectorImpl &Ins, const SDLoc &DL, + SelectionDAG &DAG, SmallVectorImpl &InVals) const { + + MachineFunction &MF = DAG.getMachineFunction(); + // Assign locations to each value returned by this call. + SmallVector RVLocs; + CCState CCInfo(CallConv, IsVarArg, MF, RVLocs, *DAG.getContext()); + + if (Ins.size() > 1) { + fail(DL, DAG, "Only a single return supported"); + assert(false); + } + + CCInfo.AnalyzeCallResult(Ins, getHasAlu32() ? RetCC_SBF32 : RetCC_SBF64); + + // Copy all of the result registers out of their specified physreg. + for (auto &Val : RVLocs) { + Chain = DAG.getCopyFromReg(Chain, DL, Val.getLocReg(), + Val.getValVT(), InGlue).getValue(1); + InGlue = Chain.getValue(2); + InVals.push_back(Chain.getValue(0)); + } + + return Chain; +} + +static void NegateCC(SDValue &LHS, SDValue &RHS, ISD::CondCode &CC) { + switch (CC) { + default: + break; + case ISD::SETULT: + case ISD::SETULE: + case ISD::SETLT: + case ISD::SETLE: + CC = ISD::getSetCCSwappedOperands(CC); + std::swap(LHS, RHS); + break; + } +} + +SDValue SBFTargetLowering::LowerBR_CC(SDValue Op, SelectionDAG &DAG) const { + SDValue Chain = Op.getOperand(0); + ISD::CondCode CC = cast(Op.getOperand(1))->get(); + SDValue LHS = Op.getOperand(2); + SDValue RHS = Op.getOperand(3); + SDValue Dest = Op.getOperand(4); + SDLoc DL(Op); + + if (!getHasJmpExt()) + NegateCC(LHS, RHS, CC); + + bool IsSignedCmp = (CC == ISD::SETGT || + CC == ISD::SETGE || + CC == ISD::SETLT || + CC == ISD::SETLE); + bool Is32Num = LHS.getValueType() == MVT::i32 || + RHS.getValueType() == MVT::i32; + + if (getHasAlu32() && Is32Num) { + if (isIntOrFPConstant(RHS) || isIntOrFPConstant(LHS)) { + // Immediate values are sign extended in SBF, so we sign extend the + // registers for a correct comparison. + LHS = DAG.getNode(ISD::SIGN_EXTEND, DL, MVT::i64, LHS); + RHS = DAG.getNode(ISD::SIGN_EXTEND, DL, MVT::i64, RHS); + } else if (IsSignedCmp) { + // If the comparison is signed, we sign extend registers + LHS = DAG.getNode(ISD::SIGN_EXTEND, DL, MVT::i64, LHS); + RHS = DAG.getNode(ISD::SIGN_EXTEND, DL, MVT::i64, RHS); + } else { + // If the comparison is unsigned, we zero extend registers + LHS = DAG.getNode(ISD::ZERO_EXTEND, DL, MVT::i64, LHS); + RHS = DAG.getNode(ISD::ZERO_EXTEND, DL, MVT::i64, RHS); + } + } + + return DAG.getNode(SBFISD::BR_CC, DL, Op.getValueType(), Chain, LHS, RHS, + DAG.getConstant(CC, DL, MVT::i64), Dest); +} + +SDValue SBFTargetLowering::LowerSELECT_CC(SDValue Op, SelectionDAG &DAG) const { + SDValue LHS = Op.getOperand(0); + SDValue RHS = Op.getOperand(1); + SDValue TrueV = Op.getOperand(2); + SDValue FalseV = Op.getOperand(3); + ISD::CondCode CC = cast(Op.getOperand(4))->get(); + SDLoc DL(Op); + + if (!getHasJmpExt()) + NegateCC(LHS, RHS, CC); + + SDValue TargetCC = DAG.getConstant(CC, DL, LHS.getValueType()); + SDValue Ops[] = {LHS, RHS, TargetCC, TrueV, FalseV}; + + return DAG.getNode(SBFISD::SELECT_CC, DL, Op.getValueType(), Ops); +} + +SDValue SBFTargetLowering::LowerATOMICRMW(SDValue Op, SelectionDAG &DAG) const { + SDLoc DL(Op); + AtomicSDNode *AN = cast(Op); + assert(AN && "Expected custom lowering of an atomic load node"); + + SDValue Chain = AN->getChain(); + SDValue Ptr = AN->getBasePtr(); + EVT PtrVT = AN->getMemoryVT(); + EVT RetVT = Op.getValueType(); + + // Load the current value + SDValue Load = + DAG.getExtLoad(ISD::EXTLOAD, DL, RetVT, Chain, Ptr, MachinePointerInfo(), + PtrVT, AN->getAlign()); + Chain = Load.getValue(1); + + // Most ops return the current value, except CMP_SWAP_WITH_SUCCESS see below + SDValue Ret = Load; + SDValue RetFlag; + + // Val contains the new value we want to set. For CMP_SWAP, Cmp contains the + // expected current value. + SDValue Cmp, Val; + if (AN->isCompareAndSwap()) { + Cmp = Op.getOperand(2); + Val = Op.getOperand(3); + + // The Cmp value must match the pointer type + EVT CmpVT = Cmp->getValueType(0); + if (CmpVT != RetVT) { + Cmp = RetVT.bitsGT(CmpVT) ? DAG.getNode(ISD::SIGN_EXTEND, DL, RetVT, Cmp) + : DAG.getNode(ISD::TRUNCATE, DL, RetVT, Cmp); + } + } else { + Val = AN->getVal(); + } + + // The new value type must match the pointer type + EVT ValVT = Val->getValueType(0); + if (ValVT != RetVT) { + Val = RetVT.bitsGT(ValVT) ? DAG.getNode(ISD::SIGN_EXTEND, DL, RetVT, Val) + : DAG.getNode(ISD::TRUNCATE, DL, RetVT, Val); + ValVT = Val->getValueType(0); + } + + SDValue NewVal; + switch (Op.getOpcode()) { + case ISD::ATOMIC_SWAP: + NewVal = Val; + break; + case ISD::ATOMIC_CMP_SWAP_WITH_SUCCESS: { + EVT RetFlagVT = AN->getValueType(1); + NewVal = DAG.getSelectCC(DL, Load, Cmp, Val, Load, ISD::SETEQ); + RetFlag = DAG.getSelectCC( + DL, Load, Cmp, DAG.getBoolConstant(true, DL, RetFlagVT, RetFlagVT), + DAG.getBoolConstant(false, DL, RetFlagVT, RetFlagVT), ISD::SETEQ); + break; + } + case ISD::ATOMIC_CMP_SWAP: + NewVal = DAG.getSelectCC(DL, Load, Cmp, Val, Load, ISD::SETEQ); + break; + case ISD::ATOMIC_LOAD_ADD: + NewVal = DAG.getNode(ISD::ADD, DL, ValVT, Load, Val); + break; + case ISD::ATOMIC_LOAD_SUB: + NewVal = DAG.getNode(ISD::SUB, DL, ValVT, Load, Val); + break; + case ISD::ATOMIC_LOAD_AND: + NewVal = DAG.getNode(ISD::AND, DL, ValVT, Load, Val); + break; + case ISD::ATOMIC_LOAD_NAND: { + NewVal = + DAG.getNOT(DL, DAG.getNode(ISD::AND, DL, ValVT, Load, Val), ValVT); + break; + } + case ISD::ATOMIC_LOAD_OR: + NewVal = DAG.getNode(ISD::OR, DL, ValVT, Load, Val); + break; + case ISD::ATOMIC_LOAD_XOR: + NewVal = DAG.getNode(ISD::XOR, DL, ValVT, Load, Val); + break; + case ISD::ATOMIC_LOAD_MIN: + NewVal = DAG.getNode(ISD::SMIN, DL, ValVT, Load, Val); + break; + case ISD::ATOMIC_LOAD_UMIN: + NewVal = DAG.getNode(ISD::UMIN, DL, ValVT, Load, Val); + break; + case ISD::ATOMIC_LOAD_MAX: + NewVal = DAG.getNode(ISD::SMAX, DL, ValVT, Load, Val); + break; + case ISD::ATOMIC_LOAD_UMAX: + NewVal = DAG.getNode(ISD::UMAX, DL, ValVT, Load, Val); + break; + default: + llvm_unreachable("unknown atomicrmw op"); + } + + Chain = + DAG.getTruncStore(Chain, DL, NewVal, Ptr, MachinePointerInfo(), PtrVT); + + if (RetFlag) { + // CMP_SWAP_WITH_SUCCESS returns {value, success, chain} + Ret = DAG.getMergeValues({Ret, RetFlag, Chain}, DL); + } else { + // All the other ops return {value, chain} + Ret = DAG.getMergeValues({Ret, Chain}, DL); + } + + return Ret; +} + +const char *SBFTargetLowering::getTargetNodeName(unsigned Opcode) const { + switch ((SBFISD::NodeType)Opcode) { + case SBFISD::FIRST_NUMBER: + break; + case SBFISD::RET_GLUE: + return "SBFISD::RET_GLUE"; + case SBFISD::CALL: + return "SBFISD::CALL"; + case SBFISD::SELECT_CC: + return "SBFISD::SELECT_CC"; + case SBFISD::BR_CC: + return "SBFISD::BR_CC"; + case SBFISD::Wrapper: + return "SBFISD::Wrapper"; + } + return nullptr; +} + +static SDValue getTargetNode(GlobalAddressSDNode *N, const SDLoc &DL, EVT Ty, + SelectionDAG &DAG, unsigned Flags) { + return DAG.getTargetGlobalAddress(N->getGlobal(), DL, Ty, 0, Flags); +} + +static SDValue getTargetNode(ConstantPoolSDNode *N, const SDLoc &DL, EVT Ty, + SelectionDAG &DAG, unsigned Flags) { + return DAG.getTargetConstantPool(N->getConstVal(), Ty, N->getAlign(), + N->getOffset(), Flags); +} + +template +SDValue SBFTargetLowering::getAddr(NodeTy *N, SelectionDAG &DAG, + unsigned Flags) const { + SDLoc DL(N); + + SDValue GA = getTargetNode(N, DL, MVT::i64, DAG, Flags); + + return DAG.getNode(SBFISD::Wrapper, DL, MVT::i64, GA); +} + +SDValue SBFTargetLowering::LowerGlobalAddress(SDValue Op, + SelectionDAG &DAG) const { + GlobalAddressSDNode *N = cast(Op); + assert(N->getOffset() == 0 && "Invalid offset for global address"); + + return getAddr(N, DAG); +} + +SDValue SBFTargetLowering::LowerConstantPool(llvm::SDValue Op, + llvm::SelectionDAG &DAG) const { + ConstantPoolSDNode *N = cast(Op); + + return getAddr(N, DAG); +} + +unsigned +SBFTargetLowering::EmitSubregExt(MachineInstr &MI, MachineBasicBlock *BB, + unsigned Reg, bool isSigned) const { + const TargetInstrInfo &TII = *BB->getParent()->getSubtarget().getInstrInfo(); + const TargetRegisterClass *RC = getRegClassFor(MVT::i64); + MachineFunction *F = BB->getParent(); + DebugLoc DL = MI.getDebugLoc(); + + MachineRegisterInfo &RegInfo = F->getRegInfo(); + + if (!isSigned) { + unsigned MovOp = + Subtarget->getHasExplicitSignExt() + ? SBF::MOV_32_64_no_sext : SBF::MOV_32_64; + Register PromotedReg0 = RegInfo.createVirtualRegister(RC); + BuildMI(BB, DL, TII.get(MovOp), PromotedReg0).addReg(Reg); + return PromotedReg0; + } + Register PromotedReg0 = RegInfo.createVirtualRegister(RC); + BuildMI(BB, DL, TII.get(SBF::MOV_32_64), PromotedReg0).addReg(Reg); + if (Subtarget->getHasExplicitSignExt()) + return PromotedReg0; + + Register PromotedReg1 = RegInfo.createVirtualRegister(RC); + Register PromotedReg2 = RegInfo.createVirtualRegister(RC); + BuildMI(BB, DL, TII.get(SBF::SLL_ri), PromotedReg1) + .addReg(PromotedReg0).addImm(32); + BuildMI(BB, DL, TII.get(SBF::SRA_ri), PromotedReg2) + .addReg(PromotedReg1).addImm(32); + + return PromotedReg2; +} + +MachineBasicBlock * +SBFTargetLowering::EmitInstrWithCustomInserter(MachineInstr &MI, + MachineBasicBlock *BB) const { + const TargetInstrInfo &TII = *BB->getParent()->getSubtarget().getInstrInfo(); + DebugLoc DL = MI.getDebugLoc(); + unsigned Opc = MI.getOpcode(); + bool isSelectRROp = (Opc == SBF::Select || + Opc == SBF::Select_64_32 || + Opc == SBF::Select_32 || + Opc == SBF::Select_32_64); + + bool isAtomicFence = Opc == SBF::ATOMIC_FENCE; + +#ifndef NDEBUG + bool isSelectRIOp = (Opc == SBF::Select_Ri || + Opc == SBF::Select_Ri_64_32 || + Opc == SBF::Select_Ri_32 || + Opc == SBF::Select_Ri_32_64); + + + assert((isSelectRROp || isSelectRIOp || isAtomicFence) && + "Unexpected instr type to insert"); +#endif + + + if (isAtomicFence) { + // this is currently a nop + MI.eraseFromParent(); + return BB; + } + + bool is32BitCmp = (Opc == SBF::Select_32 || + Opc == SBF::Select_32_64 || + Opc == SBF::Select_Ri_32 || + Opc == SBF::Select_Ri_32_64); + + // To "insert" a SELECT instruction, we actually have to insert the diamond + // control-flow pattern. The incoming instruction knows the destination vreg + // to set, the condition code register to branch on, the true/false values to + // select between, and a branch opcode to use. + const BasicBlock *LLVM_BB = BB->getBasicBlock(); + MachineFunction::iterator I = ++BB->getIterator(); + + // ThisMBB: + // ... + // TrueVal = ... + // jmp_XX r1, r2 goto Copy1MBB + // fallthrough --> Copy0MBB + MachineBasicBlock *ThisMBB = BB; + MachineFunction *F = BB->getParent(); + MachineBasicBlock *Copy0MBB = F->CreateMachineBasicBlock(LLVM_BB); + MachineBasicBlock *Copy1MBB = F->CreateMachineBasicBlock(LLVM_BB); + + F->insert(I, Copy0MBB); + F->insert(I, Copy1MBB); + // Update machine-CFG edges by transferring all successors of the current + // block to the new block which will contain the Phi node for the select. + Copy1MBB->splice(Copy1MBB->begin(), BB, + std::next(MachineBasicBlock::iterator(MI)), BB->end()); + Copy1MBB->transferSuccessorsAndUpdatePHIs(BB); + // Next, add the true and fallthrough blocks as its successors. + BB->addSuccessor(Copy0MBB); + BB->addSuccessor(Copy1MBB); + + // Insert Branch if Flag + int CC = MI.getOperand(3).getImm(); + int NewCC; + switch (CC) { +#define SET_NEWCC(X, Y) \ + case ISD::X: \ + NewCC = isSelectRROp ? SBF::Y##_rr : SBF::Y##_ri; \ + break + SET_NEWCC(SETGT, JSGT); + SET_NEWCC(SETUGT, JUGT); + SET_NEWCC(SETGE, JSGE); + SET_NEWCC(SETUGE, JUGE); + SET_NEWCC(SETEQ, JEQ); + SET_NEWCC(SETNE, JNE); + SET_NEWCC(SETLT, JSLT); + SET_NEWCC(SETULT, JULT); + SET_NEWCC(SETLE, JSLE); + SET_NEWCC(SETULE, JULE); + default: + report_fatal_error("unimplemented select CondCode " + Twine(CC)); + } + + Register LHS = MI.getOperand(1).getReg(); + bool isSignedCmp = (CC == ISD::SETGT || + CC == ISD::SETGE || + CC == ISD::SETLT || + CC == ISD::SETLE); + + // SBF at the moment only has 64-bit comparison. Any 32-bit comparison needs + // to be promoted. If we are comparing against an immediate value, we must + // sign extend the registers. Likewise for signed comparisons. Unsigned + // comparisons will zero extent registers. + if (is32BitCmp) + LHS = EmitSubregExt(MI, BB, LHS, isSignedCmp || !isSelectRROp); + + if (isSelectRROp) { + Register RHS = MI.getOperand(2).getReg(); + + if (is32BitCmp) + RHS = EmitSubregExt(MI, BB, RHS, isSignedCmp); + + BuildMI(BB, DL, TII.get(NewCC)).addReg(LHS).addReg(RHS).addMBB(Copy1MBB); + } else { + int64_t imm32 = MI.getOperand(2).getImm(); + // Check before we build J*_ri instruction. + assert (isInt<32>(imm32)); + BuildMI(BB, DL, TII.get(NewCC)) + .addReg(LHS).addImm(imm32).addMBB(Copy1MBB); + } + + // Copy0MBB: + // %FalseValue = ... + // # fallthrough to Copy1MBB + BB = Copy0MBB; + + // Update machine-CFG edges + BB->addSuccessor(Copy1MBB); + + // Copy1MBB: + // %Result = phi [ %FalseValue, Copy0MBB ], [ %TrueValue, ThisMBB ] + // ... + BB = Copy1MBB; + BuildMI(*BB, BB->begin(), DL, TII.get(SBF::PHI), MI.getOperand(0).getReg()) + .addReg(MI.getOperand(5).getReg()) + .addMBB(Copy0MBB) + .addReg(MI.getOperand(4).getReg()) + .addMBB(ThisMBB); + + MI.eraseFromParent(); // The pseudo instruction is gone now. + return BB; +} + +EVT SBFTargetLowering::getSetCCResultType(const DataLayout &, LLVMContext &, + EVT VT) const { + return getHasAlu32() ? MVT::i32 : MVT::i64; +} + +MVT SBFTargetLowering::getScalarShiftAmountTy(const DataLayout &DL, + EVT VT) const { + return (getHasAlu32() && VT == MVT::i32) ? MVT::i32 : MVT::i64; +} + +bool SBFTargetLowering::isLegalAddressingMode(const DataLayout &DL, + const AddrMode &AM, Type *Ty, + unsigned AS, + Instruction *I) const { + // No global is ever allowed as a base. + if (AM.BaseGV) + return false; + + switch (AM.Scale) { + case 0: // "r+i" or just "i", depending on HasBaseReg. + break; + case 1: + if (!AM.HasBaseReg) // allow "r+i". + break; + return false; // disallow "r+r" or "r+r+i". + default: + return false; + } + + return true; +} diff --git a/llvm/lib/Target/SBF/SBFISelLowering.h b/llvm/lib/Target/SBF/SBFISelLowering.h new file mode 100644 index 0000000000000..c7ee065165a54 --- /dev/null +++ b/llvm/lib/Target/SBF/SBFISelLowering.h @@ -0,0 +1,169 @@ +//===-- SBFISelLowering.h - SBF DAG Lowering Interface ----------*- 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 +// +//===----------------------------------------------------------------------===// +// +// This file defines the interfaces that SBF uses to lower LLVM code into a +// selection DAG. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIB_TARGET_SBF_SBFISELLOWERING_H +#define LLVM_LIB_TARGET_SBF_SBFISELLOWERING_H + +#include "SBF.h" +#include "llvm/CodeGen/SelectionDAG.h" +#include "llvm/CodeGen/TargetLowering.h" + +namespace llvm { +class SBFSubtarget; +namespace SBFISD { +enum NodeType : unsigned { + FIRST_NUMBER = ISD::BUILTIN_OP_END, + RET_GLUE, + CALL, + SELECT_CC, + BR_CC, + Wrapper, +}; +} + +class SBFTargetLowering : public TargetLowering { + const SBFSubtarget *Subtarget; +public: + explicit SBFTargetLowering(const TargetMachine &TM, const SBFSubtarget &STI); + + bool allowsMisalignedMemoryAccesses(EVT VT, unsigned, Align, + MachineMemOperand::Flags, + unsigned *) const override; + + // Provide custom lowering hooks for some operations. + SDValue LowerOperation(SDValue Op, SelectionDAG &DAG) const override; + + // This method returns the name of a target specific DAG node. + const char *getTargetNodeName(unsigned Opcode) const override; + + // This method decides whether folding a constant offset + // with the given GlobalAddress is legal. + bool isOffsetFoldingLegal(const GlobalAddressSDNode *GA) const override; + + SBFTargetLowering::ConstraintType + getConstraintType(StringRef Constraint) const override; + + std::pair + getRegForInlineAsmConstraint(const TargetRegisterInfo *TRI, + StringRef Constraint, MVT VT) const override; + + MachineBasicBlock * + EmitInstrWithCustomInserter(MachineInstr &MI, + MachineBasicBlock *BB) const override; + + bool getHasAlu32() const { return HasAlu32; } + bool getHasJmpExt() const { return HasJmpExt; } + + EVT getSetCCResultType(const DataLayout &DL, LLVMContext &Context, + EVT VT) const override; + + MVT getScalarShiftAmountTy(const DataLayout &, EVT) const override; + +private: + // Control Instruction Selection Features + bool HasAlu32; + bool HasJmpExt; + + SDValue LowerBR_CC(SDValue Op, SelectionDAG &DAG) const; + SDValue LowerSELECT_CC(SDValue Op, SelectionDAG &DAG) const; + + SDValue LowerConstantPool(SDValue Op, SelectionDAG &DAG) const; + SDValue LowerGlobalAddress(SDValue Op, SelectionDAG &DAG) const; + SDValue LowerATOMICRMW(SDValue Op, SelectionDAG &DAG) const; + + template + SDValue getAddr(NodeTy *N, SelectionDAG &DAG, unsigned Flags = 0) const; + + // Lower the result values of a call, copying them out of physregs into vregs + SDValue LowerCallResult(SDValue Chain, SDValue InGlue, + CallingConv::ID CallConv, bool IsVarArg, + const SmallVectorImpl &Ins, + const SDLoc &DL, SelectionDAG &DAG, + SmallVectorImpl &InVals) const; + + // Maximum number of arguments to a call + static const unsigned MaxArgs; + + // Lower a call into CALLSEQ_START - SBFISD:CALL - CALLSEQ_END chain + SDValue LowerCall(TargetLowering::CallLoweringInfo &CLI, + SmallVectorImpl &InVals) const override; + + /// Returns true if arguments should be sign-extended in lib calls. + bool shouldSignExtendTypeInLibCall(Type* Ty, bool IsSigned) const override; + + // Lower incoming arguments, copy physregs into vregs + SDValue LowerFormalArguments(SDValue Chain, CallingConv::ID CallConv, + bool IsVarArg, + const SmallVectorImpl &Ins, + const SDLoc &DL, SelectionDAG &DAG, + SmallVectorImpl &InVals) const override; + + bool CanLowerReturn(CallingConv::ID CallConv, MachineFunction &MF, + bool IsVarArg, + const SmallVectorImpl &Outs, + LLVMContext &Context, const Type *RetTy) const override; + + SDValue LowerReturn(SDValue Chain, CallingConv::ID CallConv, bool IsVarArg, + const SmallVectorImpl &Outs, + const SmallVectorImpl &OutVals, const SDLoc &DL, + SelectionDAG &DAG) const override; + + void ReplaceNodeResults(SDNode *N, SmallVectorImpl &Results, + SelectionDAG &DAG) const override; + + EVT getOptimalMemOpType(const MemOp &Op, + const AttributeList &FuncAttributes) const override { + return Op.size() >= 8 ? MVT::i64 : MVT::i32; + } + + bool isIntDivCheap(EVT VT, AttributeList Attr) const override { return true; } + + bool shouldConvertConstantLoadToIntImm(const APInt &Imm, + Type *Ty) const override { + return true; + } + + // Prevent reducing load width during SelectionDag phase. + // Otherwise, we may transform the following + // ctx = ctx + reloc_offset + // ... (*(u32 *)ctx) & 0x8000... + // to + // ctx = ctx + reloc_offset + // ... (*(u8 *)(ctx + 1)) & 0x80 ... + // which will be rejected by the verifier. + bool shouldReduceLoadWidth(SDNode *Load, ISD::LoadExtType ExtTy, + EVT NewVT) const override { + return false; + } + + bool isLegalAddressingMode(const DataLayout &DL, const AddrMode &AM, + Type *Ty, unsigned AS, + Instruction *I = nullptr) const override; + + // isTruncateFree - Return true if it's free to truncate a value of + // type Ty1 to type Ty2. e.g. On SBF at alu32 mode, it's free to truncate + // a i64 value in register R1 to i32 by referencing its sub-register W1. + bool isTruncateFree(Type *Ty1, Type *Ty2) const override; + bool isTruncateFree(EVT VT1, EVT VT2) const override; + + // For 32bit ALU result zext to 64bit is free. + bool isZExtFree(Type *Ty1, Type *Ty2) const override; + bool isZExtFree(EVT VT1, EVT VT2) const override; + + unsigned EmitSubregExt(MachineInstr &MI, MachineBasicBlock *BB, unsigned Reg, + bool isSigned) const; + +}; +} + +#endif diff --git a/llvm/lib/Target/SBF/SBFInstrFormats.td b/llvm/lib/Target/SBF/SBFInstrFormats.td new file mode 100644 index 0000000000000..8821ed39b3375 --- /dev/null +++ b/llvm/lib/Target/SBF/SBFInstrFormats.td @@ -0,0 +1,147 @@ +//===-- SBFInstrFormats.td - SBF Instruction Formats -------*- tablegen -*-===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +class SBFOpClass val> { + bits<3> Value = val; +} + +def SBF_LD : SBFOpClass<0x0>; +def SBF_LDX : SBFOpClass<0x1>; +def SBF_ST : SBFOpClass<0x2>; +def SBF_STX : SBFOpClass<0x3>; +def SBF_ALU : SBFOpClass<0x4>; +def SBF_JMP : SBFOpClass<0x5>; +def SBF_PQR : SBFOpClass<0x6>; +def SBF_ALU64 : SBFOpClass<0x7>; + +def SBF_LD_V2 : SBFOpClass<0x4>; +def SBF_ST_V2 : SBFOpClass<0x7>; + +class SBFSrcType val> { + bits<1> Value = val; +} + +def SBF_K : SBFSrcType<0x0>; +def SBF_X : SBFSrcType<0x1>; + +class SBFArithOp val> { + bits<4> Value = val; +} + +def SBF_ADD : SBFArithOp<0x0>; +def SBF_SUB : SBFArithOp<0x1>; +def SBF_MUL : SBFArithOp<0x2>; +def SBF_DIV : SBFArithOp<0x3>; +def SBF_OR : SBFArithOp<0x4>; +def SBF_AND : SBFArithOp<0x5>; +def SBF_LSH : SBFArithOp<0x6>; +def SBF_RSH : SBFArithOp<0x7>; +def SBF_NEG : SBFArithOp<0x8>; +def SBF_MOD : SBFArithOp<0x9>; +def SBF_XOR : SBFArithOp<0xa>; +def SBF_MOV : SBFArithOp<0xb>; +def SBF_ARSH : SBFArithOp<0xc>; +def SBF_END : SBFArithOp<0xd>; +def SBF_SDIV : SBFArithOp<0xe>; +def SBF_HOR : SBFArithOp<0xf>; + +def PQR_UHMUL : SBFArithOp<0x2>; +def PQR_UDIV : SBFArithOp<0x4>; +def PQR_UREM : SBFArithOp<0x6>; +def PQR_LMUL : SBFArithOp<0x8>; +def PQR_SHMUL : SBFArithOp<0xa>; +def PQR_SDIV : SBFArithOp<0xc>; +def PQR_SREM : SBFArithOp<0xe>; + +def SBF_XCHG : SBFArithOp<0xe>; +def SBF_CMPXCHG : SBFArithOp<0xf>; + +class SBFEndDir val> { + bits<1> Value = val; +} + +def SBF_TO_LE : SBFSrcType<0x0>; +def SBF_TO_BE : SBFSrcType<0x1>; + +class SBFJumpOp val> { + bits<4> Value = val; +} + +def SBF_JA : SBFJumpOp<0x0>; +def SBF_JEQ : SBFJumpOp<0x1>; +def SBF_JGT : SBFJumpOp<0x2>; +def SBF_JGE : SBFJumpOp<0x3>; +def SBF_JNE : SBFJumpOp<0x5>; +def SBF_JSGT : SBFJumpOp<0x6>; +def SBF_JSGE : SBFJumpOp<0x7>; +def SBF_CALL : SBFJumpOp<0x8>; +def SBF_EXIT : SBFJumpOp<0x9>; +def SBF_JLT : SBFJumpOp<0xa>; +def SBF_JLE : SBFJumpOp<0xb>; +def SBF_JSLT : SBFJumpOp<0xc>; +def SBF_JSLE : SBFJumpOp<0xd>; +def SBF_SYSCALL : SBFJumpOp<0x9>; + +class SBFWidthModifer val> { + bits<2> Value = val; +} + +def SBF_W : SBFWidthModifer<0x0>; +def SBF_H : SBFWidthModifer<0x1>; +def SBF_B : SBFWidthModifer<0x2>; +def SBF_DW : SBFWidthModifer<0x3>; + +class SBFSizeModifier val> { + bits<4> Value = val; +} + +def SBF_B_V2 : SBFSizeModifier<0x2>; +def SBF_H_V2 : SBFSizeModifier<0x3>; +def SBF_W_V2 : SBFSizeModifier<0x8>; +def SBF_DW_V2 : SBFSizeModifier<0x9>; + +class SBFModeModifer val> { + bits<3> Value = val; +} + +def SBF_IMM : SBFModeModifer<0x0>; +def SBF_ABS : SBFModeModifer<0x1>; +def SBF_IND : SBFModeModifer<0x2>; +def SBF_MEM : SBFModeModifer<0x3>; +def SBF_ATOMIC : SBFModeModifer<0x6>; + +class SBFAtomicFlag val> { + bits<4> Value = val; +} + +def SBF_FETCH : SBFAtomicFlag<0x1>; + +class InstSBF pattern> + : Instruction { + field bits<64> Inst; + field bits<64> SoftFail = 0; + let Size = 8; + + let Namespace = "SBF"; + let DecoderNamespace = "SBF"; + + SBFOpClass SBFClass; + let Inst{58-56} = SBFClass.Value; + + dag OutOperandList = outs; + dag InOperandList = ins; + let AsmString = asmstr; + let Pattern = pattern; +} + +// Pseudo instructions +class Pseudo pattern> + : InstSBF { + let Inst{63-0} = 0; + let isPseudo = 1; +} diff --git a/llvm/lib/Target/SBF/SBFInstrInfo.cpp b/llvm/lib/Target/SBF/SBFInstrInfo.cpp new file mode 100644 index 0000000000000..ef98d0c9bceff --- /dev/null +++ b/llvm/lib/Target/SBF/SBFInstrInfo.cpp @@ -0,0 +1,502 @@ +//===-- SBFInstrInfo.cpp - SBF Instruction Information ----------*- 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 +// +//===----------------------------------------------------------------------===// +// +// This file contains the SBF implementation of the TargetInstrInfo class. +// +//===----------------------------------------------------------------------===// + +#include "SBFInstrInfo.h" +#include "SBF.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/CodeGen/MachineBasicBlock.h" +#include "llvm/CodeGen/MachineInstrBuilder.h" +#include "llvm/IR/DebugLoc.h" +#include "llvm/Support/ErrorHandling.h" +#include + +#define GET_INSTRINFO_CTOR_DTOR +#include "SBFGenInstrInfo.inc" + +using namespace llvm; + +static inline bool isUncondBranchOpcode(int Opc) { return Opc == SBF::JMP; } + +static inline bool isCondBranchOpcode(int Opc) { + switch (Opc) { + case SBF::JEQ_ri: + case SBF::JEQ_rr: + case SBF::JUGT_ri: + case SBF::JUGT_rr: + case SBF::JUGE_ri: + case SBF::JUGE_rr: + case SBF::JNE_ri: + case SBF::JNE_rr: + case SBF::JSGT_ri: + case SBF::JSGT_rr: + case SBF::JSGE_ri: + case SBF::JSGE_rr: + case SBF::JULT_ri: + case SBF::JULT_rr: + case SBF::JULE_ri: + case SBF::JULE_rr: + case SBF::JSLT_ri: + case SBF::JSLT_rr: + case SBF::JSLE_ri: + case SBF::JSLE_rr: + return true; + default: + return false; + } +} + +static void parseCondBranch(MachineInstr *LastInst, MachineBasicBlock *&Target, + SmallVectorImpl &Cond) { + Cond.push_back(MachineOperand::CreateImm(LastInst->getOpcode())); + Cond.push_back(LastInst->getOperand(0)); + Cond.push_back(LastInst->getOperand(1)); + Target = LastInst->getOperand(2).getMBB(); +} + +SBFInstrInfo::SBFInstrInfo() + : SBFGenInstrInfo(SBF::ADJCALLSTACKDOWN, SBF::ADJCALLSTACKUP) {} + +void SBFInstrInfo::initializeTargetFeatures(bool HasExplicitSext, bool NewMemEncoding) { + this->HasExplicitSignExt = HasExplicitSext; + this->NewMemEncoding = NewMemEncoding; +} + +void SBFInstrInfo::copyPhysReg(MachineBasicBlock &MBB, + MachineBasicBlock::iterator I, + const DebugLoc &DL, MCRegister DestReg, + MCRegister SrcReg, bool KillSrc, + bool RenamableDest, bool RenamableSrc) const { + if (SBF::GPRRegClass.contains(DestReg, SrcReg)) + BuildMI(MBB, I, DL, get(SBF::MOV_rr), DestReg) + .addReg(SrcReg, getKillRegState(KillSrc)); + else if (SBF::GPR32RegClass.contains(DestReg, SrcReg)) { + unsigned OpCode = + HasExplicitSignExt ? SBF::MOV_rr_32_no_sext_v2 + : SBF::MOV_rr_32_no_sext_v1; + BuildMI(MBB, I, DL, get(OpCode), DestReg) + .addReg(SrcReg, getKillRegState(KillSrc)); + } + else + llvm_unreachable("Impossible reg-to-reg copy"); +} + +void SBFInstrInfo::storeRegToStackSlot(MachineBasicBlock &MBB, + MachineBasicBlock::iterator I, + Register SrcReg, bool IsKill, int FI, + const TargetRegisterClass *RC, + const TargetRegisterInfo *TRI, + Register VReg, + MachineInstr::MIFlag Flags) const { + DebugLoc DL; + if (I != MBB.end()) + DL = I->getDebugLoc(); + + if (RC == &SBF::GPRRegClass) + BuildMI(MBB, I, DL, get(NewMemEncoding ? + SBF::STD_V2 : SBF::STD_V1)) + .addReg(SrcReg, getKillRegState(IsKill)) + .addFrameIndex(FI) + .addImm(0); + else if (RC == &SBF::GPR32RegClass) + BuildMI(MBB, I, DL, get(NewMemEncoding ? + SBF::STW32_V2 : SBF::STW32_V1)) + .addReg(SrcReg, getKillRegState(IsKill)) + .addFrameIndex(FI) + .addImm(0); + else + llvm_unreachable("Can't store this register to stack slot"); +} + +Register SBFInstrInfo::isStoreToStackSlot(const MachineInstr &MI, + int &FrameIndex, + unsigned &MemBytes) const { + switch (MI.getOpcode()) { + default: + break; + case SBF::STD_V2: + case SBF::STD_V1: + MemBytes = 8; + if (MI.getOperand(0).isReg() && MI.getOperand(1).isFI() && + MI.getOperand(2).isImm() && MI.getOperand(2).getImm() == 0) { + FrameIndex = MI.getOperand(1).getIndex(); + return MI.getOperand(0).getReg(); + } + break; + case SBF::STW32_V2: + case SBF::STW32_V1: + MemBytes = 4; + if (MI.getOperand(0).isReg() && MI.getOperand(1).isFI() && + MI.getOperand(2).isImm() && MI.getOperand(2).getImm() == 0) { + FrameIndex = MI.getOperand(1).getIndex(); + return MI.getOperand(0).getReg(); + } + break; + } + + return 0; +} + +Register SBFInstrInfo::isStoreToStackSlot(const MachineInstr &MI, + int &FrameIndex) const { + unsigned MemBytes = 0; + return isStoreToStackSlot(MI, FrameIndex, MemBytes); +} + +void SBFInstrInfo::loadRegFromStackSlot(MachineBasicBlock &MBB, + MachineBasicBlock::iterator I, + Register DestReg, int FI, + const TargetRegisterClass *RC, + const TargetRegisterInfo *TRI, + Register VReg, + MachineInstr::MIFlag Flags) const { + DebugLoc DL; + if (I != MBB.end()) + DL = I->getDebugLoc(); + + if (RC == &SBF::GPRRegClass) + BuildMI(MBB, I, DL, get(NewMemEncoding ? + SBF::LDD_V2 : SBF::LDD_V1), + DestReg).addFrameIndex(FI).addImm(0); + else if (RC == &SBF::GPR32RegClass) + BuildMI(MBB, I, DL, get(NewMemEncoding ? + SBF::LDW32_V2 : SBF::LDW32_V1), + DestReg).addFrameIndex(FI).addImm(0); + else + llvm_unreachable("Can't load this register from stack slot"); +} + +Register SBFInstrInfo::isLoadFromStackSlot(const MachineInstr &MI, + int &FrameIndex, + unsigned &MemBytes) const { + switch (MI.getOpcode()) { + default: + break; + case SBF::LDD_V2: + case SBF::LDD_V1: + MemBytes = 8; + if (MI.getOperand(0).isReg() && MI.getOperand(1).isFI() && + MI.getOperand(2).isImm() && MI.getOperand(2).getImm() == 0) { + FrameIndex = MI.getOperand(1).getIndex(); + return MI.getOperand(0).getReg(); + } + break; + case SBF::LDW32_V2: + case SBF::LDW32_V1: + MemBytes = 4; + if (MI.getOperand(0).isReg() && MI.getOperand(1).isFI() && + MI.getOperand(2).isImm() && MI.getOperand(2).getImm() == 0) { + FrameIndex = MI.getOperand(1).getIndex(); + return MI.getOperand(0).getReg(); + } + break; + } + + return 0; +} + +Register SBFInstrInfo::isLoadFromStackSlot(const MachineInstr &MI, + int &FrameIndex) const { + unsigned MemBytes = 0; + return isLoadFromStackSlot(MI, FrameIndex, MemBytes); +} + +bool SBFInstrInfo::analyzeBranch(MachineBasicBlock &MBB, + MachineBasicBlock *&TBB, + MachineBasicBlock *&FBB, + SmallVectorImpl &Cond, + bool AllowModify) const { + // If the block has no terminators, it just falls into the block after it. + MachineBasicBlock::iterator I = MBB.getLastNonDebugInstr(); + if (I == MBB.end()) + return false; + + if (!isUnpredicatedTerminator(*I)) + return false; + + // Get the last instruction in the block. + MachineInstr *LastInst = &*I; + + // If there is only one terminator instruction, process it. + unsigned LastOpc = LastInst->getOpcode(); + if (I == MBB.begin() || !isUnpredicatedTerminator(*--I)) { + if (isUncondBranchOpcode(LastOpc)) { + TBB = LastInst->getOperand(0).getMBB(); + return false; + } + if (isCondBranchOpcode(LastOpc)) { + // Block ends with fall-through condbranch. + parseCondBranch(LastInst, TBB, Cond); + return false; + } + return true; // Unknown case + } + + // Get the instruction before it if it is a terminator. + MachineInstr *SecondLastInst = &*I; + unsigned SecondLastOpc = SecondLastInst->getOpcode(); + + // If AllowModify is true and the block ends with two or more unconditional + // branches, delete all but the first unconditional branch. + if (AllowModify && isUncondBranchOpcode(LastOpc)) { + while (isUncondBranchOpcode(SecondLastOpc)) { + LastInst->eraseFromParent(); + LastInst = SecondLastInst; + LastOpc = LastInst->getOpcode(); + if (I == MBB.begin() || !isUnpredicatedTerminator(*--I)) { + // Return now the only terminator is an unconditional branch. + TBB = LastInst->getOperand(0).getMBB(); + return false; + } + SecondLastInst = &*I; + SecondLastOpc = SecondLastInst->getOpcode(); + } + } + + // If we're allowed to modify and the block ends in a unconditional branch + // which could simply fallthrough, remove the branch. (Note: This case only + // matters when we can't understand the whole sequence, otherwise it's also + // handled by BranchFolding.cpp.) + if (AllowModify && isUncondBranchOpcode(LastOpc) && + MBB.isLayoutSuccessor(getBranchDestBlock(*LastInst))) { + LastInst->eraseFromParent(); + LastInst = SecondLastInst; + LastOpc = LastInst->getOpcode(); + if (I == MBB.begin() || !isUnpredicatedTerminator(*--I)) { + assert(!isUncondBranchOpcode(LastOpc) && + "unreachable unconditional branches removed above"); + + if (isCondBranchOpcode(LastOpc)) { + // Block ends with fall-through condbranch. + parseCondBranch(LastInst, TBB, Cond); + return false; + } + return true; // Can't handle indirect branch. + } + SecondLastInst = &*I; + SecondLastOpc = SecondLastInst->getOpcode(); + } + + // If there are three terminators, we don't know what sort of block this is. + if (SecondLastInst && I != MBB.begin() && isUnpredicatedTerminator(*--I)) + return true; + + // If the block ends with a conditional jump and a JA, handle it. + if (isCondBranchOpcode(SecondLastOpc) && isUncondBranchOpcode(LastOpc)) { + parseCondBranch(SecondLastInst, TBB, Cond); + FBB = LastInst->getOperand(0).getMBB(); + return false; + } + + // If the block ends with two unconditional branches, handle it. The second + // one is not executed, so remove it. + if (isUncondBranchOpcode(SecondLastOpc) && isUncondBranchOpcode(LastOpc)) { + TBB = SecondLastInst->getOperand(0).getMBB(); + I = LastInst; + if (AllowModify) + I->eraseFromParent(); + return false; + } + + // Otherwise, can't handle this. + return true; +} + +unsigned SBFInstrInfo::insertBranch(MachineBasicBlock &MBB, + MachineBasicBlock *TBB, + MachineBasicBlock *FBB, + ArrayRef Cond, + const DebugLoc &DL, int *BytesAdded) const { + assert(!BytesAdded && "code size not handled"); + + // Shouldn't be a fall through. + assert(TBB && "insertBranch must not be told to insert a fallthrough"); + + if (BytesAdded) + *BytesAdded = 8; + + if (Cond.empty()) { + // Unconditional branch + assert(!FBB && "Unconditional branch with multiple successors!"); + BuildMI(&MBB, DL, get(SBF::JMP)).addMBB(TBB); + return 1; + } + + // See the order we parse the jump information in `parseCondBranch` + BuildMI(&MBB, DL, get(Cond[0].getImm())) + .add(Cond[1]) + .add(Cond[2]) + .addMBB(TBB); + + if (FBB) { + BuildMI(&MBB, DL, get(SBF::JMP)).addMBB(FBB); + if (BytesAdded) + *BytesAdded += 8; + } + + return 1; +} + +unsigned SBFInstrInfo::removeBranch(MachineBasicBlock &MBB, + int *BytesRemoved) const { + assert(!BytesRemoved && "code size not handled"); + + MachineBasicBlock::iterator I = MBB.getLastNonDebugInstr(); + if (I == MBB.end()) + return 0; + + if (!isUncondBranchOpcode(I->getOpcode()) && + !isCondBranchOpcode(I->getOpcode())) + return 0; + + // Remove the branch. + I->eraseFromParent(); + + I = MBB.end(); + + if (I == MBB.begin()) { + if (BytesRemoved) + *BytesRemoved = 8; + return 1; + } + + --I; + if (!isCondBranchOpcode(I->getOpcode())) { + if (BytesRemoved) + *BytesRemoved = 8; + return 1; + } + + // Remove the branch. + I->eraseFromParent(); + if (BytesRemoved) + *BytesRemoved = 16; + + return 2; +} + +bool SBFInstrInfo::reverseBranchCondition( + SmallVectorImpl &Cond) const { + switch (Cond[0].getImm()) { + default: + llvm_unreachable("Unknown conditional branch!"); + case SBF::JEQ_ri: + Cond[0].setImm(SBF::JNE_ri); + break; + case SBF::JEQ_rr: + Cond[0].setImm(SBF::JNE_rr); + break; + case SBF::JUGT_ri: + Cond[0].setImm(SBF::JULE_ri); + break; + case SBF::JUGT_rr: + Cond[0].setImm(SBF::JULE_rr); + break; + case SBF::JUGE_ri: + Cond[0].setImm(SBF::JULT_ri); + break; + case SBF::JUGE_rr: + Cond[0].setImm(SBF::JULT_rr); + break; + case SBF::JNE_ri: + Cond[0].setImm(SBF::JEQ_ri); + break; + case SBF::JNE_rr: + Cond[0].setImm(SBF::JEQ_rr); + break; + case SBF::JSGT_ri: + Cond[0].setImm(SBF::JSLE_ri); + break; + case SBF::JSGT_rr: + Cond[0].setImm(SBF::JSLE_rr); + break; + case SBF::JSGE_ri: + Cond[0].setImm(SBF::JSLT_ri); + break; + case SBF::JSGE_rr: + Cond[0].setImm(SBF::JSLT_rr); + break; + case SBF::JULT_ri: + Cond[0].setImm(SBF::JUGE_ri); + break; + case SBF::JULT_rr: + Cond[0].setImm(SBF::JUGE_rr); + break; + case SBF::JULE_ri: + Cond[0].setImm(SBF::JUGT_ri); + break; + case SBF::JULE_rr: + Cond[0].setImm(SBF::JUGT_rr); + break; + case SBF::JSLT_ri: + Cond[0].setImm(SBF::JSGE_ri); + break; + case SBF::JSLT_rr: + Cond[0].setImm(SBF::JSGE_rr); + break; + case SBF::JSLE_ri: + Cond[0].setImm(SBF::JSGT_ri); + break; + case SBF::JSLE_rr: + Cond[0].setImm(SBF::JSGT_rr); + break; + } + + return false; +} + +MachineBasicBlock * +SBFInstrInfo::getBranchDestBlock(const MachineInstr &MI) const { + unsigned Opcode = MI.getOpcode(); + if (Opcode == SBF::JMP) { + return MI.getOperand(0).getMBB(); + } + + if (isCondBranchOpcode(Opcode)) { + return MI.getOperand(2).getMBB(); + } + + llvm_unreachable("unexpected opcode!"); +} + +unsigned SBFInstrInfo::getInstSizeInBytes(const MachineInstr &MI) const { + if (MI.getOpcode() == SBF::LD_imm64) + return 16; + + return 8; +} + +std::optional SBFInstrInfo::isAddImmediate(const MachineInstr &MI, + Register Reg) const { + const MachineOperand &Op0 = MI.getOperand(0); + if (!Op0.isReg() || Reg != Op0.getReg()) + return std::nullopt; + + if (!MI.getOperand(1).isReg() || !MI.getOperand(2).isImm()) + return std::nullopt; + + int Sign = 1; + int64_t Offset = 0; + unsigned Opcode = MI.getOpcode(); + switch (Opcode) { + default: + return std::nullopt; + case SBF::SUB_ri: + case SBF::SUB_ri_32: + Sign *= -1; + [[fallthrough]]; + case SBF::ADD_ri: + case SBF::ADD_ri_32: { + Offset = MI.getOperand(2).getImm() * Sign; + return RegImmPair{MI.getOperand(1).getReg(), Offset}; + } + } +} diff --git a/llvm/lib/Target/SBF/SBFInstrInfo.h b/llvm/lib/Target/SBF/SBFInstrInfo.h new file mode 100644 index 0000000000000..e3b88039234cf --- /dev/null +++ b/llvm/lib/Target/SBF/SBFInstrInfo.h @@ -0,0 +1,90 @@ +//===-- SBFInstrInfo.h - SBF Instruction Information ------------*- 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 +// +//===----------------------------------------------------------------------===// +// +// This file contains the SBF implementation of the TargetInstrInfo class. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIB_TARGET_SBF_SBFINSTRINFO_H +#define LLVM_LIB_TARGET_SBF_SBFINSTRINFO_H + +#include "SBFRegisterInfo.h" +#include "llvm/CodeGen/TargetInstrInfo.h" + +#define GET_INSTRINFO_HEADER +#include "SBFGenInstrInfo.inc" + +namespace llvm { + +class SBFInstrInfo : public SBFGenInstrInfo { + const SBFRegisterInfo RI; + +public: + SBFInstrInfo(); + + const SBFRegisterInfo &getRegisterInfo() const { return RI; } + + void copyPhysReg(MachineBasicBlock &MBB, MachineBasicBlock::iterator I, + const DebugLoc &DL, MCRegister DestReg, MCRegister SrcReg, + bool KillSrc, bool RenamableDest = false, + bool RenamableSrc = false) const override; + + void storeRegToStackSlot( + MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI, Register SrcReg, + bool isKill, int FrameIndex, const TargetRegisterClass *RC, + const TargetRegisterInfo *TRI, Register VReg, + MachineInstr::MIFlag Flags = MachineInstr::NoFlags) const override; + + void loadRegFromStackSlot( + MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI, + Register DestReg, int FrameIndex, const TargetRegisterClass *RC, + const TargetRegisterInfo *TRI, Register VReg, + MachineInstr::MIFlag Flags = MachineInstr::NoFlags) const override; + + bool analyzeBranch(MachineBasicBlock &MBB, MachineBasicBlock *&TBB, + MachineBasicBlock *&FBB, + SmallVectorImpl &Cond, + bool AllowModify) const override; + + unsigned removeBranch(MachineBasicBlock &MBB, + int *BytesRemoved = nullptr) const override; + unsigned insertBranch(MachineBasicBlock &MBB, MachineBasicBlock *TBB, + MachineBasicBlock *FBB, ArrayRef Cond, + const DebugLoc &DL, + int *BytesAdded = nullptr) const override; + void initializeTargetFeatures(bool HasExplicitSext, bool NewMemEncoding); + + bool + reverseBranchCondition(SmallVectorImpl &Cond) const override; + + MachineBasicBlock *getBranchDestBlock(const MachineInstr &MI) const override; + + unsigned getInstSizeInBytes(const MachineInstr &MI) const override; + + std::optional isAddImmediate(const MachineInstr &MI, + Register Reg) const override; + + Register isStoreToStackSlot(const MachineInstr &MI, + int &FrameIndex) const override; + + Register isStoreToStackSlot(const MachineInstr &MI, int &FrameIndex, + unsigned &MemBytes) const override; + + Register isLoadFromStackSlot(const MachineInstr &MI, + int &FrameIndex) const override; + + Register isLoadFromStackSlot(const MachineInstr &MI, int &FrameIndex, + unsigned &MemBytes) const override; + +private: + bool HasExplicitSignExt; + bool NewMemEncoding; +}; +} + +#endif diff --git a/llvm/lib/Target/SBF/SBFInstrInfo.td b/llvm/lib/Target/SBF/SBFInstrInfo.td new file mode 100644 index 0000000000000..fff20cbd9ded7 --- /dev/null +++ b/llvm/lib/Target/SBF/SBFInstrInfo.td @@ -0,0 +1,1468 @@ +//===-- SBFInstrInfo.td - Target Description for SBF Target ---------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// +// +// This file describes the SBF instructions in TableGen format. +// +//===----------------------------------------------------------------------===// + +include "SBFInstrFormats.td" +include "SBFTargetFeatures.td" + +// Instruction Operands and Patterns + +// These are target-independent nodes, but have target-specific formats. +def SDT_SBFCallSeqStart : SDCallSeqStart<[SDTCisVT<0, iPTR>, + SDTCisVT<1, iPTR>]>; +def SDT_SBFCallSeqEnd : SDCallSeqEnd<[SDTCisVT<0, iPTR>, SDTCisVT<1, iPTR>]>; +def SDT_SBFCall : SDTypeProfile<0, -1, [SDTCisVT<0, iPTR>]>; +def SDT_SBFSetFlag : SDTypeProfile<0, 3, [SDTCisSameAs<0, 1>]>; +def SDT_SBFSelectCC : SDTypeProfile<1, 5, [SDTCisSameAs<1, 2>, + SDTCisSameAs<0, 4>, + SDTCisSameAs<4, 5>]>; +def SDT_SBFBrCC : SDTypeProfile<0, 4, [SDTCisSameAs<0, 1>, + SDTCisVT<3, OtherVT>]>; +def SDT_SBFWrapper : SDTypeProfile<1, 1, [SDTCisSameAs<0, 1>, + SDTCisPtrTy<0>]>; + +def SBFcall : SDNode<"SBFISD::CALL", SDT_SBFCall, + [SDNPHasChain, SDNPOptInGlue, SDNPOutGlue, + SDNPVariadic]>; +def SBFretglue : SDNode<"SBFISD::RET_GLUE", SDTNone, + [SDNPHasChain, SDNPOptInGlue, SDNPVariadic]>; +def SBFcallseq_start: SDNode<"ISD::CALLSEQ_START", SDT_SBFCallSeqStart, + [SDNPHasChain, SDNPOutGlue]>; +def SBFcallseq_end : SDNode<"ISD::CALLSEQ_END", SDT_SBFCallSeqEnd, + [SDNPHasChain, SDNPOptInGlue, SDNPOutGlue]>; +def SBFbrcc : SDNode<"SBFISD::BR_CC", SDT_SBFBrCC, + [SDNPHasChain, SDNPOutGlue, SDNPInGlue]>; + +def SBFselectcc : SDNode<"SBFISD::SELECT_CC", SDT_SBFSelectCC>; +def SBFWrapper : SDNode<"SBFISD::Wrapper", SDT_SBFWrapper>; +def SBFHasALU32 : Predicate<"Subtarget->getHasAlu32()">; +def SBFNoALU32 : Predicate<"!Subtarget->getHasAlu32()">; +def SBFHasLddw : Predicate<"!Subtarget->getNoLddw()">; +def SBFNoLddw : Predicate<"Subtarget->getNoLddw()">; +def SBFHasNeg : Predicate<"!Subtarget->getDisableNeg()">; +def SBFNoNeg: Predicate<"Subtarget->getDisableNeg()">; +def SBFRevSub : Predicate<"Subtarget->getReverseSubImm()">; +def SBFNoRevSub : Predicate<"!Subtarget->getReverseSubImm()">; +def SBFCallxSrc : Predicate<"Subtarget->getCallXRegSrc()">, AssemblerPredicate<(all_of FeatureCallxRegSrc)>; +def SBFNoCallxSrc : Predicate<"!Subtarget->getCallXRegSrc()">; +def SBFPqrInstr : Predicate<"Subtarget->getHasPqrClass()">; +def SBFNoPqrInstr : Predicate<"!Subtarget->getHasPqrClass()">; +def SBFHasStoreImm : Predicate<"Subtarget->getHasStoreImm()">; +def SBFExplicitSignExt : Predicate<"Subtarget->getHasExplicitSignExt()">; +def SBFNoExplicitSignExt : Predicate<"!Subtarget->getHasExplicitSignExt()">; +def SBFNewMemEncoding : Predicate<"Subtarget->getNewMemEncoding()">, AssemblerPredicate<(all_of FeatureNewMemEncoding)>; +def SBFOldMemEncoding : Predicate<"!Subtarget->getNewMemEncoding()">; +def SBFHasStaticSyscalls : Predicate<"Subtarget->getHasStaticSyscalls()">; +def SBFNoStaticSyscalls : Predicate<"!Subtarget->getHasStaticSyscalls()">; + +def brtarget : Operand { + let PrintMethod = "printBrTargetOperand"; +} +def calltarget : Operand; + +def u64imm : Operand { + let PrintMethod = "printImm64Operand"; +} + +def gpr_or_imm : Operand; + +def i64immSExt32 : PatLeaf<(i64 imm), + [{return isInt<32>(N->getSExtValue()); }]>; +def i32immSExt32 : PatLeaf<(i32 imm), + [{return isInt<32>(N->getSExtValue()); }]>; +def i64immZExt32 : PatLeaf<(i64 imm), + [{return isUInt<32>(N->getZExtValue()); }]>; + +def imm_to_i64 : SDNodeXFormgetTargetConstant(N->getZExtValue(), SDLoc(N), MVT::i64); +}]>; + +// Fetch the upper 32-bits of a 64-bit integer. +def Upper32 : SDNodeXFormgetSExtValue() >> 32; + return CurDAG->getTargetConstant(value, SDLoc(N), + N->getValueType(0)); +}]>; + +// Fetch the lower 32-bits of a 64-bit integer. +def Lower32 : SDNodeXFormgetSExtValue() & 0x00000000ffffffff; + return CurDAG->getTargetConstant(value, SDLoc(N), + N->getValueType(0)); +}]>; + + +// Addressing modes. +def ADDRri : ComplexPattern; +def FIri : ComplexPattern; + +// Address operands +def MEMri : Operand { + let PrintMethod = "printMemOperand"; + let EncoderMethod = "getMemoryOpValue"; + let DecoderMethod = "decodeMemoryOpValue"; + let MIOperandInfo = (ops GPR, i16imm); +} + +// Conditional code predicates - used for pattern matching for jump instructions +def SBF_CC_EQ : PatLeaf<(i64 imm), + [{return (N->getZExtValue() == ISD::SETEQ);}]>; +def SBF_CC_NE : PatLeaf<(i64 imm), + [{return (N->getZExtValue() == ISD::SETNE);}]>; +def SBF_CC_GE : PatLeaf<(i64 imm), + [{return (N->getZExtValue() == ISD::SETGE);}]>; +def SBF_CC_GT : PatLeaf<(i64 imm), + [{return (N->getZExtValue() == ISD::SETGT);}]>; +def SBF_CC_GTU : PatLeaf<(i64 imm), + [{return (N->getZExtValue() == ISD::SETUGT);}]>; +def SBF_CC_GEU : PatLeaf<(i64 imm), + [{return (N->getZExtValue() == ISD::SETUGE);}]>; +def SBF_CC_LE : PatLeaf<(i64 imm), + [{return (N->getZExtValue() == ISD::SETLE);}]>; +def SBF_CC_LT : PatLeaf<(i64 imm), + [{return (N->getZExtValue() == ISD::SETLT);}]>; +def SBF_CC_LTU : PatLeaf<(i64 imm), + [{return (N->getZExtValue() == ISD::SETULT);}]>; +def SBF_CC_LEU : PatLeaf<(i64 imm), + [{return (N->getZExtValue() == ISD::SETULE);}]>; + +// For arithmetic and jump instructions the 8-bit 'code' +// field is divided into three parts: +// +// +----------------+--------+--------------------+ +// | 4 bits | 1 bit | 3 bits | +// | operation code | source | instruction class | +// +----------------+--------+--------------------+ +// (MSB) (LSB) +class TYPE_ALU_JMP op, bits<1> srctype, + dag outs, dag ins, string asmstr, list pattern, + bit IsPqr64 = 0> + : InstSBF { + + // In the PQR class, instructions that deal with 64-bit registers have a different OpCode. + // To obtain it, we add one to its base value. + let Inst{63-60} = !if(IsPqr64, !add(op, 1), op); + let Inst{59} = srctype; +} + +//For load and store instructions the 8-bit 'code' field is divided as: +// +// +--------+--------+-------------------+ +// | 3 bits | 2 bits | 3 bits | +// | mode | size | instruction class | +// +--------+--------+-------------------+ +// (MSB) (LSB) +class TYPE_LD_ST mode, bits<2> size, + dag outs, dag ins, string asmstr, list pattern> + : InstSBF { + + let Inst{63-61} = mode; + let Inst{60-59} = size; +} + +//For load and store instructions in SBFv2 the 8-bit 'code' field is divided as: +// +// +--------+---------------+-------------------+ +// | 4 bits | 1 bit | 3 bits | +// | size | source type | instruction class | +// +--------+---------------+-------------------+ +// (MSB) (LSB) +class TYPE_LD_ST_V2 size, bits<1> srctype, + dag outs, dag ins, string asmstr, list pattern> + : InstSBF { + + let Inst{63-60} = size; + let Inst{59} = srctype; +} + + +// jump instructions +class JMP_RR + : TYPE_ALU_JMP { + bits<4> dst; + bits<4> src; + bits<16> BrDst; + + let Inst{55-52} = src; + let Inst{51-48} = dst; + let Inst{47-32} = BrDst; + let SBFClass = SBF_JMP; +} + +class JMP_RI + : TYPE_ALU_JMP { + bits<4> dst; + bits<16> BrDst; + bits<32> imm; + + let Inst{51-48} = dst; + let Inst{47-32} = BrDst; + let Inst{31-0} = imm; + let SBFClass = SBF_JMP; +} + +multiclass J { + def _rr : JMP_RR; + def _ri : JMP_RI; +} + +let isBranch = 1, isTerminator = 1, hasDelaySlot=0 in { +// cmp+goto instructions +defm JEQ : J; +defm JUGT : J; +defm JUGE : J; +defm JNE : J; +defm JSGT : J; +defm JSGE : J; +defm JULT : J; +defm JULE : J; +defm JSLT : J; +defm JSLE : J; +} + +// ALU instructions +class MATH_RI pattern, bit isPqr64 = 0> + : TYPE_ALU_JMP { + bits<4> dst; + bits<32> imm; + + let Inst{51-48} = dst; + let Inst{31-0} = imm; + let SBFClass = Class; +} + +class MATH_RR pattern, bit isPqr64 = 0> + : TYPE_ALU_JMP { + bits<4> dst; + bits<4> src; + + let Inst{55-52} = src; + let Inst{51-48} = dst; + let SBFClass = Class; +} + +multiclass MATH_32 { + def _rr_32 : MATH_RR; + def _ri_32 : MATH_RI; +} + +multiclass MATH_64 { + + defvar isPqr64 = !if(!eq(Class, SBF_PQR), 1, 0); + + def _rr : MATH_RR; + + def _ri : MATH_RI; +} + +multiclass ALU { + defm "" : MATH_64; + + defm "" : MATH_32; +} + +multiclass PQR { + defm "" : MATH_64; + defm "" : MATH_32; +} + +let Constraints = "$dst = $src2" in { + let isAsCheapAsAMove = 1 in { + defm ADD : ALU; + defm SUB : ALU; + defm OR : ALU; + defm AND : ALU; + defm SLL : ALU; + defm SRL : ALU; + defm XOR : ALU; + defm SRA : ALU; + + let Predicates = [SBFNoLddw] in { + def HOR : MATH_RI; + let DecoderNamespace = "SBFv2" in { + def HOR_addr : MATH_RI; + + } + } + } + + + let Predicates = [SBFNoPqrInstr] in { + defm MUL : ALU; + defm DIV : ALU; + defm MOD : ALU; + } + + let Predicates = [SBFPqrInstr] in { + defm UHMUL : MATH_64; + defm UDIV : PQR; + defm UREM : PQR; + defm LMUL : PQR; + defm SHMUL : MATH_64; + defm SDIV_pqr : PQR; + defm SREM : PQR; + } +} + +// Special case for SBFv2 +// In SBFv1, `sub reg, imm` is interpreted as reg = reg - imm, +// but in SBFv2 it means reg = imm - reg +def : Pat<(sub GPR:$src, i64immSExt32:$imm), + (SUB_ri GPR:$src, i64immSExt32:$imm)>, Requires<[SBFNoRevSub]>; +def : Pat<(sub GPR32:$src, i32immSExt32:$imm), + (SUB_ri_32 GPR32:$src, i32immSExt32:$imm)>, Requires<[SBFNoRevSub]>; + +def : Pat<(sub i64immSExt32:$imm, GPR:$src), + (SUB_ri GPR:$src, i64immSExt32:$imm)>, Requires<[SBFRevSub]>; +def : Pat<(sub i32immSExt32:$imm, GPR32:$src), + (SUB_ri_32 GPR32:$src, i32immSExt32:$imm)>, Requires<[SBFRevSub]>; + +class NEG_RR pattern> + : TYPE_ALU_JMP { + bits<4> dst; + + let Inst{51-48} = dst; + let SBFClass = Class; +} + +let Constraints = "$dst = $src", isAsCheapAsAMove = 1 in { + def NEG_64: NEG_RR; + def NEG_32: NEG_RR; +} + +// Instruction `neg` exists on SBFv1, but not on SBFv2 +// In SBFv2, the negate operation is done with a subtraction +def : Pat<(ineg i64:$src), (NEG_64 GPR:$src)>, Requires<[SBFHasNeg]>; +def : Pat<(ineg i32:$src), (NEG_32 GPR32:$src)>, Requires<[SBFHasNeg]>; + +def : Pat<(ineg i64:$src), (SUB_ri GPR:$src, 0)>, Requires<[SBFNoNeg]>; +def : Pat<(ineg i32:$src), (SUB_ri_32 GPR32:$src, 0)>, Requires<[SBFNoNeg]>; + + +class LD_IMM64 Pseudo, string Mnemonic> + : TYPE_LD_ST { + + bits<4> dst; + bits<64> imm; + + let Inst{51-48} = dst; + let Inst{55-52} = Pseudo; + let Inst{47-32} = 0; + let Inst{31-0} = imm{31-0}; + let SBFClass = SBF_LD; +} + +let isReMaterializable = 1, isAsCheapAsAMove = 1 in { +def LD_imm64 : LD_IMM64<0, "lddw">, Requires<[SBFHasLddw]>; +def MOV_rr : MATH_RR; +def MOV_ri : MATH_RI; + +def MOV_ri_32 : MATH_RI; + +let Predicates = [SBFExplicitSignExt], DecoderNamespace = "SBFv2" in { + def MOV_rr_32_no_sext_v2 : MATH_RR; +} + +let Predicates = [SBFExplicitSignExt], DecoderNamespace = "Repeated" in { + def MOV_ri_32_zext : MATH_RI; +} + +def MOV_rr_32_no_sext_v1 : MATH_RR, Requires<[SBFNoExplicitSignExt]>; +} + +def FI_ri + : TYPE_LD_ST { + // This is a tentative instruction, and will be replaced + // with MOV_rr and ADD_ri in PEI phase + let Inst{51-48} = 0; + let Inst{55-52} = 2; + let Inst{47-32} = 0; + let Inst{31-0} = 0; + let SBFClass = SBF_LD; + bit isPseudo = true; +} + +def LD_pseudo + : TYPE_LD_ST { + + bits<4> dst; + bits<64> imm; + bits<4> pseudo; + + let Inst{51-48} = dst; + let Inst{55-52} = pseudo; + let Inst{47-32} = 0; + let Inst{31-0} = imm{31-0}; + let SBFClass = SBF_LD; +} + +// STORE instructions +class STORE_V1 + : TYPE_LD_ST { + bits<4> src; + bits<20> addr; + + let Inst{51-48} = addr{19-16}; // base reg + let Inst{55-52} = src; + let Inst{47-32} = addr{15-0}; // offset + let SBFClass = SBF_STX; +} + +class STORE_V2 + : TYPE_LD_ST_V2 { + bits<4> src; + bits<20> addr; + + let Inst{51-48} = addr{19-16}; // base reg + let Inst{55-52} = src; + let Inst{47-32} = addr{15-0}; // offset + let SBFClass = SBF_ST_V2; +} + +multiclass STOREi64 { + def _V1 : STORE_V1, Requires<[SBFOldMemEncoding]>; + + let DecoderNamespace = "SBFv2" in { + def _V2 : STORE_V2, Requires<[SBFNewMemEncoding]>; + } +} + + +defm STW : STOREi64; +defm STH : STOREi64; +defm STB : STOREi64; +defm STD : STOREi64; + +def : Pat<(store GPR:$src, ADDRri:$addr), + (STD_V1 GPR:$src, ADDRri:$addr)>, Requires<[SBFOldMemEncoding]>; + +def : Pat<(store GPR:$src, ADDRri:$addr), + (STD_V2 GPR:$src, ADDRri:$addr)>, Requires<[SBFNewMemEncoding]>; + +let Predicates = [SBFNoALU32, SBFOldMemEncoding] in { + def : Pat<(truncstorei32 GPR:$src, ADDRri:$addr), + (STW_V1 GPR:$src, ADDRri:$addr)>; + def : Pat<(truncstorei16 GPR:$src, ADDRri:$addr), + (STH_V1 GPR:$src, ADDRri:$addr)>; + def : Pat<(truncstorei8 GPR:$src, ADDRri:$addr), + (STB_V1 GPR:$src, ADDRri:$addr)>; +} + +let Predicates = [SBFNoALU32, SBFNewMemEncoding] in { + def : Pat<(truncstorei32 GPR:$src, ADDRri:$addr), + (STW_V2 GPR:$src, ADDRri:$addr)>; + def : Pat<(truncstorei16 GPR:$src, ADDRri:$addr), + (STH_V2 GPR:$src, ADDRri:$addr)>; + def : Pat<(truncstorei8 GPR:$src, ADDRri:$addr), + (STB_V2 GPR:$src, ADDRri:$addr)>; +} + + +class STORE_imm_V1 + : TYPE_LD_ST { + bits<20> addr; + bits<32> imm; + let Inst{51-48} = addr{19-16}; // base reg + let Inst{47-32} = addr{15-0}; // offset + let Inst{31-0} = imm; + let SBFClass = SBF_ST; +} + +class STORE_imm_V2 + : TYPE_LD_ST_V2 { + bits<20> addr; + bits<32> imm; + let Inst{51-48} = addr{19-16}; // base reg + let Inst{47-32} = addr{15-0}; // offset + let Inst{31-0} = imm; + let SBFClass = SBF_ST_V2; +} + +multiclass STORE_imm { + def _V1 : STORE_imm_V1, Requires<[SBFOldMemEncoding]>; + + let DecoderNamespace = "SBFv2" in { + def _V2 : STORE_imm_V2, Requires<[SBFNewMemEncoding]>; + } +} + +// Opcode (SBF_ST | SBF_MEM | SBF_DW) implies sign extension for +// value stored to memory: +// - it is fine to generate such write when immediate is -1 +// - it is incorrect to generate such write when immediate is +// +0xffff_ffff. +// +// In the latter case two instructions would be generated instead of +// one BPF_ST: +// lddw rA, 0xffffffff +// stx [rb], rA +// +// For SBF_{B,H,W} the size of value stored matches size of the immediate. +defm STD_imm : STORE_imm; +defm STW_imm : STORE_imm; +defm STH_imm : STORE_imm; +defm STB_imm : STORE_imm; + +let Predicates = [SBFHasStoreImm, SBFOldMemEncoding] in { + def : Pat<(store (i64 i64immSExt32:$imm), ADDRri:$addr), + (STD_imm_V1 (i64 imm:$imm), ADDRri:$addr)>; + def : Pat<(truncstorei32 (i64 i64immZExt32:$imm), ADDRri:$addr), + (STW_imm_V1 (i64 imm:$imm), ADDRri:$addr)>; + def : Pat<(truncstorei16 (i64 i64immZExt32:$imm), ADDRri:$addr), + (STH_imm_V1 (i64 imm:$imm), ADDRri:$addr)>; + def : Pat<(truncstorei8 (i64 i64immZExt32:$imm), ADDRri:$addr), + (STB_imm_V1 (i64 imm:$imm), ADDRri:$addr)>; +} + +let Predicates = [SBFHasStoreImm, SBFNewMemEncoding] in { + def : Pat<(store (i64 i64immSExt32:$imm), ADDRri:$addr), + (STD_imm_V2 (i64 imm:$imm), ADDRri:$addr)>; + def : Pat<(truncstorei32 (i64 i64immZExt32:$imm), ADDRri:$addr), + (STW_imm_V2 (i64 imm:$imm), ADDRri:$addr)>; + def : Pat<(truncstorei16 (i64 i64immZExt32:$imm), ADDRri:$addr), + (STH_imm_V2 (i64 imm:$imm), ADDRri:$addr)>; + def : Pat<(truncstorei8 (i64 i64immZExt32:$imm), ADDRri:$addr), + (STB_imm_V2 (i64 imm:$imm), ADDRri:$addr)>; +} + +let Predicates = [SBFHasStoreImm, SBFNewMemEncoding] in { + def : Pat<(store (i32 imm:$src), ADDRri:$dst), + (STW_imm_V2 (imm_to_i64 $src), ADDRri:$dst)>; + def : Pat<(truncstorei16 (i32 imm:$src), ADDRri:$dst), + (STH_imm_V2 (imm_to_i64 imm:$src), ADDRri:$dst)>; + def : Pat<(truncstorei8 (i32 imm:$src), ADDRri:$dst), + (STB_imm_V2 (imm_to_i64 imm:$src), ADDRri:$dst)>; +} + + +let Predicates = [SBFHasALU32, SBFHasStoreImm, SBFOldMemEncoding] in { + def : Pat<(store (i32 imm:$src), ADDRri:$dst), + (STW_imm_V1 (imm_to_i64 $src), ADDRri:$dst)>; + def : Pat<(truncstorei16 (i32 imm:$src), ADDRri:$dst), + (STH_imm_V1 (imm_to_i64 imm:$src), ADDRri:$dst)>; + def : Pat<(truncstorei8 (i32 imm:$src), ADDRri:$dst), + (STB_imm_V1 (imm_to_i64 imm:$src), ADDRri:$dst)>; +} + +let Predicates = [SBFHasALU32, SBFHasStoreImm, SBFNewMemEncoding] in { + def : Pat<(store (i32 imm:$src), ADDRri:$dst), + (STW_imm_V2 (imm_to_i64 $src), ADDRri:$dst)>; + def : Pat<(truncstorei16 (i32 imm:$src), ADDRri:$dst), + (STH_imm_V2 (imm_to_i64 imm:$src), ADDRri:$dst)>; + def : Pat<(truncstorei8 (i32 imm:$src), ADDRri:$dst), + (STB_imm_V2 (imm_to_i64 imm:$src), ADDRri:$dst)>; +} + +// LOAD instructions +class LOAD_V1 + : TYPE_LD_ST { + bits<4> dst; + bits<20> addr; + + let Inst{51-48} = dst; + let Inst{55-52} = addr{19-16}; + let Inst{47-32} = addr{15-0}; + let SBFClass = SBF_LDX; +} + +class LOAD_V2 + : TYPE_LD_ST_V2 { + bits<4> dst; + bits<20> addr; + + let Inst{51-48} = dst; + let Inst{55-52} = addr{19-16}; + let Inst{47-32} = addr{15-0}; + let SBFClass = SBF_LD_V2; +} + +multiclass LOADi64 { + def _V1 : LOAD_V1, Requires<[SBFOldMemEncoding]>; + + let DecoderNamespace = "SBFv2" in { + def _V2 : LOAD_V2, Requires<[SBFNewMemEncoding]>; + } +} + +let isCodeGenOnly = 1 in { + multiclass CORE_LD { + def _V1 : TYPE_LD_ST; + + def _V2 : TYPE_LD_ST_V2; + } + + defm CORE_LD64 : CORE_LD; + defm CORE_LD32 : CORE_LD; + + def CORE_ST_V1 : TYPE_LD_ST; + + def CORE_ST_V2 : TYPE_LD_ST_V2; + + let Constraints = "$dst = $src" in { + def CORE_SHIFT : MATH_RR; + } +} + +defm LDW : LOADi64; +defm LDH : LOADi64; +defm LDB : LOADi64; +defm LDD : LOADi64; + +def : Pat<(load ADDRri:$addr), + (LDD_V1 ADDRri:$addr)>, Requires<[SBFOldMemEncoding]>; + +def : Pat<(load ADDRri:$addr), + (LDD_V2 ADDRri:$addr)>, Requires<[SBFNewMemEncoding]>; + +let Predicates = [SBFNoALU32, SBFOldMemEncoding] in { + def : Pat<(zextloadi32 ADDRri:$addr), + (LDW_V1 ADDRri:$addr)>; + def : Pat<(zextloadi16 ADDRri:$addr), + (LDH_V1 ADDRri:$addr)>; + def : Pat<(zextloadi8 ADDRri:$addr), + (LDB_V1 ADDRri:$addr)>; +} + +let Predicates = [SBFNoALU32, SBFNewMemEncoding] in { + def : Pat<(zextloadi32 ADDRri:$addr), + (LDW_V2 ADDRri:$addr)>; + def : Pat<(zextloadi16 ADDRri:$addr), + (LDH_V2 ADDRri:$addr)>; + def : Pat<(zextloadi8 ADDRri:$addr), + (LDB_V2 ADDRri:$addr)>; +} + +class BRANCH Pattern> + : TYPE_ALU_JMP { + bits<16> BrDst; + + let Inst{47-32} = BrDst; + let SBFClass = SBF_JMP; +} + +class CALL + : TYPE_ALU_JMP { + bits<32> BrDst; + + let Inst{31-0} = BrDst; + let SBFClass = SBF_JMP; +} + +class SYSCALL + : TYPE_ALU_JMP { + bits<32> imm; + + let Inst{31-0} = imm; + let SBFClass = SBF_JMP; +} + + +class CALLX + : TYPE_ALU_JMP { + bits<32> BrDst; + + let Inst{31-0} = BrDst; + let SBFClass = SBF_JMP; +} + +class CALLX_SRC_REG + : TYPE_ALU_JMP { + bits<4> BrDst; + + let Inst{55-52} = BrDst; + let SBFClass = SBF_JMP; +} + +// Jump always +let isBranch = 1, isTerminator = 1, hasDelaySlot=0, isBarrier = 1 in { + def JMP : BRANCH; +} + +// Jump and link +let isCall=1, hasDelaySlot=0, Uses = [R10], + // Potentially clobbered registers + Defs = [R0, R1, R2, R3, R4, R5] in { + def JAL : CALL<"call">; + def JALX : CALLX<"callx">, Requires<[SBFNoCallxSrc]>; + let DecoderNamespace = "SBFv2" in { + def JALX_v2 : CALLX_SRC_REG<"callx">, Requires<[SBFCallxSrc]>; + def SYSCALL_v3 : SYSCALL<"syscall">, Requires<[SBFHasStaticSyscalls]>; + } +} + +class NOP_I + : TYPE_ALU_JMP { + // mov r0, r0 == nop + let Inst{55-52} = 0; + let Inst{51-48} = 0; + let SBFClass = SBF_ALU64; +} + +let hasSideEffects = 0, isCodeGenOnly = 1 in + def NOP : NOP_I<"nop">; + +class EXIT + : TYPE_ALU_JMP { + let Inst{31-0} = 0; + let SBFClass = SBF_JMP; +} + +let isReturn = 1, isTerminator = 1, hasDelaySlot=0, isBarrier = 1, + isNotDuplicable = 1, Predicates = [SBFNoStaticSyscalls] in { + def EXIT : EXIT<"exit">; +} + +class RETURN + : TYPE_ALU_JMP { + let Inst{31-0} = 0; + let SBFClass = SBF_JMP; +} + +let isReturn = 1, isTerminator = 1, hasDelaySlot=0, isBarrier = 1, + isNotDuplicable = 1, Predicates = [SBFHasStaticSyscalls] in { + def RETURN_v3 : RETURN<"return">; +} + +// ADJCALLSTACKDOWN/UP pseudo insns +let Defs = [R10], Uses = [R10], isCodeGenOnly = 1 in { +def ADJCALLSTACKDOWN : Pseudo<(outs), (ins i64imm:$amt1, i64imm:$amt2), + "#ADJCALLSTACKDOWN $amt1 $amt2", + [(SBFcallseq_start timm:$amt1, timm:$amt2)]>; +def ADJCALLSTACKUP : Pseudo<(outs), (ins i64imm:$amt1, i64imm:$amt2), + "#ADJCALLSTACKUP $amt1 $amt2", + [(SBFcallseq_end timm:$amt1, timm:$amt2)]>; +} + +let usesCustomInserter = 1, isCodeGenOnly = 1 in { + def Select : Pseudo<(outs GPR:$dst), + (ins GPR:$lhs, GPR:$rhs, i64imm:$imm, GPR:$src, GPR:$src2), + "# Select PSEUDO $dst = $lhs $imm $rhs ? $src : $src2", + [(set i64:$dst, + (SBFselectcc i64:$lhs, i64:$rhs, (i64 imm:$imm), i64:$src, i64:$src2))]>; + def Select_Ri : Pseudo<(outs GPR:$dst), + (ins GPR:$lhs, i64imm:$rhs, i64imm:$imm, GPR:$src, GPR:$src2), + "# Select PSEUDO $dst = $lhs $imm $rhs ? $src : $src2", + [(set i64:$dst, + (SBFselectcc i64:$lhs, (i64immSExt32:$rhs), (i64 imm:$imm), i64:$src, i64:$src2))]>; + def Select_64_32 : Pseudo<(outs GPR32:$dst), + (ins GPR:$lhs, GPR:$rhs, i64imm:$imm, GPR32:$src, GPR32:$src2), + "# Select PSEUDO $dst = $lhs $imm $rhs ? $src : $src2", + [(set i32:$dst, + (SBFselectcc i64:$lhs, i64:$rhs, (i64 imm:$imm), i32:$src, i32:$src2))]>; + def Select_Ri_64_32 : Pseudo<(outs GPR32:$dst), + (ins GPR:$lhs, i64imm:$rhs, i64imm:$imm, GPR32:$src, GPR32:$src2), + "# Select PSEUDO $dst = $lhs $imm $rhs ? $src : $src2", + [(set i32:$dst, + (SBFselectcc i64:$lhs, (i64immSExt32:$rhs), (i64 imm:$imm), i32:$src, i32:$src2))]>; + def Select_32 : Pseudo<(outs GPR32:$dst), + (ins GPR32:$lhs, GPR32:$rhs, i32imm:$imm, GPR32:$src, GPR32:$src2), + "# Select PSEUDO $dst = $lhs $imm $rhs ? $src : $src2", + [(set i32:$dst, + (SBFselectcc i32:$lhs, i32:$rhs, (i32 imm:$imm), i32:$src, i32:$src2))]>; + def Select_Ri_32 : Pseudo<(outs GPR32:$dst), + (ins GPR32:$lhs, i32imm:$rhs, i32imm:$imm, GPR32:$src, GPR32:$src2), + "# Select PSEUDO $dst = $lhs $imm $rhs ? $src : $src2", + [(set i32:$dst, + (SBFselectcc i32:$lhs, (i32immSExt32:$rhs), (i32 imm:$imm), i32:$src, i32:$src2))]>; + def Select_32_64 : Pseudo<(outs GPR:$dst), + (ins GPR32:$lhs, GPR32:$rhs, i32imm:$imm, GPR:$src, GPR:$src2), + "# Select PSEUDO $dst = $lhs $imm $rhs ? $src : $src2", + [(set i64:$dst, + (SBFselectcc i32:$lhs, i32:$rhs, (i32 imm:$imm), i64:$src, i64:$src2))]>; + def Select_Ri_32_64 : Pseudo<(outs GPR:$dst), + (ins GPR32:$lhs, i32imm:$rhs, i32imm:$imm, GPR:$src, GPR:$src2), + "# Select PSEUDO $dst = $lhs $imm $rhs ? $src : $src2", + [(set i64:$dst, + (SBFselectcc i32:$lhs, (i32immSExt32:$rhs), (i32 imm:$imm), i64:$src, i64:$src2))]>; +} + +// 0xffffFFFF doesn't fit into simm32, optimize common case +def : Pat<(i64 (and (i64 GPR:$src), 0xffffFFFF)), + (SRL_ri (SLL_ri (i64 GPR:$src), 32), 32)>; + +// Calls +def : Pat<(SBFcall tglobaladdr:$dst), (JAL tglobaladdr:$dst)>; +def : Pat<(SBFcall texternalsym:$dst), (JAL texternalsym:$dst)>; +def : Pat<(SBFcall imm:$dst), (JAL imm:$dst)>, Requires<[SBFNoStaticSyscalls]>; +def : Pat<(SBFcall GPR:$dst), (JALX GPR:$dst)>, Requires<[SBFNoCallxSrc]>; +def : Pat<(SBFcall GPR:$dst), (JALX_v2 GPR:$dst)>, Requires<[SBFCallxSrc]>; +def : Pat<(SBFcall imm:$imm), (SYSCALL_v3 imm:$imm)>, Requires<[SBFHasStaticSyscalls]>; + +// Loads +let Predicates = [SBFNoALU32, SBFOldMemEncoding] in { + def : Pat<(i64 (extloadi8 ADDRri:$src)), (i64 (LDB_V1 ADDRri:$src))>; + def : Pat<(i64 (extloadi16 ADDRri:$src)), (i64 (LDH_V1 ADDRri:$src))>; + def : Pat<(i64 (extloadi32 ADDRri:$src)), (i64 (LDW_V1 ADDRri:$src))>; +} + +let Predicates = [SBFNoALU32, SBFNewMemEncoding] in { + def : Pat<(i64 (extloadi8 ADDRri:$src)), (i64 (LDB_V2 ADDRri:$src))>; + def : Pat<(i64 (extloadi16 ADDRri:$src)), (i64 (LDH_V2 ADDRri:$src))>; + def : Pat<(i64 (extloadi32 ADDRri:$src)), (i64 (LDW_V2 ADDRri:$src))>; +} + +// Atomic XADD for SBFNoALU32 +class XADD + : TYPE_LD_ST { + bits<4> dst; + bits<20> addr; + + let Inst{51-48} = addr{19-16}; // base reg + let Inst{55-52} = dst; + let Inst{47-32} = addr{15-0}; // offset + let Inst{7-4} = SBF_ADD.Value; + let SBFClass = SBF_STX; +} + +let Constraints = "$dst = $val" in { + let Predicates = [SBFNoALU32] in { + def XADDW : XADD; + } +} + +// Atomic add, and, or, xor +class ATOMIC_NOFETCH + : TYPE_LD_ST { + bits<4> dst; + bits<20> addr; + + let Inst{51-48} = addr{19-16}; // base reg + let Inst{55-52} = dst; + let Inst{47-32} = addr{15-0}; // offset + let Inst{7-4} = Opc.Value; + let SBFClass = SBF_STX; +} + +class ATOMIC32_NOFETCH + : TYPE_LD_ST { + bits<4> dst; + bits<20> addr; + + let Inst{51-48} = addr{19-16}; // base reg + let Inst{55-52} = dst; + let Inst{47-32} = addr{15-0}; // offset + let Inst{7-4} = Opc.Value; + let SBFClass = SBF_STX; +} + +let Constraints = "$dst = $val" in { + let Predicates = [SBFHasALU32], DecoderNamespace = "SBFALU32" in { + def XADDW32 : ATOMIC32_NOFETCH; + def XANDW32 : ATOMIC32_NOFETCH; + def XORW32 : ATOMIC32_NOFETCH; + def XXORW32 : ATOMIC32_NOFETCH; + } + + def XADDD : ATOMIC_NOFETCH; + def XANDD : ATOMIC_NOFETCH; + def XORD : ATOMIC_NOFETCH; + def XXORD : ATOMIC_NOFETCH; +} + +// Atomic Fetch-and- operations +class XFALU64 + : TYPE_LD_ST { + bits<4> dst; + bits<20> addr; + + let Inst{51-48} = addr{19-16}; // base reg + let Inst{55-52} = dst; + let Inst{47-32} = addr{15-0}; // offset + let Inst{7-4} = Opc.Value; + let Inst{3-0} = SBF_FETCH.Value; + let SBFClass = SBF_STX; +} + +class XFALU32 + : TYPE_LD_ST { + bits<4> dst; + bits<20> addr; + + let Inst{51-48} = addr{19-16}; // base reg + let Inst{55-52} = dst; + let Inst{47-32} = addr{15-0}; // offset + let Inst{7-4} = Opc.Value; + let Inst{3-0} = SBF_FETCH.Value; + let SBFClass = SBF_STX; +} + +let Constraints = "$dst = $val" in { + let Predicates = [SBFHasALU32], DecoderNamespace = "SBFALU32" in { + def XFADDW32 : XFALU32; + def XFANDW32 : XFALU32; + def XFORW32 : XFALU32; + def XFXORW32 : XFALU32; + } + + def XFADDD : XFALU64; + def XFANDD : XFALU64; + def XFORD : XFALU64; + def XFXORD : XFALU64; +} + +let usesCustomInserter = 1, isCodeGenOnly = 1 in { + def ATOMIC_FENCE : Pseudo< + (outs), + (ins), + "#atomic_fence", + [(atomic_fence timm, timm)]>; +} + +// Atomic Exchange +class XCHG + : TYPE_LD_ST { + bits<4> dst; + bits<20> addr; + + let Inst{51-48} = addr{19-16}; // base reg + let Inst{55-52} = dst; + let Inst{47-32} = addr{15-0}; // offset + let Inst{7-4} = SBF_XCHG.Value; + let Inst{3-0} = SBF_FETCH.Value; + let SBFClass = SBF_STX; +} + +class XCHG32 + : TYPE_LD_ST { + bits<4> dst; + bits<20> addr; + + let Inst{51-48} = addr{19-16}; // base reg + let Inst{55-52} = dst; + let Inst{47-32} = addr{15-0}; // offset + let Inst{7-4} = SBF_XCHG.Value; + let Inst{3-0} = SBF_FETCH.Value; + let SBFClass = SBF_STX; +} + +let Constraints = "$dst = $val" in { + let Predicates = [SBFHasALU32], DecoderNamespace = "SBFALU32" in { + def XCHGW32 : XCHG32; + } + + def XCHGD : XCHG; +} + +// Compare-And-Exchange +class CMPXCHG + : TYPE_LD_ST { + bits<4> new; + bits<20> addr; + + let Inst{51-48} = addr{19-16}; // base reg + let Inst{55-52} = new; + let Inst{47-32} = addr{15-0}; // offset + let Inst{7-4} = SBF_CMPXCHG.Value; + let Inst{3-0} = SBF_FETCH.Value; + let SBFClass = SBF_STX; +} + +class CMPXCHG32 + : TYPE_LD_ST { + bits<4> new; + bits<20> addr; + + let Inst{51-48} = addr{19-16}; // base reg + let Inst{55-52} = new; + let Inst{47-32} = addr{15-0}; // offset + let Inst{7-4} = SBF_CMPXCHG.Value; + let Inst{3-0} = SBF_FETCH.Value; + let SBFClass = SBF_STX; +} + +let Predicates = [SBFHasALU32], Defs = [W0], Uses = [W0], + DecoderNamespace = "SBFALU32" in { + def CMPXCHGW32 : CMPXCHG32; +} + +let Defs = [R0], Uses = [R0] in { + def CMPXCHGD : CMPXCHG; +} + +// bswap16, bswap32, bswap64 +class BSWAP SizeOp, string OpcodeStr, SBFSrcType SrcType, list Pattern> + : TYPE_ALU_JMP { + bits<4> dst; + + let Inst{51-48} = dst; + let Inst{31-0} = SizeOp; + let SBFClass = SBF_ALU; +} + + +let Constraints = "$dst = $src" in { + def BE16 : BSWAP<16, "be16", SBF_TO_BE, [(set GPR:$dst, (srl (bswap GPR:$src), (i64 48)))]>; + def BE32 : BSWAP<32, "be32", SBF_TO_BE, [(set GPR:$dst, (srl (bswap GPR:$src), (i64 32)))]>; + def BE64 : BSWAP<64, "be64", SBF_TO_BE, [(set GPR:$dst, (bswap GPR:$src))]>; +} + +let DecoderNamespace = "SBFv2" in { + def MOV_32_64 : MATH_RR; +} + +let isCodeGenOnly = 1 in { + def MOV_32_64_addr : MATH_RI, Requires<[SBFNoLddw]>; + + def MOV_32_64_no_sext : MATH_RR; +} + +let DecoderNamespace = "SBFv2", Predicates = [SBFNoLddw] in { + def MOV_32_64_imm : MATH_RI; +} + +// In SBFv2, a CopyToReg of a 64-bit value is split in two instructions: +// mov32 r1, 0x55667788 +// hor r1, 0x11223344 +// These instructions copy the value 0x1122334455667788 to a register. +def : Pat<(i64 imm:$imm), + (HOR (MOV_32_64_imm (i32 (Lower32 $imm))), + (i32 (Upper32 $imm)))>, Requires<[SBFNoLddw]>; + +// load 64-bit global address into register. +def : Pat<(SBFWrapper tglobaladdr:$in), (LD_imm64 tglobaladdr:$in)>, + Requires<[SBFHasLddw]>; +def : Pat<(SBFWrapper tglobaladdr:$in), + (HOR_addr (MOV_32_64_addr tglobaladdr:$in), + tglobaladdr:$in)>, Requires<[SBFNoLddw]>; + +def : Pat<(SBFWrapper tconstpool:$in), (LD_imm64 tconstpool:$in)>, + Requires<[SBFHasLddw]>; +def : Pat<(SBFWrapper tconstpool:$in), + (HOR_addr (MOV_32_64_addr tconstpool:$in), + tconstpool:$in)>, Requires<[SBFNoLddw]>; + +// SBFv2 sign extension +def : Pat<(i64 (sext GPR32:$src)), + (MOV_32_64 GPR32:$src)>, Requires<[SBFExplicitSignExt]>; + +// SBFv1 sign extension +def : Pat<(i64 (sext GPR32:$src)), + (SRA_ri (SLL_ri (MOV_32_64 GPR32:$src), 32), 32)>, + Requires<[SBFNoExplicitSignExt]>; + +// SBFv2 zero extension +def : Pat<(i64 (zext GPR32:$src)), (INSERT_SUBREG (i64 (IMPLICIT_DEF)), + GPR32:$src, sub_32)>, Requires<[SBFExplicitSignExt]>; + +// SBFv1 zero extension +def : Pat<(i64 (zext GPR32:$src)), (MOV_32_64 GPR32:$src)>, + Requires<[SBFNoExplicitSignExt]>; + +// SBFv2 truncation +def : Pat<(i32 (trunc GPR:$src)), + (AND_ri_32 (i32 (EXTRACT_SUBREG GPR:$src, sub_32)), + (i32 0xffffffff))>, Requires<[SBFExplicitSignExt]>; + +// SBFv1 truncation +def : Pat<(i32 (trunc GPR:$src)), + (i32 (EXTRACT_SUBREG GPR:$src, sub_32))>, Requires<[SBFNoExplicitSignExt]>; + +// SBFv2 anyext +def : Pat<(i64 (anyext GPR32:$src)), + (INSERT_SUBREG (i64 (IMPLICIT_DEF)), GPR32:$src, sub_32)>, Requires<[SBFExplicitSignExt]>; + +// SBFv1 anyext +def : Pat<(i64 (anyext GPR32:$src)), + (INSERT_SUBREG (i64 (IMPLICIT_DEF)), GPR32:$src, sub_32)>, Requires<[SBFNoExplicitSignExt]>; + +class STORE32_V1 + : TYPE_LD_ST { + bits<4> src; + bits<20> addr; + + let Inst{51-48} = addr{19-16}; // base reg + let Inst{55-52} = src; + let Inst{47-32} = addr{15-0}; // offset + let SBFClass = SBF_STX; +} + +class STORE32_V2 + : TYPE_LD_ST_V2 { + bits<4> src; + bits<20> addr; + + let Inst{51-48} = addr{19-16}; // base reg + let Inst{55-52} = src; + let Inst{47-32} = addr{15-0}; // offset + let SBFClass = SBF_ST_V2; +} + +multiclass STOREi32 { + let DecoderNamespace = "SBFALU32" in { + def _V1 : STORE32_V1, Requires<[SBFOldMemEncoding]>; + } + + let DecoderNamespace = "SBFALU32MEMv2" in { + def _V2 : STORE32_V2, Requires<[SBFNewMemEncoding]>; + } +} + +defm STW32 : STOREi32; +defm STH32 : STOREi32; +defm STB32 : STOREi32; + +let Predicates = [SBFHasALU32, SBFOldMemEncoding] in { + def : Pat<(store GPR32:$src, ADDRri:$addr), + (STW32_V1 GPR32:$src, ADDRri:$addr)>; + def : Pat<(truncstorei16 GPR32:$src, ADDRri:$addr), + (STH32_V1 GPR32:$src, ADDRri:$addr)>; + def : Pat<(truncstorei8 GPR32:$src, ADDRri:$addr), + (STB32_V1 GPR32:$src, ADDRri:$addr)>; +} + +let Predicates = [SBFHasALU32, SBFNewMemEncoding] in { + def : Pat<(store GPR32:$src, ADDRri:$addr), + (STW32_V2 GPR32:$src, ADDRri:$addr)>; + def : Pat<(truncstorei16 GPR32:$src, ADDRri:$addr), + (STH32_V2 GPR32:$src, ADDRri:$addr)>; + def : Pat<(truncstorei8 GPR32:$src, ADDRri:$addr), + (STB32_V2 GPR32:$src, ADDRri:$addr)>; +} + +class LOAD32_V1 + : TYPE_LD_ST { + bits<4> dst; + bits<20> addr; + + let Inst{51-48} = dst; + let Inst{55-52} = addr{19-16}; + let Inst{47-32} = addr{15-0}; + let SBFClass = SBF_LDX; +} + +class LOAD32_V2 + : TYPE_LD_ST_V2 { + bits<4> dst; + bits<20> addr; + + let Inst{51-48} = dst; + let Inst{55-52} = addr{19-16}; + let Inst{47-32} = addr{15-0}; + let SBFClass = SBF_LD_V2; +} + + +multiclass LOADi32 { + let DecoderNamespace = "SBFALU32" in { + def _V1 : LOAD32_V1, Requires<[SBFOldMemEncoding]>; + } + let DecoderNamespace = "SBFALU32MEMv2" in { + def _V2 : LOAD32_V2, Requires<[SBFNewMemEncoding]>; + } +} + + +defm LDW32 : LOADi32; +defm LDH32 : LOADi32; +defm LDB32 : LOADi32; + +let Predicates = [SBFHasALU32, SBFOldMemEncoding] in { + def : Pat<(load ADDRri:$addr), + (LDW32_V1 ADDRri:$addr)>; + def : Pat<(zextloadi16 ADDRri:$addr), + (LDH32_V1 ADDRri:$addr)>; + def : Pat<(zextloadi8 ADDRri:$addr), + (LDB32_V1 ADDRri:$addr)>; +} + +let Predicates = [SBFHasALU32, SBFNewMemEncoding] in { + def : Pat<(load ADDRri:$addr), + (LDW32_V2 ADDRri:$addr)>; + def : Pat<(zextloadi16 ADDRri:$addr), + (LDH32_V2 ADDRri:$addr)>; + def : Pat<(zextloadi8 ADDRri:$addr), + (LDB32_V2 ADDRri:$addr)>; +} + +let Predicates = [SBFHasALU32, SBFOldMemEncoding] in { + def : Pat<(truncstorei8 GPR:$src, ADDRri:$dst), + (STB32_V1 (EXTRACT_SUBREG GPR:$src, sub_32), ADDRri:$dst)>; + def : Pat<(truncstorei16 GPR:$src, ADDRri:$dst), + (STH32_V1 (EXTRACT_SUBREG GPR:$src, sub_32), ADDRri:$dst)>; + def : Pat<(truncstorei32 GPR:$src, ADDRri:$dst), + (STW32_V1 (EXTRACT_SUBREG GPR:$src, sub_32), ADDRri:$dst)>; + def : Pat<(i32 (extloadi8 ADDRri:$src)), (i32 (LDB32_V1 ADDRri:$src))>; + def : Pat<(i32 (extloadi16 ADDRri:$src)), (i32 (LDH32_V1 ADDRri:$src))>; + def : Pat<(i64 (zextloadi8 ADDRri:$src)), + (SUBREG_TO_REG (i64 0), (LDB32_V1 ADDRri:$src), sub_32)>; + def : Pat<(i64 (zextloadi16 ADDRri:$src)), + (SUBREG_TO_REG (i64 0), (LDH32_V1 ADDRri:$src), sub_32)>; + def : Pat<(i64 (zextloadi32 ADDRri:$src)), + (SUBREG_TO_REG (i64 0), (LDW32_V1 ADDRri:$src), sub_32)>; + def : Pat<(i64 (extloadi8 ADDRri:$src)), + (SUBREG_TO_REG (i64 0), (LDB32_V1 ADDRri:$src), sub_32)>; + def : Pat<(i64 (extloadi16 ADDRri:$src)), + (SUBREG_TO_REG (i64 0), (LDH32_V1 ADDRri:$src), sub_32)>; + def : Pat<(i64 (extloadi32 ADDRri:$src)), + (SUBREG_TO_REG (i64 0), (LDW32_V1 ADDRri:$src), sub_32)>; +} + +let Predicates = [SBFHasALU32, SBFNewMemEncoding] in { + def : Pat<(truncstorei8 GPR:$src, ADDRri:$dst), + (STB32_V2 (EXTRACT_SUBREG GPR:$src, sub_32), ADDRri:$dst)>; + def : Pat<(truncstorei16 GPR:$src, ADDRri:$dst), + (STH32_V2 (EXTRACT_SUBREG GPR:$src, sub_32), ADDRri:$dst)>; + def : Pat<(truncstorei32 GPR:$src, ADDRri:$dst), + (STW32_V2 (EXTRACT_SUBREG GPR:$src, sub_32), ADDRri:$dst)>; + def : Pat<(i32 (extloadi8 ADDRri:$src)), (i32 (LDB32_V2 ADDRri:$src))>; + def : Pat<(i32 (extloadi16 ADDRri:$src)), (i32 (LDH32_V2 ADDRri:$src))>; + def : Pat<(i64 (zextloadi8 ADDRri:$src)), + (SUBREG_TO_REG (i64 0), (LDB32_V2 ADDRri:$src), sub_32)>; + def : Pat<(i64 (zextloadi16 ADDRri:$src)), + (SUBREG_TO_REG (i64 0), (LDH32_V2 ADDRri:$src), sub_32)>; + def : Pat<(i64 (zextloadi32 ADDRri:$src)), + (SUBREG_TO_REG (i64 0), (LDW32_V2 ADDRri:$src), sub_32)>; + def : Pat<(i64 (extloadi8 ADDRri:$src)), + (SUBREG_TO_REG (i64 0), (LDB32_V2 ADDRri:$src), sub_32)>; + def : Pat<(i64 (extloadi16 ADDRri:$src)), + (SUBREG_TO_REG (i64 0), (LDH32_V2 ADDRri:$src), sub_32)>; + def : Pat<(i64 (extloadi32 ADDRri:$src)), + (SUBREG_TO_REG (i64 0), (LDW32_V2 ADDRri:$src), sub_32)>; +} diff --git a/llvm/lib/Target/SBF/SBFMCInstLower.cpp b/llvm/lib/Target/SBF/SBFMCInstLower.cpp new file mode 100644 index 0000000000000..328ef0ca58e9e --- /dev/null +++ b/llvm/lib/Target/SBF/SBFMCInstLower.cpp @@ -0,0 +1,84 @@ +//=-- SBFMCInstLower.cpp - Convert SBF MachineInstr to an MCInst ------------=// +// +// 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 +// +//===----------------------------------------------------------------------===// +// +// This file contains code to lower SBF MachineInstrs to their corresponding +// MCInst records. +// +//===----------------------------------------------------------------------===// + +#include "SBFMCInstLower.h" +#include "llvm/CodeGen/AsmPrinter.h" +#include "llvm/CodeGen/MachineBasicBlock.h" +#include "llvm/CodeGen/MachineInstr.h" +#include "llvm/MC/MCAsmInfo.h" +#include "llvm/MC/MCContext.h" +#include "llvm/MC/MCExpr.h" +#include "llvm/MC/MCInst.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/raw_ostream.h" +using namespace llvm; + +MCSymbol * +SBFMCInstLower::GetGlobalAddressSymbol(const MachineOperand &MO) const { + return Printer.getSymbol(MO.getGlobal()); +} + +MCSymbol * +SBFMCInstLower::GetExternalSymbolSymbol(const MachineOperand &MO) const { + return Printer.GetExternalSymbolSymbol(MO.getSymbolName()); +} + +MCOperand SBFMCInstLower::LowerSymbolOperand(const MachineOperand &MO, + MCSymbol *Sym) const { + + const MCExpr *Expr = MCSymbolRefExpr::create(Sym, Ctx); + + if (!MO.isJTI() && MO.getOffset()) + llvm_unreachable("unknown symbol op"); + + return MCOperand::createExpr(Expr); +} + +void SBFMCInstLower::Lower(const MachineInstr *MI, MCInst &OutMI) const { + OutMI.setOpcode(MI->getOpcode()); + + for (const MachineOperand &MO : MI->operands()) { + MCOperand MCOp; + switch (MO.getType()) { + default: + MI->print(errs()); + llvm_unreachable("unknown operand type"); + case MachineOperand::MO_Register: + // Ignore all implicit register operands. + if (MO.isImplicit()) + continue; + MCOp = MCOperand::createReg(MO.getReg()); + break; + case MachineOperand::MO_Immediate: + MCOp = MCOperand::createImm(MO.getImm()); + break; + case MachineOperand::MO_MachineBasicBlock: + MCOp = MCOperand::createExpr( + MCSymbolRefExpr::create(MO.getMBB()->getSymbol(), Ctx)); + break; + case MachineOperand::MO_RegisterMask: + continue; + case MachineOperand::MO_ExternalSymbol: + MCOp = LowerSymbolOperand(MO, GetExternalSymbolSymbol(MO)); + break; + case MachineOperand::MO_GlobalAddress: + MCOp = LowerSymbolOperand(MO, GetGlobalAddressSymbol(MO)); + break; + case MachineOperand::MO_ConstantPoolIndex: + MCOp = LowerSymbolOperand(MO, Printer.GetCPISymbol(MO.getIndex())); + break; + } + + OutMI.addOperand(MCOp); + } +} diff --git a/llvm/lib/Target/SBF/SBFMCInstLower.h b/llvm/lib/Target/SBF/SBFMCInstLower.h new file mode 100644 index 0000000000000..1d03df89ee4db --- /dev/null +++ b/llvm/lib/Target/SBF/SBFMCInstLower.h @@ -0,0 +1,41 @@ +//===-- SBFMCInstLower.h - Lower MachineInstr to MCInst ---------*- 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 +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIB_TARGET_SBF_SBFMCINSTLOWER_H +#define LLVM_LIB_TARGET_SBF_SBFMCINSTLOWER_H + +#include "llvm/Support/Compiler.h" + +namespace llvm { +class AsmPrinter; +class MCContext; +class MCInst; +class MCOperand; +class MCSymbol; +class MachineInstr; +class MachineOperand; + +// SBFMCInstLower - This class is used to lower an MachineInstr into an MCInst. +class LLVM_LIBRARY_VISIBILITY SBFMCInstLower { + MCContext &Ctx; + + AsmPrinter &Printer; + +public: + SBFMCInstLower(MCContext &ctx, AsmPrinter &printer) + : Ctx(ctx), Printer(printer) {} + void Lower(const MachineInstr *MI, MCInst &OutMI) const; + + MCOperand LowerSymbolOperand(const MachineOperand &MO, MCSymbol *Sym) const; + + MCSymbol *GetGlobalAddressSymbol(const MachineOperand &MO) const; + MCSymbol *GetExternalSymbolSymbol(const MachineOperand &MO) const; +}; +} + +#endif diff --git a/llvm/lib/Target/SBF/SBFMIChecking.cpp b/llvm/lib/Target/SBF/SBFMIChecking.cpp new file mode 100644 index 0000000000000..576aca11db71b --- /dev/null +++ b/llvm/lib/Target/SBF/SBFMIChecking.cpp @@ -0,0 +1,248 @@ +//===-------------- SBFMIChecking.cpp - MI Checking Legality -------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// +// +// This pass performs checking to signal errors for certain illegal usages at +// MachineInstruction layer. Specially, the result of XADD{32,64} insn should +// not be used. The pass is done at the PreEmit pass right before the +// machine code is emitted at which point the register liveness information +// is still available. +// +//===----------------------------------------------------------------------===// + +#include "SBF.h" +#include "SBFTargetMachine.h" +#include "llvm/Support/Debug.h" + +using namespace llvm; + +#define DEBUG_TYPE "sbf-mi-checking" + +namespace { + +struct SBFMIPreEmitChecking : public MachineFunctionPass { + + static char ID; + MachineFunction *MF; + const TargetRegisterInfo *TRI; + + SBFMIPreEmitChecking() : MachineFunctionPass(ID) { + initializeSBFMIPreEmitCheckingPass(*PassRegistry::getPassRegistry()); + } + +private: + // Initialize class variables. + void initialize(MachineFunction &MFParm); + + bool processAtomicInsts(); + +public: + + // Main entry point for this pass. + bool runOnMachineFunction(MachineFunction &MF) override { + if (!skipFunction(MF.getFunction())) { + initialize(MF); + return processAtomicInsts(); + } + return false; + } +}; + +// Initialize class variables. +void SBFMIPreEmitChecking::initialize(MachineFunction &MFParm) { + MF = &MFParm; + TRI = MF->getSubtarget().getRegisterInfo(); + LLVM_DEBUG(dbgs() << "*** SBF PreEmit checking pass ***\n\n"); +} + +// Make sure all Defs of XADD are dead, meaning any result of XADD insn is not +// used. +// +// NOTE: SBF backend hasn't enabled sub-register liveness track, so when the +// source and destination operands of XADD are GPR32, there is no sub-register +// dead info. If we rely on the generic MachineInstr::allDefsAreDead, then we +// will raise false alarm on GPR32 Def. +// +// To support GPR32 Def, ideally we could just enable sub-registr liveness track +// on SBF backend, then allDefsAreDead could work on GPR32 Def. This requires +// implementing TargetSubtargetInfo::enableSubRegLiveness on SBF. +// +// However, sub-register liveness tracking module inside LLVM is actually +// designed for the situation where one register could be split into more than +// one sub-registers for which case each sub-register could have their own +// liveness and kill one of them doesn't kill others. So, tracking liveness for +// each make sense. +// +// For SBF, each 64-bit register could only have one 32-bit sub-register. This +// is exactly the case which LLVM think brings no benefits for doing +// sub-register tracking, because the live range of sub-register must always +// equal to its parent register, therefore liveness tracking is disabled even +// the back-end has implemented enableSubRegLiveness. The detailed information +// is at r232695: +// +// Author: Matthias Braun +// Date: Thu Mar 19 00:21:58 2015 +0000 +// Do not track subregister liveness when it brings no benefits +// +// Hence, for SBF, we enhance MachineInstr::allDefsAreDead. Given the solo +// sub-register always has the same liveness as its parent register, LLVM is +// already attaching a implicit 64-bit register Def whenever the there is +// a sub-register Def. The liveness of the implicit 64-bit Def is available. +// For example, for "lock *(u32 *)(r0 + 4) += w9", the MachineOperand info could +// be: +// +// $w9 = XADDW32 killed $r0, 4, $w9(tied-def 0), +// implicit killed $r9, implicit-def dead $r9 +// +// Even though w9 is not marked as Dead, the parent register r9 is marked as +// Dead correctly, and it is safe to use such information or our purpose. +static bool hasLiveDefs(const MachineInstr &MI, const TargetRegisterInfo *TRI) { + const MCRegisterClass *GPR64RegClass = + &SBFMCRegisterClasses[SBF::GPRRegClassID]; + std::vector GPR32LiveDefs; + std::vector GPR64DeadDefs; + + for (const MachineOperand &MO : MI.operands()) { + bool RegIsGPR64; + + if (!MO.isReg() || MO.isUse()) + continue; + + RegIsGPR64 = GPR64RegClass->contains(MO.getReg()); + if (!MO.isDead()) { + // It is a GPR64 live Def, we are sure it is live. */ + if (RegIsGPR64) + return true; + // It is a GPR32 live Def, we are unsure whether it is really dead due to + // no sub-register liveness tracking. Push it to vector for deferred + // check. + GPR32LiveDefs.push_back(MO.getReg()); + continue; + } + + // Record any GPR64 dead Def as some unmarked GPR32 could be alias of its + // low 32-bit. + if (RegIsGPR64) + GPR64DeadDefs.push_back(MO.getReg()); + } + + // No GPR32 live Def, safe to return false. + if (GPR32LiveDefs.empty()) + return false; + + // No GPR64 dead Def, so all those GPR32 live Def can't have alias, therefore + // must be truely live, safe to return true. + if (GPR64DeadDefs.empty()) + return true; + + // Otherwise, return true if any aliased SuperReg of GPR32 is not dead. + for (auto I : GPR32LiveDefs) + for (MCPhysReg SR : TRI->superregs(I)) + if (!llvm::is_contained(GPR64DeadDefs, SR)) + return true; + + return false; +} + +bool SBFMIPreEmitChecking::processAtomicInsts() { + for (MachineBasicBlock &MBB : *MF) { + for (MachineInstr &MI : MBB) { + if (MI.getOpcode() != SBF::XADDW && + MI.getOpcode() != SBF::XADDD && + MI.getOpcode() != SBF::XADDW32) + continue; + + LLVM_DEBUG(MI.dump()); + if (hasLiveDefs(MI, TRI)) { + DebugLoc Empty; + const DebugLoc &DL = MI.getDebugLoc(); + if (DL != Empty) + report_fatal_error(Twine("line ") + std::to_string(DL.getLine()) + + ": Invalid usage of the XADD return value", false); + else + report_fatal_error("Invalid usage of the XADD return value", false); + } + } + } + + // Check return values of atomic_fetch_and_{add,and,or,xor}. + // If the return is not used, the atomic_fetch_and_ instruction + // is replaced with atomic_ instruction. + MachineInstr *ToErase = nullptr; + bool Changed = false; + const SBFInstrInfo *TII = MF->getSubtarget().getInstrInfo(); + for (MachineBasicBlock &MBB : *MF) { + for (MachineInstr &MI : MBB) { + if (ToErase) { + ToErase->eraseFromParent(); + ToErase = nullptr; + } + + if (MI.getOpcode() != SBF::XFADDW32 && MI.getOpcode() != SBF::XFADDD && + MI.getOpcode() != SBF::XFANDW32 && MI.getOpcode() != SBF::XFANDD && + MI.getOpcode() != SBF::XFXORW32 && MI.getOpcode() != SBF::XFXORD && + MI.getOpcode() != SBF::XFORW32 && MI.getOpcode() != SBF::XFORD) + continue; + + if (hasLiveDefs(MI, TRI)) + continue; + + LLVM_DEBUG(dbgs() << "Transforming "; MI.dump()); + unsigned newOpcode; + switch (MI.getOpcode()) { + case SBF::XFADDW32: + newOpcode = SBF::XADDW32; + break; + case SBF::XFADDD: + newOpcode = SBF::XADDD; + break; + case SBF::XFANDW32: + newOpcode = SBF::XANDW32; + break; + case SBF::XFANDD: + newOpcode = SBF::XANDD; + break; + case SBF::XFXORW32: + newOpcode = SBF::XXORW32; + break; + case SBF::XFXORD: + newOpcode = SBF::XXORD; + break; + case SBF::XFORW32: + newOpcode = SBF::XORW32; + break; + case SBF::XFORD: + newOpcode = SBF::XORD; + break; + default: + llvm_unreachable("Incorrect Atomic Instruction Opcode"); + } + + BuildMI(MBB, MI, MI.getDebugLoc(), TII->get(newOpcode)) + .add(MI.getOperand(0)) + .add(MI.getOperand(1)) + .add(MI.getOperand(2)) + .add(MI.getOperand(3)); + + ToErase = &MI; + Changed = true; + } + } + + return Changed; +} + +} // end default namespace + +INITIALIZE_PASS(SBFMIPreEmitChecking, "sbf-mi-pemit-checking", + "SBF PreEmit Checking", false, false) + +char SBFMIPreEmitChecking::ID = 0; +FunctionPass* llvm::createSBFMIPreEmitCheckingPass() +{ + return new SBFMIPreEmitChecking(); +} diff --git a/llvm/lib/Target/SBF/SBFMIPeephole.cpp b/llvm/lib/Target/SBF/SBFMIPeephole.cpp new file mode 100644 index 0000000000000..d09df5513b254 --- /dev/null +++ b/llvm/lib/Target/SBF/SBFMIPeephole.cpp @@ -0,0 +1,449 @@ +//===-------------- SBFMIPeephole.cpp - MI Peephole Cleanups -------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// +// +// This pass performs peephole optimizations to cleanup ugly code sequences at +// MachineInstruction layer. +// +// Currently, there are two optimizations implemented: +// - One pre-RA MachineSSA pass to eliminate type promotion sequences, those +// zero extend 32-bit subregisters to 64-bit registers, if the compiler +// could prove the subregisters is defined by 32-bit operations in which +// case the upper half of the underlying 64-bit registers were zeroed +// implicitly. +// +// - One post-RA PreEmit pass to do final cleanup on some redundant +// instructions generated due to bad RA on subregister. +//===----------------------------------------------------------------------===// + +#include "SBF.h" +#include "SBFInstrInfo.h" +#include "SBFTargetMachine.h" +#include "llvm/ADT/Statistic.h" +#include "llvm/CodeGen/MachineInstrBuilder.h" +#include "llvm/CodeGen/MachineRegisterInfo.h" +#include "llvm/Support/Debug.h" +#include + +using namespace llvm; + +#define DEBUG_TYPE "sbf-mi-zext-elim" + +namespace { + +struct SBFMIPeephole : public MachineFunctionPass { + + static char ID; + const SBFInstrInfo *TII; + MachineFunction *MF; + MachineRegisterInfo *MRI; + + SBFMIPeephole() : MachineFunctionPass(ID) { + initializeSBFMIPeepholePass(*PassRegistry::getPassRegistry()); + } + +private: + // Initialize class variables. + void initialize(MachineFunction &MFParm); + bool eliminateZExt(); + + std::set PhiInsns; + +public: + + // Main entry point for this pass. + bool runOnMachineFunction(MachineFunction &MF) override { + if (skipFunction(MF.getFunction())) + return false; + + initialize(MF); + + return eliminateZExt(); + } +}; + +// Initialize class variables. +void SBFMIPeephole::initialize(MachineFunction &MFParm) { + MF = &MFParm; + MRI = &MF->getRegInfo(); + TII = MF->getSubtarget().getInstrInfo(); + LLVM_DEBUG(dbgs() << "*** SBF MachineSSA ZEXT Elim peephole pass ***\n\n"); +} + +bool SBFMIPeephole::eliminateZExt() { + MachineInstr* ToErase = nullptr; + bool Eliminated = false; + + for (MachineBasicBlock &MBB : *MF) { + for (MachineInstr &MI : MBB) { + // If the previous instruction was marked for elimination, remove it now. + if (ToErase) { + ToErase->eraseFromParent(); + ToErase = nullptr; + } + + if (MI.getOpcode() != SBF::MOV_32_64_no_sext) + continue; + + // Eliminate MOV_32_64 if possible. + // MOV_32_64 rA, wB + LLVM_DEBUG(dbgs() << "Candidate MOV_32_64_no_sext instruction:"); + LLVM_DEBUG(MI.dump()); + + LLVM_DEBUG(dbgs() << "Removing the MOV_32_64_no_sext instruction\n"); + + Register dst = MI.getOperand(0).getReg(); + Register src = MI.getOperand(1).getReg(); + + // Build a SUBREG_TO_REG instruction. + BuildMI(MBB, MI, MI.getDebugLoc(), TII->get(SBF::SUBREG_TO_REG), dst) + .addImm(0).addReg(src).addImm(SBF::sub_32); + + ToErase = &MI; + Eliminated = true; + } + } + + return Eliminated; +} + +} // end default namespace + +INITIALIZE_PASS(SBFMIPeephole, DEBUG_TYPE, + "SBF MachineSSA Peephole Optimization For ZEXT Eliminate", + false, false) + +char SBFMIPeephole::ID = 0; +FunctionPass* llvm::createSBFMIPeepholePass() { return new SBFMIPeephole(); } + +STATISTIC(RedundantMovElemNum, "Number of redundant moves eliminated"); + +namespace { + +struct SBFMIPreEmitPeephole : public MachineFunctionPass { + + static char ID; + MachineFunction *MF; + const TargetRegisterInfo *TRI; + const SBFInstrInfo *TII; + const SBFSubtarget *SubTarget; + const CodeGenOptLevel OptLevel; + const bool DisablePeephole; + + SBFMIPreEmitPeephole(CodeGenOptLevel OptLevel, bool DisablePeephole) + : MachineFunctionPass(ID), OptLevel(OptLevel), + DisablePeephole(DisablePeephole) { + initializeSBFMIPreEmitPeepholePass(*PassRegistry::getPassRegistry()); + } + +private: + // Initialize class variables. + void initialize(MachineFunction &MFParm); + + bool eliminateRedundantMov(); + bool addReturn(); + +public: + + // Main entry point for this pass. + bool runOnMachineFunction(MachineFunction &MF) override { + initialize(MF); + + bool PeepholeExecuted = false; + if (SubTarget->getHasStaticSyscalls()) + PeepholeExecuted |= addReturn(); + + // We shall not skip adding the return to SBPFv3 functions + if (skipFunction(MF.getFunction()) || OptLevel == CodeGenOptLevel::None || + DisablePeephole) + return PeepholeExecuted; + + PeepholeExecuted |= eliminateRedundantMov(); + + return PeepholeExecuted; + } +}; + +// Initialize class variables. +void SBFMIPreEmitPeephole::initialize(MachineFunction &MFParm) { + MF = &MFParm; + SubTarget = &MF->getSubtarget(); + TRI = SubTarget->getRegisterInfo(); + TII = SubTarget->getInstrInfo(); + LLVM_DEBUG(dbgs() << "*** SBF PreEmit peephole pass ***\n\n"); +} + +bool SBFMIPreEmitPeephole::addReturn() { + bool Added = false; + + // In SBFv3, every function must either end with either a JA or a RETURN + // instruction. When we call a function that will never return the control + // flow (e.g. when the callee aborts execution), the caller last instruction + // will be a CALL, failing validation. + // + // Although we can change ISelLowering and manually add the return for an + // LLVM-IR unreachable instruction, LLVM codegen uses the target machine's + // return instruction to determine whether a function needs an epilogue. + // This setting increases code size, even when we know the call won't + // trasnfer control back to the caller. + // + // In that case, we can analyze every function before emitting machine code + // and include a useless return instruction. + + // PreEmitPeephole happens after block placement, so the last block in + // the ELF layout is also the last one in MF. + MachineBasicBlock &MBB = MF->back(); + MachineInstr &MI = MBB.back(); + unsigned Opcode = MI.getOpcode(); + if (Opcode != SBF::RETURN_v3 && Opcode != SBF::JMP) { + BuildMI(&MBB, MI.getDebugLoc(), TII->get(SBF::RETURN_v3)); + Added = true; + } + + return Added; +} + +bool SBFMIPreEmitPeephole::eliminateRedundantMov() { + MachineInstr* ToErase = nullptr; + bool Eliminated = false; + + for (MachineBasicBlock &MBB : *MF) { + for (MachineInstr &MI : MBB) { + // If the previous instruction was marked for elimination, remove it now. + if (ToErase) { + LLVM_DEBUG(dbgs() << " Redundant Mov Eliminated:"); + LLVM_DEBUG(ToErase->dump()); + ToErase->eraseFromParent(); + ToErase = nullptr; + } + + // Eliminate identical move: + // + // MOV rA, rA + // MOV wA, wA + unsigned Opcode = MI.getOpcode(); + if (Opcode == SBF::MOV_rr || + Opcode == SBF::MOV_rr_32_no_sext_v2 || + Opcode == SBF::MOV_32_64_no_sext) { + Register dst = MI.getOperand(0).getReg(); + Register src = MI.getOperand(1).getReg(); + + if (dst != src) + continue; + + ToErase = &MI; + RedundantMovElemNum++; + Eliminated = true; + } + } + } + + return Eliminated; +} + +} // end default namespace + +INITIALIZE_PASS(SBFMIPreEmitPeephole, "sbf-mi-pemit-peephole", + "SBF PreEmit Peephole Optimization", false, false) + +char SBFMIPreEmitPeephole::ID = 0; +FunctionPass* llvm::createSBFMIPreEmitPeepholePass(CodeGenOptLevel OptLevel, bool DisablePeephole) +{ + return new SBFMIPreEmitPeephole(OptLevel, DisablePeephole); +} + +STATISTIC(TruncElemNum, "Number of truncation eliminated"); + +namespace { + +struct SBFMIPeepholeTruncElim : public MachineFunctionPass { + + static char ID; + const SBFInstrInfo *TII; + MachineFunction *MF; + MachineRegisterInfo *MRI; + + SBFMIPeepholeTruncElim() : MachineFunctionPass(ID) { + initializeSBFMIPeepholeTruncElimPass(*PassRegistry::getPassRegistry()); + } + +private: + // Initialize class variables. + void initialize(MachineFunction &MFParm); + + bool eliminateTruncSeq(); + +public: + + // Main entry point for this pass. + bool runOnMachineFunction(MachineFunction &MF) override { + if (skipFunction(MF.getFunction())) + return false; + + initialize(MF); + + return eliminateTruncSeq(); + } +}; + +static bool TruncSizeCompatible(int TruncSize, unsigned opcode, bool NewEncoding) +{ + if (TruncSize == 1) { + if (NewEncoding) + return opcode == SBF::LDB_V2 || opcode == SBF::LDB32_V2; + + return opcode == SBF::LDB_V1 || opcode == SBF::LDB32_V1; + } + + if (TruncSize == 2) { + if (NewEncoding) + return opcode == SBF::LDH_V2 || opcode == SBF::LDH32_V2; + + return opcode == SBF::LDH_V1 || opcode == SBF::LDH32_V1; + } + + if (TruncSize == 4) { + if (NewEncoding) + return opcode == SBF::LDW_V2 || opcode == SBF::LDW32_V2; + + return opcode == SBF::LDW_V1 || opcode == SBF::LDW32_V1; + } + + return false; +} + +// Initialize class variables. +void SBFMIPeepholeTruncElim::initialize(MachineFunction &MFParm) { + MF = &MFParm; + MRI = &MF->getRegInfo(); + TII = MF->getSubtarget().getInstrInfo(); + LLVM_DEBUG(dbgs() << "*** SBF MachineSSA TRUNC Elim peephole pass ***\n\n"); +} + +// Reg truncating is often the result of 8/16/32bit->64bit or +// 8/16bit->32bit conversion. If the reg value is loaded with +// masked byte width, the AND operation can be removed since +// SBF LOAD already has zero extension. +// +// This also solved a correctness issue. +// In SBF socket-related program, e.g., __sk_buff->{data, data_end} +// are 32-bit registers, but later on, kernel verifier will rewrite +// it with 64-bit value. Therefore, truncating the value after the +// load will result in incorrect code. +bool SBFMIPeepholeTruncElim::eliminateTruncSeq() { + MachineInstr* ToErase = nullptr; + bool Eliminated = false; + + bool NewEncoding = MF->getSubtarget().getNewMemEncoding(); + for (MachineBasicBlock &MBB : *MF) { + for (MachineInstr &MI : MBB) { + // The second insn to remove if the eliminate candidate is a pair. + MachineInstr *MI2 = nullptr; + Register DstReg, SrcReg; + MachineInstr *DefMI; + int TruncSize = -1; + + // If the previous instruction was marked for elimination, remove it now. + if (ToErase) { + ToErase->eraseFromParent(); + ToErase = nullptr; + } + + // AND A, 0xFFFFFFFF will be turned into SLL/SRL pair due to immediate + // for SBF ANDI is i32, and this case only happens on ALU64. + if (MI.getOpcode() == SBF::SRL_ri && + MI.getOperand(2).getImm() == 32) { + SrcReg = MI.getOperand(1).getReg(); + if (!MRI->hasOneNonDBGUse(SrcReg)) + continue; + + MI2 = MRI->getVRegDef(SrcReg); + DstReg = MI.getOperand(0).getReg(); + + if (!MI2 || + MI2->getOpcode() != SBF::SLL_ri || + MI2->getOperand(2).getImm() != 32) + continue; + + // Update SrcReg. + SrcReg = MI2->getOperand(1).getReg(); + DefMI = MRI->getVRegDef(SrcReg); + if (DefMI) + TruncSize = 4; + } else if (MI.getOpcode() == SBF::AND_ri || + MI.getOpcode() == SBF::AND_ri_32) { + SrcReg = MI.getOperand(1).getReg(); + DstReg = MI.getOperand(0).getReg(); + DefMI = MRI->getVRegDef(SrcReg); + + if (!DefMI) + continue; + + int64_t imm = MI.getOperand(2).getImm(); + if (imm == 0xff) + TruncSize = 1; + else if (imm == 0xffff) + TruncSize = 2; + } + + if (TruncSize == -1) + continue; + + // The definition is PHI node, check all inputs. + if (DefMI->isPHI()) { + bool CheckFail = false; + + for (unsigned i = 1, e = DefMI->getNumOperands(); i < e; i += 2) { + MachineOperand &opnd = DefMI->getOperand(i); + if (!opnd.isReg()) { + CheckFail = true; + break; + } + + MachineInstr *PhiDef = MRI->getVRegDef(opnd.getReg()); + if (!PhiDef || PhiDef->isPHI() || + !TruncSizeCompatible(TruncSize, + PhiDef->getOpcode(), NewEncoding)) { + CheckFail = true; + break; + } + } + + if (CheckFail) + continue; + } else if (!TruncSizeCompatible(TruncSize, + DefMI->getOpcode(), NewEncoding)) { + continue; + } + + BuildMI(MBB, MI, MI.getDebugLoc(), TII->get(SBF::MOV_rr), DstReg) + .addReg(SrcReg); + + if (MI2) + MI2->eraseFromParent(); + + // Mark it to ToErase, and erase in the next iteration. + ToErase = &MI; + TruncElemNum++; + Eliminated = true; + } + } + + return Eliminated; +} + +} // end default namespace + +INITIALIZE_PASS(SBFMIPeepholeTruncElim, "sbf-mi-trunc-elim", + "SBF MachineSSA Peephole Optimization For TRUNC Eliminate", + false, false) + +char SBFMIPeepholeTruncElim::ID = 0; +FunctionPass* llvm::createSBFMIPeepholeTruncElimPass() +{ + return new SBFMIPeepholeTruncElim(); +} diff --git a/llvm/lib/Target/SBF/SBFMISimplifyPatchable.cpp b/llvm/lib/Target/SBF/SBFMISimplifyPatchable.cpp new file mode 100644 index 0000000000000..0c42d3a5deb12 --- /dev/null +++ b/llvm/lib/Target/SBF/SBFMISimplifyPatchable.cpp @@ -0,0 +1,400 @@ +//===----- SBFMISimplifyPatchable.cpp - MI Simplify Patchable Insts -------===// +// +// 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 +// +//===----------------------------------------------------------------------===// +// +// This pass targets a subset of instructions like below +// ld_imm64 r1, @global +// ldd r2, r1, 0 +// add r3, struct_base_reg, r2 +// +// Here @global should represent an AMA (abstruct member access). +// Such an access is subject to bpf load time patching. After this pass, the +// code becomes +// ld_imm64 r1, @global +// add r3, struct_base_reg, r1 +// +// Eventually, at BTF output stage, a relocation record will be generated +// for ld_imm64 which should be replaced later by bpf loader: +// r1 = +// add r3, struct_base_reg, r1 +// +// This pass also removes the intermediate load generated in IR pass for +// __builtin_btf_type_id() intrinsic. +// +//===----------------------------------------------------------------------===// + +#include "SBF.h" +#include "SBFCORE.h" +#include "SBFInstrInfo.h" +#include "SBFTargetMachine.h" +#include "llvm/CodeGen/MachineInstrBuilder.h" +#include "llvm/CodeGen/MachineRegisterInfo.h" +#include "llvm/IR/GlobalVariable.h" +#include "llvm/Support/Debug.h" +#include + +using namespace llvm; + +#define DEBUG_TYPE "sbf-mi-simplify-patchable" + +namespace { + +struct SBFMISimplifyPatchable : public MachineFunctionPass { + + static char ID; + const SBFInstrInfo *TII; + MachineFunction *MF; + + SBFMISimplifyPatchable() : MachineFunctionPass(ID) { + initializeSBFMISimplifyPatchablePass(*PassRegistry::getPassRegistry()); + } + +private: + std::set SkipInsts; + + // Initialize class variables. + void initialize(MachineFunction &MFParm); + + bool isLoadInst(unsigned Opcode); + bool removeLD(); + void processCandidate(MachineRegisterInfo *MRI, MachineBasicBlock &MBB, + MachineInstr &MI, Register &SrcReg, Register &DstReg, + const GlobalValue *GVal, bool IsAma); + void processDstReg(MachineRegisterInfo *MRI, Register &DstReg, + Register &SrcReg, const GlobalValue *GVal, + bool doSrcRegProp, bool IsAma); + void processInst(MachineRegisterInfo *MRI, MachineInstr *Inst, + MachineOperand *RelocOp, const GlobalValue *GVal); + void checkADDrr(MachineRegisterInfo *MRI, MachineOperand *RelocOp, + const GlobalValue *GVal); + void checkShift(MachineRegisterInfo *MRI, MachineBasicBlock &MBB, + MachineOperand *RelocOp, const GlobalValue *GVal, + unsigned Opcode); + +public: + // Main entry point for this pass. + bool runOnMachineFunction(MachineFunction &MF) override { + if (skipFunction(MF.getFunction())) + return false; + + initialize(MF); + return removeLD(); + } +}; + +// Initialize class variables. +void SBFMISimplifyPatchable::initialize(MachineFunction &MFParm) { + MF = &MFParm; + TII = MF->getSubtarget().getInstrInfo(); + LLVM_DEBUG(dbgs() << "*** SBF simplify patchable insts pass ***\n\n"); +} + +static bool isST(unsigned Opcode, bool NewEncoding) { + if (NewEncoding) { + return Opcode == SBF::STB_imm_V2 || Opcode == SBF::STH_imm_V2 || + Opcode == SBF::STW_imm_V2 || Opcode == SBF::STD_imm_V2; + } + + return Opcode == SBF::STB_imm_V1 || Opcode == SBF::STH_imm_V1 || + Opcode == SBF::STW_imm_V1 || Opcode == SBF::STD_imm_V1; +} + +static bool isSTX32(unsigned Opcode, bool NewEncoding) { + if (NewEncoding) { + return Opcode == SBF::STB32_V2 || Opcode == SBF::STH32_V2 + || Opcode == SBF::STW32_V2; + } + return Opcode == SBF::STB32_V1 || Opcode == SBF::STH32_V1 + || Opcode == SBF::STW32_V1; +} + +static bool isSTX64(unsigned Opcode, bool NewEncoding) { + if (NewEncoding) { + return Opcode == SBF::STB_V2 || Opcode == SBF::STH_V2 || + Opcode == SBF::STW_V2 ||Opcode == SBF::STD_V2; + } + + return Opcode == SBF::STB_V1 || Opcode == SBF::STH_V1 || + Opcode == SBF::STW_V1 ||Opcode == SBF::STD_V1; +} + +static bool isLDX32(unsigned Opcode, bool NewEncoding) { + if (NewEncoding) + return Opcode == SBF::LDB32_V2 || Opcode == SBF::LDH32_V2 || + Opcode == SBF::LDW32_V2; + + return Opcode == SBF::LDB32_V1 || Opcode == SBF::LDH32_V1 || + Opcode == SBF::LDW32_V1; +} + +static bool isLDX64(unsigned Opcode, bool NewEncoding) { + if (NewEncoding) + return Opcode == SBF::LDB_V2 || Opcode == SBF::LDH_V2 || + Opcode == SBF::LDW_V2 || Opcode == SBF::LDD_V2; + + return Opcode == SBF::LDB_V1 || Opcode == SBF::LDH_V1 || + Opcode == SBF::LDW_V1 || Opcode == SBF::LDD_V1; +} + +bool SBFMISimplifyPatchable::isLoadInst(unsigned Opcode) { + bool NewMemEncoding = MF->getSubtarget().getNewMemEncoding(); + return isLDX32(Opcode, NewMemEncoding) || + isLDX64(Opcode, NewMemEncoding); +} + +void SBFMISimplifyPatchable::checkADDrr(MachineRegisterInfo *MRI, + MachineOperand *RelocOp, const GlobalValue *GVal) { + const MachineInstr *Inst = RelocOp->getParent(); + const MachineOperand *Op1 = &Inst->getOperand(1); + const MachineOperand *Op2 = &Inst->getOperand(2); + const MachineOperand *BaseOp = (RelocOp == Op1) ? Op2 : Op1; + + // Go through all uses of %1 as in %1 = ADD_rr %2, %3 + const SBFSubtarget& SubTarget = MF->getSubtarget(); + bool NewMemEncoding = SubTarget.getNewMemEncoding(); + const MachineOperand Op0 = Inst->getOperand(0); + for (MachineOperand &MO : + llvm::make_early_inc_range(MRI->use_operands(Op0.getReg()))) { + // The candidate needs to have a unique definition. + if (!MRI->getUniqueVRegDef(MO.getReg())) + continue; + + MachineInstr *DefInst = MO.getParent(); + unsigned Opcode = DefInst->getOpcode(); + unsigned COREOp; + if (isLDX64(Opcode, NewMemEncoding)) + COREOp = NewMemEncoding ? SBF::CORE_LD64_V2 : SBF::CORE_LD64_V1; + else if (isLDX32(Opcode, NewMemEncoding)) + COREOp = NewMemEncoding ? SBF::CORE_LD32_V2 : SBF::CORE_LD32_V1; + else if (isSTX64(Opcode, NewMemEncoding) || + isSTX32(Opcode, NewMemEncoding) || + isST(Opcode, NewMemEncoding)) + COREOp = NewMemEncoding ? SBF::CORE_ST_V2 : SBF::CORE_ST_V1; + else + continue; + + // It must be a form of %2 = *(type *)(%1 + 0) or *(type *)(%1 + 0) = %2. + const MachineOperand &ImmOp = DefInst->getOperand(2); + if (!ImmOp.isImm() || ImmOp.getImm() != 0) + continue; + + // Reject the form: + // %1 = ADD_rr %2, %3 + // *(type *)(%2 + 0) = %1 + if (isSTX64(Opcode, NewMemEncoding) || + isSTX32(Opcode, NewMemEncoding)) { + const MachineOperand &Opnd = DefInst->getOperand(0); + if (Opnd.isReg() && Opnd.getReg() == MO.getReg()) + continue; + } + + BuildMI(*DefInst->getParent(), *DefInst, DefInst->getDebugLoc(), TII->get(COREOp)) + .add(DefInst->getOperand(0)).addImm(Opcode).add(*BaseOp) + .addGlobalAddress(GVal); + DefInst->eraseFromParent(); + } +} + +void SBFMISimplifyPatchable::checkShift(MachineRegisterInfo *MRI, + MachineBasicBlock &MBB, MachineOperand *RelocOp, const GlobalValue *GVal, + unsigned Opcode) { + // Relocation operand should be the operand #2. + MachineInstr *Inst = RelocOp->getParent(); + if (RelocOp != &Inst->getOperand(2)) + return; + + BuildMI(MBB, *Inst, Inst->getDebugLoc(), TII->get(SBF::CORE_SHIFT)) + .add(Inst->getOperand(0)).addImm(Opcode) + .add(Inst->getOperand(1)).addGlobalAddress(GVal); + Inst->eraseFromParent(); +} + +void SBFMISimplifyPatchable::processCandidate(MachineRegisterInfo *MRI, + MachineBasicBlock &MBB, MachineInstr &MI, Register &SrcReg, + Register &DstReg, const GlobalValue *GVal, bool IsAma) { + if (MRI->getRegClass(DstReg) == &SBF::GPR32RegClass) { + if (IsAma) { + // We can optimize such a pattern: + // %1:gpr = LD_imm64 @"llvm.s:0:4$0:2" + // %2:gpr32 = LDW32 %1:gpr, 0 + // %3:gpr = SUBREG_TO_REG 0, %2:gpr32, %subreg.sub_32 + // %4:gpr = ADD_rr %0:gpr, %3:gpr + // or similar patterns below for non-alu32 case. + auto Begin = MRI->use_begin(DstReg), End = MRI->use_end(); + decltype(End) NextI; + for (auto I = Begin; I != End; I = NextI) { + NextI = std::next(I); + if (!MRI->getUniqueVRegDef(I->getReg())) + continue; + + unsigned Opcode = I->getParent()->getOpcode(); + if (Opcode == SBF::SUBREG_TO_REG) { + Register TmpReg = I->getParent()->getOperand(0).getReg(); + processDstReg(MRI, TmpReg, DstReg, GVal, false, IsAma); + } + } + } + + BuildMI(MBB, MI, MI.getDebugLoc(), TII->get(SBF::COPY), DstReg) + .addReg(SrcReg, 0, SBF::sub_32); + return; + } + + // All uses of DstReg replaced by SrcReg + processDstReg(MRI, DstReg, SrcReg, GVal, true, IsAma); +} + +void SBFMISimplifyPatchable::processDstReg(MachineRegisterInfo *MRI, + Register &DstReg, Register &SrcReg, const GlobalValue *GVal, + bool doSrcRegProp, bool IsAma) { + auto Begin = MRI->use_begin(DstReg), End = MRI->use_end(); + decltype(End) NextI; + for (auto I = Begin; I != End; I = NextI) { + NextI = std::next(I); + if (doSrcRegProp) { + // In situations like below it is not known if usage is a kill + // after setReg(): + // + // .-> %2:gpr = LD_imm64 @"llvm.t:0:0$0:0" + // | + // |`----------------. + // | %3:gpr = LDD %2:gpr, 0 + // | %4:gpr = ADD_rr %0:gpr(tied-def 0), killed %3:gpr <--- (1) + // | %5:gpr = LDD killed %4:gpr, 0 ^^^^^^^^^^^^^ + // | STD killed %5:gpr, %1:gpr, 0 this is I + // `----------------. + // %6:gpr = LDD %2:gpr, 0 + // %7:gpr = ADD_rr %0:gpr(tied-def 0), killed %6:gpr <--- (2) + // %8:gpr = LDD killed %7:gpr, 0 ^^^^^^^^^^^^^ + // STD killed %8:gpr, %1:gpr, 0 this is I + // + // Instructions (1) and (2) would be updated by setReg() to: + // + // ADD_rr %0:gpr(tied-def 0), %2:gpr + // + // %2:gpr is not killed at (1), so it is necessary to remove kill flag + // from I. + I->setReg(SrcReg); + I->setIsKill(false); + } + + // The candidate needs to have a unique definition. + if (IsAma && MRI->getUniqueVRegDef(I->getReg())) + processInst(MRI, I->getParent(), &*I, GVal); + } +} + +// Check to see whether we could do some optimization +// to attach relocation to downstream dependent instructions. +// Two kinds of patterns are recognized below: +// Pattern 1: +// %1 = LD_imm64 @"llvm.b:0:4$0:1" <== patch_imm = 4 +// %2 = LDD %1, 0 <== this insn will be removed +// %3 = ADD_rr %0, %2 +// %4 = LDW[32] %3, 0 OR STW[32] %4, %3, 0 +// The `%4 = ...` will be transformed to +// CORE_[ALU32_]MEM(%4, mem_opcode, %0, @"llvm.b:0:4$0:1") +// and later on, BTF emit phase will translate to +// %4 = LDW[32] %0, 4 STW[32] %4, %0, 4 +// and attach a relocation to it. +// Pattern 2: +// %15 = LD_imm64 @"llvm.t:5:63$0:2" <== relocation type 5 +// %16 = LDD %15, 0 <== this insn will be removed +// %17 = SRA_rr %14, %16 +// The `%17 = ...` will be transformed to +// %17 = CORE_SHIFT(SRA_ri, %14, @"llvm.t:5:63$0:2") +// and later on, BTF emit phase will translate to +// %r4 = SRA_ri %r4, 63 +void SBFMISimplifyPatchable::processInst(MachineRegisterInfo *MRI, + MachineInstr *Inst, MachineOperand *RelocOp, const GlobalValue *GVal) { + unsigned Opcode = Inst->getOpcode(); + if (isLoadInst(Opcode)) { + SkipInsts.insert(Inst); + return; + } + + if (Opcode == SBF::ADD_rr) + checkADDrr(MRI, RelocOp, GVal); + else if (Opcode == SBF::SLL_rr) + checkShift(MRI, *Inst->getParent(), RelocOp, GVal, SBF::SLL_ri); + else if (Opcode == SBF::SRA_rr) + checkShift(MRI, *Inst->getParent(), RelocOp, GVal, SBF::SRA_ri); + else if (Opcode == SBF::SRL_rr) + checkShift(MRI, *Inst->getParent(), RelocOp, GVal, SBF::SRL_ri); +} + +/// Remove unneeded Load instructions. +bool SBFMISimplifyPatchable::removeLD() { + MachineRegisterInfo *MRI = &MF->getRegInfo(); + MachineInstr *ToErase = nullptr; + bool Changed = false; + + for (MachineBasicBlock &MBB : *MF) { + for (MachineInstr &MI : MBB) { + if (ToErase) { + ToErase->eraseFromParent(); + ToErase = nullptr; + } + + // Ensure the register format is LOAD , , 0 + if (!isLoadInst(MI.getOpcode())) + continue; + + if (SkipInsts.find(&MI) != SkipInsts.end()) + continue; + + if (!MI.getOperand(0).isReg() || !MI.getOperand(1).isReg()) + continue; + + if (!MI.getOperand(2).isImm() || MI.getOperand(2).getImm()) + continue; + + Register DstReg = MI.getOperand(0).getReg(); + Register SrcReg = MI.getOperand(1).getReg(); + + MachineInstr *DefInst = MRI->getUniqueVRegDef(SrcReg); + if (!DefInst) + continue; + + if (DefInst->getOpcode() != SBF::LD_imm64) + continue; + + const MachineOperand &MO = DefInst->getOperand(1); + if (!MO.isGlobal()) + continue; + + const GlobalValue *GVal = MO.getGlobal(); + auto *GVar = dyn_cast(GVal); + if (!GVar) + continue; + + // Global variables representing structure offset or type id. + bool IsAma = false; + if (GVar->hasAttribute(SBFCoreSharedInfo::AmaAttr)) + IsAma = true; + else if (!GVar->hasAttribute(SBFCoreSharedInfo::TypeIdAttr)) + continue; + + processCandidate(MRI, MBB, MI, SrcReg, DstReg, GVal, IsAma); + + ToErase = &MI; + Changed = true; + } + } + + return Changed; +} + +} // namespace + +INITIALIZE_PASS(SBFMISimplifyPatchable, DEBUG_TYPE, + "SBF PreEmit SimplifyPatchable", false, false) + +char SBFMISimplifyPatchable::ID = 0; +FunctionPass *llvm::createSBFMISimplifyPatchablePass() { + return new SBFMISimplifyPatchable(); +} diff --git a/llvm/lib/Target/SBF/SBFPreserveDIType.cpp b/llvm/lib/Target/SBF/SBFPreserveDIType.cpp new file mode 100644 index 0000000000000..8c5dcbb37b2da --- /dev/null +++ b/llvm/lib/Target/SBF/SBFPreserveDIType.cpp @@ -0,0 +1,132 @@ +//===----------- SBFPreserveDIType.cpp - Preserve DebugInfo Types ---------===// +// +// 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 +// +//===----------------------------------------------------------------------===// +// +// Preserve Debuginfo types encoded in __builtin_btf_type_id() metadata. +// +//===----------------------------------------------------------------------===// + +#include "SBF.h" +#include "SBFCORE.h" +#include "llvm/IR/DebugInfoMetadata.h" +#include "llvm/IR/GlobalVariable.h" +#include "llvm/IR/Instruction.h" +#include "llvm/IR/Instructions.h" +#include "llvm/IR/Module.h" +#include "llvm/IR/PassManager.h" +#include "llvm/IR/Type.h" +#include "llvm/IR/Value.h" +#include "llvm/Pass.h" + +#define DEBUG_TYPE "sbf-preserve-di-type" + +namespace llvm { +constexpr StringRef SBFCoreSharedInfo::TypeIdAttr; +} // namespace llvm + +using namespace llvm; + +namespace { + +static bool SBFPreserveDITypeImpl(Function &F) { + LLVM_DEBUG(dbgs() << "********** preserve debuginfo type **********\n"); + + Module *M = F.getParent(); + + // Bail out if no debug info. + if (M->debug_compile_units().empty()) + return false; + + std::vector PreserveDITypeCalls; + + for (auto &BB : F) { + for (auto &I : BB) { + auto *Call = dyn_cast(&I); + if (!Call) + continue; + + const auto *GV = dyn_cast(Call->getCalledOperand()); + if (!GV) + continue; + + if (GV->getName().starts_with("llvm.bpf.btf.type.id")) { + if (!Call->getMetadata(LLVMContext::MD_preserve_access_index)) + report_fatal_error( + "Missing metadata for llvm.bpf.btf.type.id intrinsic"); + PreserveDITypeCalls.push_back(Call); + } + } + } + + if (PreserveDITypeCalls.empty()) + return false; + + std::string BaseName = "llvm.btf_type_id."; + static int Count = 0; + for (auto Call : PreserveDITypeCalls) { + const ConstantInt *Flag = dyn_cast(Call->getArgOperand(1)); + assert(Flag); + uint64_t FlagValue = Flag->getValue().getZExtValue(); + + if (FlagValue >= SBFCoreSharedInfo::MAX_BTF_TYPE_ID_FLAG) + report_fatal_error("Incorrect flag for llvm.bpf.btf.type.id intrinsic"); + + MDNode *MD = Call->getMetadata(LLVMContext::MD_preserve_access_index); + + uint32_t Reloc; + if (FlagValue == SBFCoreSharedInfo::BTF_TYPE_ID_LOCAL_RELOC) { + Reloc = SBFCoreSharedInfo::BTF_TYPE_ID_LOCAL; + } else { + Reloc = SBFCoreSharedInfo::BTF_TYPE_ID_REMOTE; + DIType *Ty = cast(MD); + while (auto *DTy = dyn_cast(Ty)) { + unsigned Tag = DTy->getTag(); + if (Tag != dwarf::DW_TAG_const_type && + Tag != dwarf::DW_TAG_volatile_type) + break; + Ty = DTy->getBaseType(); + } + + if (Ty->getName().empty()) { + if (isa(Ty)) + report_fatal_error( + "SubroutineType not supported for BTF_TYPE_ID_REMOTE reloc"); + else + report_fatal_error("Empty type name for BTF_TYPE_ID_REMOTE reloc"); + } + MD = Ty; + } + + BasicBlock *BB = Call->getParent(); + IntegerType *VarType = Type::getInt64Ty(BB->getContext()); + std::string GVName = + BaseName + std::to_string(Count) + "$" + std::to_string(Reloc); + GlobalVariable *GV = new GlobalVariable( + *M, VarType, false, GlobalVariable::ExternalLinkage, nullptr, GVName); + GV->addAttribute(SBFCoreSharedInfo::TypeIdAttr); + GV->setMetadata(LLVMContext::MD_preserve_access_index, MD); + + // Load the global variable which represents the type info. + auto *LDInst = + new LoadInst(Type::getInt64Ty(BB->getContext()), GV, "", Call->getIterator()); + Instruction *PassThroughInst = + SBFCoreSharedInfo::insertPassThrough(M, BB, LDInst, Call); + Call->replaceAllUsesWith(PassThroughInst); + Call->eraseFromParent(); + Count++; + } + + return true; +} + +} // End anonymous namespace + +PreservedAnalyses SBFPreserveDITypePass::run(Function &F, + FunctionAnalysisManager &AM) { + return SBFPreserveDITypeImpl(F) ? PreservedAnalyses::none() + : PreservedAnalyses::all(); +} diff --git a/llvm/lib/Target/SBF/SBFRegisterInfo.cpp b/llvm/lib/Target/SBF/SBFRegisterInfo.cpp new file mode 100644 index 0000000000000..4179e302c6dd6 --- /dev/null +++ b/llvm/lib/Target/SBF/SBFRegisterInfo.cpp @@ -0,0 +1,184 @@ +//===-- SBFRegisterInfo.cpp - SBF Register Information ----------*- 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 +// +//===----------------------------------------------------------------------===// +// +// This file contains the SBF implementation of the TargetRegisterInfo class. +// +//===----------------------------------------------------------------------===// + +#include "SBFFunctionInfo.h" +#include "SBFRegisterInfo.h" +#include "SBFSubtarget.h" +#include "llvm/CodeGen/MachineFrameInfo.h" +#include "llvm/CodeGen/MachineFunction.h" +#include "llvm/CodeGen/MachineInstrBuilder.h" +#include "llvm/CodeGen/RegisterScavenging.h" +#include "llvm/CodeGen/TargetFrameLowering.h" +#include "llvm/CodeGen/TargetInstrInfo.h" +#include "llvm/IR/DiagnosticInfo.h" +#include "llvm/Support/ErrorHandling.h" + +#define GET_REGINFO_TARGET_DESC +#include "SBFGenRegisterInfo.inc" +using namespace llvm; + +unsigned SBFRegisterInfo::FrameLength = 512; + +SBFRegisterInfo::SBFRegisterInfo() + : SBFGenRegisterInfo(SBF::R0) {} + +const MCPhysReg * +SBFRegisterInfo::getCalleeSavedRegs(const MachineFunction *MF) const { + return CSR_SaveList; +} + +BitVector SBFRegisterInfo::getReservedRegs(const MachineFunction &MF) const { + BitVector Reserved(getNumRegs()); + markSuperRegs(Reserved, SBF::W10); // [W|R]10 is read only frame pointer + return Reserved; +} + +static void WarnSize(int Offset, MachineFunction &MF, DebugLoc& DL) +{ + static Function *OldMF = nullptr; + int MaxOffset = -1 * SBFRegisterInfo::FrameLength; + if (Offset < MaxOffset) { + + if (&(MF.getFunction()) == OldMF) { + return; + } + OldMF = &(MF.getFunction()); + + dbgs() << "Error:"; + if (DL) { + dbgs() << " "; + DL.print(dbgs()); + } + uint64_t StackSize = MF.getFrameInfo().getStackSize(); + dbgs() << " Function " << MF.getFunction().getName() + << " Stack offset of " << -Offset << " exceeded max offset of " + << -MaxOffset << " by " << MaxOffset - Offset + << " bytes, please minimize large stack variables. " + << "Estimated function frame size: " << StackSize << " bytes." + << " Exceeding the maximum stack offset may cause " + "undefined behavior during execution.\n\n"; + } +} + +bool SBFRegisterInfo::eliminateFrameIndex(MachineBasicBlock::iterator II, + int SPAdj, unsigned FIOperandNum, + RegScavenger *RS) const { + assert(SPAdj == 0 && "Unexpected"); + + unsigned i = 0; + MachineInstr &MI = *II; + MachineBasicBlock &MBB = *MI.getParent(); + MachineFunction &MF = *MBB.getParent(); + DebugLoc DL = MI.getDebugLoc(); + + if (!DL) + /* try harder to get some debug loc */ + for (auto &I : MBB) + if (I.getDebugLoc()) { + DL = I.getDebugLoc().getFnDebugLoc(); + break; + } + + while (!MI.getOperand(i).isFI()) { + ++i; + assert(i < MI.getNumOperands() && "Instr doesn't have FrameIndex operand!"); + } + + Register FrameReg = getFrameRegister(MF); + int FrameIndex = MI.getOperand(i).getIndex(); + const TargetInstrInfo &TII = *MF.getSubtarget().getInstrInfo(); + + if (MI.getOpcode() == SBF::MOV_rr) { + int Offset = resolveInternalFrameIndex(MF, FrameIndex, std::nullopt); + + if (!MF.getSubtarget().getHasDynamicFrames()) { + WarnSize(Offset, MF, DL); + } + MI.getOperand(i).ChangeToRegister(FrameReg, false); + Register reg = MI.getOperand(i - 1).getReg(); + BuildMI(MBB, ++II, DL, TII.get(SBF::ADD_ri), reg) + .addReg(reg) + .addImm(Offset); + return false; + } + + int Offset = + resolveInternalFrameIndex(MF, FrameIndex, MI.getOperand(i + 1).getImm()); + + + if (!isInt<32>(Offset)) + llvm_unreachable("bug in frame offset"); + + if (!MF.getSubtarget().getHasDynamicFrames()) { + WarnSize(Offset, MF, DL); + } + + if (MI.getOpcode() == SBF::FI_ri) { + // architecture does not really support FI_ri, replace it with + // MOV_rr , frame_reg + // ADD_ri , imm + Register reg = MI.getOperand(i - 1).getReg(); + + BuildMI(MBB, ++II, DL, TII.get(SBF::MOV_rr), reg) + .addReg(FrameReg); + BuildMI(MBB, II, DL, TII.get(SBF::ADD_ri), reg) + .addReg(reg) + .addImm(Offset); + + // Remove FI_ri instruction + MI.eraseFromParent(); + } else { + MI.getOperand(i).ChangeToRegister(FrameReg, false); + MI.getOperand(i + 1).ChangeToImmediate(Offset); + } + return false; +} + +int SBFRegisterInfo::resolveInternalFrameIndex( + const llvm::MachineFunction &MF, int FI, std::optional Imm) const { + const MachineFrameInfo &MFI = MF.getFrameInfo(); + const SBFFunctionInfo *SBFFuncInfo = MF.getInfo(); + int Offset = MFI.getObjectOffset(FI); + const SBFSubtarget & SubTarget = MF.getSubtarget(); + uint64_t StackSize = MFI.getStackSize(); + + if (!SubTarget.getHasDynamicFrames() && + SBFFuncInfo->containsFrameIndex(FI)) { + Offset = SBFRegisterInfo::FrameLength - Offset; + if (static_cast(Offset) < StackSize) { + dbgs() << "Error: A function call in method " + << MF.getFunction().getName() + << " overwrites values in the frame. Please, decrease stack usage " + << "or remove parameters from the call. " + << "The function call may cause undefined behavior " + "during execution.\n\n"; + } + return -Offset; + } + + if (SubTarget.getHasDynamicFrames() && + SBFFuncInfo->containsFrameIndex(FI)) { + return -Offset; + } + + Offset += Imm.value_or(0); + + if (SubTarget.getHasDynamicFrames()) { + return static_cast(StackSize) + Offset; + } + + return Offset; +} + +Register SBFRegisterInfo::getFrameRegister(const MachineFunction &MF) const { + return SBF::R10; +} diff --git a/llvm/lib/Target/SBF/SBFRegisterInfo.h b/llvm/lib/Target/SBF/SBFRegisterInfo.h new file mode 100644 index 0000000000000..ee5b9f99c5fea --- /dev/null +++ b/llvm/lib/Target/SBF/SBFRegisterInfo.h @@ -0,0 +1,44 @@ +//===-- SBFRegisterInfo.h - SBF Register Information Impl -------*- 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 +// +//===----------------------------------------------------------------------===// +// +// This file contains the SBF implementation of the TargetRegisterInfo class. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIB_TARGET_SBF_SBFREGISTERINFO_H +#define LLVM_LIB_TARGET_SBF_SBFREGISTERINFO_H + +#include "llvm/CodeGen/TargetRegisterInfo.h" +#include + +#define GET_REGINFO_HEADER +#include "SBFGenRegisterInfo.inc" + +namespace llvm { + +struct SBFRegisterInfo : public SBFGenRegisterInfo { + static unsigned FrameLength; + + SBFRegisterInfo(); + + const MCPhysReg *getCalleeSavedRegs(const MachineFunction *MF) const override; + + BitVector getReservedRegs(const MachineFunction &MF) const override; + + bool eliminateFrameIndex(MachineBasicBlock::iterator MI, int SPAdj, + unsigned FIOperandNum, + RegScavenger *RS = nullptr) const override; + + Register getFrameRegister(const MachineFunction &MF) const override; + + int resolveInternalFrameIndex(const MachineFunction &MF, int FI, + std::optional Imm) const; +}; +} + +#endif diff --git a/llvm/lib/Target/SBF/SBFRegisterInfo.td b/llvm/lib/Target/SBF/SBFRegisterInfo.td new file mode 100644 index 0000000000000..2b434f2cea24d --- /dev/null +++ b/llvm/lib/Target/SBF/SBFRegisterInfo.td @@ -0,0 +1,49 @@ +//===-- SBFRegisterInfo.td - SBF Register defs -------------*- tablegen -*-===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +//===----------------------------------------------------------------------===// +// Declarations that describe the SBF register file +//===----------------------------------------------------------------------===// + +let Namespace = "SBF" in { + def sub_32 : SubRegIndex<32>; +} + +class Wi Enc, string n> : Register { + let HWEncoding = Enc; + let Namespace = "SBF"; +} + +// Registers are identified with 4-bit ID numbers. +// Ri - 64-bit integer registers +class Ri Enc, string n, list subregs> + : RegisterWithSubRegs { + let HWEncoding = Enc; + let Namespace = "SBF"; + let SubRegIndices = [sub_32]; +} + +foreach I = 0-10 in { + // 32-bit Integer (alias to low part of 64-bit register). + def W#I : Wi, DwarfRegNum<[I]>; + // 64-bit Integer registers + def R#I : Ri("W"#I)]>, DwarfRegNum<[I]>; +} + +// Register classes. +def GPR32 : RegisterClass<"SBF", [i32], 64, (add + (sequence "W%u", 1, 9), + W0, // Return value + W10 // Frame Ptr +)>; + +def GPR : RegisterClass<"SBF", [i64], 64, (add + (sequence "R%u", 1, 9), + R0, // Return value + R10 // Frame Ptr +)>; diff --git a/llvm/lib/Target/SBF/SBFSelectionDAGInfo.h b/llvm/lib/Target/SBF/SBFSelectionDAGInfo.h new file mode 100644 index 0000000000000..49fe4f4fb3d0f --- /dev/null +++ b/llvm/lib/Target/SBF/SBFSelectionDAGInfo.h @@ -0,0 +1,31 @@ +//===-- SBFSelectionDAGInfo.h - SBF SelectionDAG Info -----------*- 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 +// +//===----------------------------------------------------------------------===// +// +// This file defines the SBF subclass for SelectionDAGTargetInfo. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIB_TARGET_SBF_SBFSELECTIONDAGINFO_H +#define LLVM_LIB_TARGET_SBF_SBFSELECTIONDAGINFO_H + +#include "llvm/CodeGen/SelectionDAGTargetInfo.h" + +namespace llvm { + +class SBFSelectionDAGInfo : public SelectionDAGTargetInfo { +public: + SBFSelectionDAGInfo() {} + + unsigned getCommonMaxStoresPerMemFunc() const { + return 4; + } +}; + +} + +#endif diff --git a/llvm/lib/Target/SBF/SBFSubtarget.cpp b/llvm/lib/Target/SBF/SBFSubtarget.cpp new file mode 100644 index 0000000000000..93979cb1c68e7 --- /dev/null +++ b/llvm/lib/Target/SBF/SBFSubtarget.cpp @@ -0,0 +1,80 @@ +//===-- SBFSubtarget.cpp - SBF Subtarget Information ----------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// +// +// This file implements the SBF specific subclass of TargetSubtargetInfo. +// +//===----------------------------------------------------------------------===// + +#include "SBFSubtarget.h" +#include "SBF.h" +#include "SBFTargetMachine.h" +#include "GISel/SBFCallLowering.h" +#include "GISel/SBFLegalizerInfo.h" +#include "GISel/SBFRegisterBankInfo.h" +#include "llvm/MC/TargetRegistry.h" +#include "llvm/TargetParser/Host.h" +#include "TargetInfo/SBFTargetInfo.h" + +using namespace llvm; + +#define DEBUG_TYPE "sbf-subtarget" + +#define GET_SUBTARGETINFO_TARGET_DESC +#define GET_SUBTARGETINFO_CTOR +#include "SBFGenSubtargetInfo.inc" + +void SBFSubtarget::anchor() {} + +SBFSubtarget &SBFSubtarget::initializeSubtargetDependencies(const Triple &TT, + StringRef CPU, + StringRef FS) { + initializeEnvironment(TT); + initSubtargetFeatures(CPU, FS); + InstrInfo.initializeTargetFeatures(HasExplicitSignExt, NewMemEncoding); + return *this; +} + +void SBFSubtarget::initializeEnvironment(const Triple &TT) { + assert(TT.getArch() == Triple::sbf && "expected Triple::sbf"); + UseDwarfRIS = false; + + // New SBF features + HasJmpExt = false; + HasDynamicFrames = false; + DisableNeg = false; + ReverseSubImm = false; + NoLddw = false; + CallxRegSrc = false; + HasPqrClass = false; + HasStoreImm = false; + HasAlu32 = false; + HasExplicitSignExt = false; + NewMemEncoding = false; + HasStaticSyscalls = false; + IsAbiV2 = false; +} + +void SBFSubtarget::initSubtargetFeatures(StringRef CPU, StringRef FS) { + ParseSubtargetFeatures(CPU, /*TuneCPU*/ CPU, FS); +} + +SBFSubtarget::SBFSubtarget(const Triple &TT, const std::string &CPU, + const std::string &FS, const TargetMachine &TM) + : SBFGenSubtargetInfo(TT, cpuFromSubArch(TT, CPU), /*TuneCPU*/ cpuFromSubArch(TT, CPU), FS), InstrInfo(), + FrameLowering(initializeSubtargetDependencies(TT, cpuFromSubArch(TT, CPU), FS)), + TLInfo(TM, *this) { + assert(TT.getArch() == Triple::sbf && "expected Triple::sbf"); + + CallLoweringInfo.reset(new SBFCallLowering(*getTargetLowering())); + Legalizer.reset(new SBFLegalizerInfo(*this)); + auto *RBI = new SBFRegisterBankInfo(*getRegisterInfo()); + RegBankInfo.reset(RBI); + + InstSelector.reset(createSBFInstructionSelector( + *static_cast(&TM), *this, *RBI)); +} diff --git a/llvm/lib/Target/SBF/SBFSubtarget.h b/llvm/lib/Target/SBF/SBFSubtarget.h new file mode 100644 index 0000000000000..19208b061f03f --- /dev/null +++ b/llvm/lib/Target/SBF/SBFSubtarget.h @@ -0,0 +1,140 @@ +//===-- SBFSubtarget.h - Define Subtarget for the SBF -----------*- 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 +// +//===----------------------------------------------------------------------===// +// +// This file declares the SBF specific subclass of TargetSubtargetInfo. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIB_TARGET_SBF_SBFSUBTARGET_H +#define LLVM_LIB_TARGET_SBF_SBFSUBTARGET_H + +#include "SBFFrameLowering.h" +#include "SBFISelLowering.h" +#include "SBFInstrInfo.h" +#include "SBFRegisterInfo.h" +#include "SBFSelectionDAGInfo.h" +#include "llvm/CodeGen/GlobalISel/CallLowering.h" +#include "llvm/CodeGen/GlobalISel/InstructionSelector.h" +#include "llvm/CodeGen/GlobalISel/LegalizerInfo.h" +#include "llvm/CodeGen/RegisterBankInfo.h" +#include "llvm/CodeGen/SelectionDAGTargetInfo.h" +#include "llvm/CodeGen/TargetSubtargetInfo.h" +#include "llvm/IR/DataLayout.h" +#include "llvm/Target/TargetMachine.h" + +#define GET_SUBTARGETINFO_HEADER +#include "SBFGenSubtargetInfo.inc" + +namespace llvm { +class StringRef; + +class SBFSubtarget : public SBFGenSubtargetInfo { + virtual void anchor(); + SBFInstrInfo InstrInfo; + SBFFrameLowering FrameLowering; + SBFTargetLowering TLInfo; + SBFSelectionDAGInfo TSInfo; + +private: + void initializeEnvironment(const Triple &TT); + void initSubtargetFeatures(StringRef CPU, StringRef FS); + +protected: + // whether the cpu supports jmp ext + bool HasJmpExt; + + // whether the cpu supports alu32 instructions. + bool HasAlu32; + + // whether we should use fixed or dynamic frames + bool HasDynamicFrames; + + // Relocate FK_Data_8 fixups as R_SBF_64_ABS64 + bool UseRelocAbs64; + + // Not used for anything, just set by the static-syscalls marker feature. + bool HasStaticSyscalls; + + // whether we should enable MCAsmInfo DwarfUsesRelocationsAcrossSections + bool UseDwarfRIS; + + // Whether to disable the negate (neg) instruction + bool DisableNeg; + + // Whether to consider 'sub reg, imm' as 'reg = imm - reg', instead of 'reg = + // reg - imm'. + bool ReverseSubImm; + + // Whether we should use the LDDW instruction + bool NoLddw; + + // Whether to encode destination register in Callx's src field + bool CallxRegSrc; + + // Whether we have the PQR instruction class + bool HasPqrClass; + + // Whether we have store imm instructions + bool HasStoreImm; + + // Whether we have the explicit sign extension instruction (mov32) + bool HasExplicitSignExt; + + // Whether we enable the new encoding for memory instructions + bool NewMemEncoding; + + // Whether we are using AbiV2 + bool IsAbiV2; + + std::unique_ptr CallLoweringInfo; + std::unique_ptr InstSelector; + std::unique_ptr Legalizer; + std::unique_ptr RegBankInfo; + +public: + // This constructor initializes the data members to match that + // of the specified triple. + SBFSubtarget(const Triple &TT, const std::string &CPU, const std::string &FS, + const TargetMachine &TM); + + SBFSubtarget &initializeSubtargetDependencies(const Triple &TT, StringRef CPU, + StringRef FS); + + // ParseSubtargetFeatures - Parses features string setting specified + // subtarget options. Definition of function is auto generated by tblgen. + void ParseSubtargetFeatures(StringRef CPU, StringRef TuneCPU, StringRef FS); + bool getHasJmpExt() const { return HasJmpExt; } + bool getHasAlu32() const { return HasAlu32; } + bool getHasDynamicFrames() const { return HasDynamicFrames; } + bool getUseDwarfRIS() const { return UseDwarfRIS; } + bool getDisableNeg() const { return DisableNeg; } + bool getReverseSubImm() const { return ReverseSubImm; } + bool getNoLddw() const { return NoLddw; } + bool getCallXRegSrc() const { return CallxRegSrc; } + bool getHasPqrClass() const { return HasPqrClass; } + bool getHasStoreImm() const { return HasStoreImm; } + bool getHasExplicitSignExt() const { return HasExplicitSignExt; } + bool getNewMemEncoding() const { return NewMemEncoding; } + bool getHasStaticSyscalls() const { return HasStaticSyscalls; } + const SBFInstrInfo *getInstrInfo() const override { return &InstrInfo; } + const SBFFrameLowering *getFrameLowering() const override { + return &FrameLowering; + } + const SBFTargetLowering *getTargetLowering() const override { + return &TLInfo; + } + const SBFSelectionDAGInfo *getSelectionDAGInfo() const override { + return &TSInfo; + } + const SBFRegisterInfo *getRegisterInfo() const override { + return &InstrInfo.getRegisterInfo(); + } +}; +} // namespace llvm + +#endif diff --git a/llvm/lib/Target/SBF/SBFTargetFeatures.td b/llvm/lib/Target/SBF/SBFTargetFeatures.td new file mode 100644 index 0000000000000..ab302f6022890 --- /dev/null +++ b/llvm/lib/Target/SBF/SBFTargetFeatures.td @@ -0,0 +1,77 @@ +//===-- SBFTargetFeatures.td - Target Features for SBF Target ---------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// +// +// This file describes the SBF target features in TableGen format. +// +//===----------------------------------------------------------------------===// + +def ALU32 : SubtargetFeature<"alu32", "HasAlu32", "true", + "Enable ALU32 instructions">; + +def DwarfRIS: SubtargetFeature<"dwarfris", "UseDwarfRIS", "true", + "Disable MCAsmInfo DwarfUsesRelocationsAcrossSections">; + +def FeatureDynamicFrames : SubtargetFeature<"dynamic-frames", "HasDynamicFrames", "true", + "Enable dynamic frames">; + +def FeatureRelocAbs64 : SubtargetFeature<"reloc-abs64", "UseRelocAbs64", "true", + "Fix 64bit data relocations">; + +def FeatureStaticSyscalls : SubtargetFeature<"static-syscalls", "HasStaticSyscalls", "true", + "Enable static syscalls">; + +def FeatureDisableNeg : SubtargetFeature<"no-neg", "DisableNeg", "true", + "Disable the neg instruction">; + +def FeatureReverseSubImm : SubtargetFeature<"reverse-sub", "ReverseSubImm", "true", + "Reverse the operands in the 'sub reg, imm' instruction">; + +def FeatureDisableLddw : SubtargetFeature<"no-lddw", "NoLddw", "true", + "Disable the lddw instruction">; + +def FeatureCallxRegSrc : SubtargetFeature<"callx-reg-src", "CallxRegSrc", "true", + "Encode Callx destination register in the src field">; + +def FeaturePqrInstr : SubtargetFeature<"pqr-instr", "HasPqrClass", "true", + "Enable the PQR instruction class">; + +def FeatureStoreImm : SubtargetFeature<"store-imm", "HasStoreImm", "true", + "Enable store imm instructions">; + +def FeatureExplicitSext : SubtargetFeature<"explicit-sext", "HasExplicitSignExt", + "true", "Enable the explicit sign extension instruction mov32">; + +def FeatureNewMemEncoding : SubtargetFeature<"mem-encoding", "NewMemEncoding", + "true", "Enable the new encoding for memory instructions">; + +def FeatureJumpExt : SubtargetFeature<"jmp-ext", "HasJmpExt", + "true", "Enable jumps with less than and less than or equal">; + +def FeatureAbiV2 : SubtargetFeature<"abi-v2", "IsAbiV2", + "true", "Enables AbiV2 in SBF (no-op in LLVM)">; + + +class Proc Features> + : Processor; + +def : Proc<"generic", []>; + +def : Proc<"v1", [FeatureDynamicFrames, FeatureStoreImm, FeatureJumpExt]>; + +def : Proc<"v2", [FeatureDynamicFrames, FeatureStoreImm, FeatureJumpExt, FeatureDisableLddw, + FeatureNewMemEncoding, FeatureCallxRegSrc, FeaturePqrInstr, FeatureExplicitSext, + FeatureDisableNeg, FeatureReverseSubImm, ALU32]>; + +def : Proc<"v3", [FeatureDynamicFrames, FeatureStoreImm, FeatureJumpExt, FeatureDisableLddw, + FeatureNewMemEncoding, FeatureCallxRegSrc, FeaturePqrInstr, FeatureExplicitSext, + FeatureDisableNeg, FeatureReverseSubImm, ALU32, FeatureStaticSyscalls, FeatureRelocAbs64]>; + +def : Proc<"v4", [FeatureDynamicFrames, FeatureStoreImm, FeatureJumpExt, FeatureDisableLddw, + FeatureNewMemEncoding, FeatureCallxRegSrc, FeaturePqrInstr, FeatureExplicitSext, + FeatureDisableNeg, FeatureReverseSubImm, ALU32, FeatureStaticSyscalls, FeatureRelocAbs64, + FeatureAbiV2]>; \ No newline at end of file diff --git a/llvm/lib/Target/SBF/SBFTargetMachine.cpp b/llvm/lib/Target/SBF/SBFTargetMachine.cpp new file mode 100644 index 0000000000000..36128b388cc30 --- /dev/null +++ b/llvm/lib/Target/SBF/SBFTargetMachine.cpp @@ -0,0 +1,169 @@ +//===-- SBFTargetMachine.cpp - Define TargetMachine for SBF ---------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// +// +// Implements the info about SBF target spec. +// +//===----------------------------------------------------------------------===// + +#include "SBF.h" +#include "SBFTargetMachine.h" +#include "SBFTargetTransformInfo.h" +#include "SBFFunctionInfo.h" +#include "MCTargetDesc/SBFMCAsmInfo.h" +#include "TargetInfo/SBFTargetInfo.h" +#include "llvm/CodeGen/Passes.h" +#include "llvm/CodeGen/TargetLoweringObjectFileImpl.h" +#include "llvm/CodeGen/TargetPassConfig.h" +#include "llvm/IR/PassManager.h" +#include "llvm/MC/TargetRegistry.h" +#include "llvm/Passes/PassBuilder.h" +#include "llvm/Target/TargetOptions.h" +#include "llvm/Transforms/Scalar.h" +#include "llvm/Transforms/Scalar/SimplifyCFG.h" +#include "llvm/Transforms/Utils/SimplifyCFGOptions.h" +#include +using namespace llvm; + +static cl:: +opt DisableMIPeephole("disable-sbf-peephole", cl::Hidden, + cl::desc("Disable machine peepholes for SBF")); + +extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeSBFTarget() { + // Register the target. + RegisterTargetMachine XX(getTheSBFXTarget()); + + PassRegistry &PR = *PassRegistry::getPassRegistry(); + initializeSBFCheckAndAdjustIRPass(PR); + initializeSBFMIPeepholePass(PR); + initializeSBFMIPeepholeTruncElimPass(PR); + initializeSBFDAGToDAGISelLegacyPass(PR); +} + +// DataLayout: little or big endian +static std::string computeDataLayout(const Triple &TT, StringRef FS) { + // TOOD: jle; specialize this (and elsewhere) to Solana-only once the new + // back-end is integrated; e.g. we won't need IsSolana, etc. + assert(TT.getArch() == Triple::sbf && "expected Triple::sbf"); + return "e-m:e-p:64:64-i64:64-n32:64-S128"; +} + +static Reloc::Model getEffectiveRelocModel(std::optional RM) { + return RM.value_or(Reloc::PIC_); +} + +SBFTargetMachine::SBFTargetMachine(const Target &T, const Triple &TT, + StringRef CPU, StringRef FS, + const TargetOptions &Options, + std::optional RM, + std::optional CM, + CodeGenOptLevel OL, bool JIT) + : CodeGenTargetMachineImpl(T, computeDataLayout(TT, FS), TT, CPU, FS, Options, + getEffectiveRelocModel(RM), + getEffectiveCodeModel(CM, CodeModel::Small), OL), + TLOF(std::make_unique()), + Subtarget(TT, std::string(CPU), std::string(FS), *this) { + initAsmInfo(); + + SBFMCAsmInfo *MAI = + static_cast(const_cast(AsmInfo.get())); + MAI->setDwarfUsesRelocationsAcrossSections(!Subtarget.getUseDwarfRIS()); + MAI->setSupportsDebugInformation(true); +} + +namespace { +// SBF Code Generator Pass Configuration Options. +class SBFPassConfig : public TargetPassConfig { +public: + SBFPassConfig(SBFTargetMachine &TM, PassManagerBase &PM) + : TargetPassConfig(TM, PM) {} + + SBFTargetMachine &getSBFTargetMachine() const { + return getTM(); + } + + void addIRPasses() override; + bool addInstSelector() override; + void addMachineSSAOptimization() override; + void addPreEmitPass() override; +}; +} + +TargetPassConfig *SBFTargetMachine::createPassConfig(PassManagerBase &PM) { + return new SBFPassConfig(*this, PM); +} + +void SBFTargetMachine::registerPassBuilderCallbacks(PassBuilder &PB) { + PB.registerPipelineParsingCallback( + [](StringRef PassName, FunctionPassManager &FPM, + ArrayRef) { + if (PassName == "sbf-ir-peephole") { + FPM.addPass(SBFIRPeepholePass()); + return true; + } + return false; + }); + PB.registerPipelineStartEPCallback( + [=](ModulePassManager &MPM, OptimizationLevel) { + FunctionPassManager FPM; + FPM.addPass(SBFAbstractMemberAccessPass(this)); + FPM.addPass(SBFPreserveDITypePass()); + FPM.addPass(SBFIRPeepholePass()); + MPM.addPass(createModuleToFunctionPassAdaptor(std::move(FPM))); + }); + PB.registerPeepholeEPCallback([=](FunctionPassManager &FPM, + OptimizationLevel Level) { + FPM.addPass(SimplifyCFGPass( + SimplifyCFGOptions().hoistCommonInsts(true).convertSwitchToLookupTable( + true))); + }); +} + +void SBFPassConfig::addIRPasses() { + addPass(createSBFCheckAndAdjustIR()); + TargetPassConfig::addIRPasses(); +} + +TargetTransformInfo +SBFTargetMachine::getTargetTransformInfo(const Function &F) const { + return TargetTransformInfo(SBFTTIImpl(this, F)); +} + +MachineFunctionInfo *SBFTargetMachine::createMachineFunctionInfo( + llvm::BumpPtrAllocator &Allocator, const llvm::Function &F, + const llvm::TargetSubtargetInfo *STI) const { + return SBFFunctionInfo::create( + Allocator, F, static_cast(STI)); +} + +// Install an instruction selector pass using +// the ISelDag to gen SBF code. +bool SBFPassConfig::addInstSelector() { + addPass(createSBFISelDag(getSBFTargetMachine())); + + return false; +} + +void SBFPassConfig::addMachineSSAOptimization() { + addPass(createSBFMISimplifyPatchablePass()); + + // The default implementation must be called first as we want eBPF + // Peephole ran at last. + TargetPassConfig::addMachineSSAOptimization(); + + const SBFSubtarget *Subtarget = getSBFTargetMachine().getSubtargetImpl(); + if (!DisableMIPeephole) { + if (Subtarget->getHasAlu32() && Subtarget->getHasExplicitSignExt()) + addPass(createSBFMIPeepholePass()); + addPass(createSBFMIPeepholeTruncElimPass()); + } +} + +void SBFPassConfig::addPreEmitPass() { + addPass(createSBFMIPreEmitCheckingPass()); + addPass(createSBFMIPreEmitPeepholePass(getOptLevel(), DisableMIPeephole)); +} diff --git a/llvm/lib/Target/SBF/SBFTargetMachine.h b/llvm/lib/Target/SBF/SBFTargetMachine.h new file mode 100644 index 0000000000000..80c06b4cfde81 --- /dev/null +++ b/llvm/lib/Target/SBF/SBFTargetMachine.h @@ -0,0 +1,52 @@ +//===-- SBFTargetMachine.h - Define TargetMachine for SBF --- 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 +// +//===----------------------------------------------------------------------===// +// +// This file declares the SBF specific subclass of TargetMachine. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIB_TARGET_SBF_SBFTARGETMACHINE_H +#define LLVM_LIB_TARGET_SBF_SBFTARGETMACHINE_H + +#include "SBFSubtarget.h" +#include "llvm/CodeGen/CodeGenTargetMachineImpl.h" + +namespace llvm { +class SBFTargetMachine : public CodeGenTargetMachineImpl { + std::unique_ptr TLOF; + SBFSubtarget Subtarget; + +public: + SBFTargetMachine(const Target &T, const Triple &TT, StringRef CPU, + StringRef FS, const TargetOptions &Options, + std::optional RM, + std::optional CM, CodeGenOptLevel OL, + bool JIT); + + const SBFSubtarget *getSubtargetImpl() const { return &Subtarget; } + const SBFSubtarget *getSubtargetImpl(const Function &) const override { + return &Subtarget; + } + + TargetPassConfig *createPassConfig(PassManagerBase &PM) override; + + TargetTransformInfo getTargetTransformInfo(const Function &F) const override; + + TargetLoweringObjectFile *getObjFileLowering() const override { + return TLOF.get(); + } + + void registerPassBuilderCallbacks(PassBuilder &PB) override; + + MachineFunctionInfo * + createMachineFunctionInfo(BumpPtrAllocator &Allocator, const Function &F, + const TargetSubtargetInfo *STI) const override; +}; +} + +#endif diff --git a/llvm/lib/Target/SBF/SBFTargetTransformInfo.h b/llvm/lib/Target/SBF/SBFTargetTransformInfo.h new file mode 100644 index 0000000000000..fd684ff36cf96 --- /dev/null +++ b/llvm/lib/Target/SBF/SBFTargetTransformInfo.h @@ -0,0 +1,97 @@ +//===------ SBFTargetTransformInfo.h - SBF specific TTI ---------*- 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 +// +//===----------------------------------------------------------------------===// +// +// This file uses the target's specific information to +// provide more precise answers to certain TTI queries, while letting the +// target independent and default TTI implementations handle the rest. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIB_TARGET_SBF_SBFTARGETTRANSFORMINFO_H +#define LLVM_LIB_TARGET_SBF_SBFTARGETTRANSFORMINFO_H + +#include "SBFTargetMachine.h" +#include "llvm/Analysis/TargetTransformInfo.h" +#include "llvm/CodeGen/BasicTTIImpl.h" +#include "llvm/Transforms/Utils/ScalarEvolutionExpander.h" + +namespace llvm { +class SBFTTIImpl : public BasicTTIImplBase { + typedef BasicTTIImplBase BaseT; + typedef TargetTransformInfo TTI; + friend BaseT; + + const SBFSubtarget *ST; + const SBFTargetLowering *TLI; + + const SBFSubtarget *getST() const { return ST; } + const SBFTargetLowering *getTLI() const { return TLI; } + +public: + explicit SBFTTIImpl(const SBFTargetMachine *TM, const Function &F) + : BaseT(TM, F.getParent()->getDataLayout()), ST(TM->getSubtargetImpl(F)), + TLI(ST->getTargetLowering()) {} + + int getIntImmCost(const APInt &Imm, Type *Ty, TTI::TargetCostKind CostKind) { + if (Imm.getBitWidth() <= 64 && isInt<32>(Imm.getSExtValue())) + return TTI::TCC_Free; + + return TTI::TCC_Basic; + } + + bool shouldBuildLookupTables() const { + return true; + } + + bool shouldBuildRelLookupTables() const { + // Relational lookup tables are not working for SBF, since the offset + // calculation is not implemented. + return false; + } + + InstructionCost getCmpSelInstrCost( + unsigned Opcode, Type *ValTy, Type *CondTy, CmpInst::Predicate VecPred, + TTI::TargetCostKind CostKind, + TTI::OperandValueInfo Op1Info = {TTI::OK_AnyValue, TTI::OP_None}, + TTI::OperandValueInfo Op2Info = {TTI::OK_AnyValue, TTI::OP_None}, + const llvm::Instruction *I = nullptr) { + if (Opcode == Instruction::Select) + return SCEVCheapExpansionBudget.getValue(); + + return BaseT::getCmpSelInstrCost(Opcode, ValTy, CondTy, VecPred, CostKind, + Op1Info, Op2Info, I); + } + + InstructionCost getArithmeticInstrCost( + unsigned Opcode, Type *Ty, TTI::TargetCostKind CostKind, + TTI::OperandValueInfo Op1Info = {TTI::OK_AnyValue, TTI::OP_None}, + TTI::OperandValueInfo Op2Info = {TTI::OK_AnyValue, TTI::OP_None}, + ArrayRef Args = {}, const Instruction *CxtI = nullptr) { + int ISDOpcode = TLI->InstructionOpcodeToISD(Opcode); + + if ((ISDOpcode == ISD::ADD && CostKind == TTI::TCK_RecipThroughput) || + !Ty->isIntOrPtrTy()) + return SCEVCheapExpansionBudget.getValue() + 1; + + return BaseT::getArithmeticInstrCost(Opcode, Ty, CostKind, Op1Info, + Op2Info); + } + + TTI::MemCmpExpansionOptions enableMemCmpExpansion(bool OptSize, + bool IsZeroCmp) const { + TTI::MemCmpExpansionOptions Options; + Options.LoadSizes = {8, 4, 2, 1}; + Options.MaxNumLoads = TLI->getMaxExpandSizeMemcmp(OptSize); + return Options; + } + +}; + +} // end namespace llvm + +#endif // LLVM_LIB_TARGET_SBF_SBFTARGETTRANSFORMINFO_H diff --git a/llvm/lib/Target/SBF/TargetInfo/CMakeLists.txt b/llvm/lib/Target/SBF/TargetInfo/CMakeLists.txt new file mode 100644 index 0000000000000..899f26fbd2f0a --- /dev/null +++ b/llvm/lib/Target/SBF/TargetInfo/CMakeLists.txt @@ -0,0 +1,10 @@ +add_llvm_component_library(LLVMSBFInfo + SBFTargetInfo.cpp + + LINK_COMPONENTS + MC + Support + + ADD_TO_COMPONENT + SBF + ) diff --git a/llvm/lib/Target/SBF/TargetInfo/SBFTargetInfo.cpp b/llvm/lib/Target/SBF/TargetInfo/SBFTargetInfo.cpp new file mode 100644 index 0000000000000..b3f34db9701f6 --- /dev/null +++ b/llvm/lib/Target/SBF/TargetInfo/SBFTargetInfo.cpp @@ -0,0 +1,58 @@ +//===-- SBFTargetInfo.cpp - SBF Target Implementation ---------------------===// +// +// 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 "TargetInfo/SBFTargetInfo.h" +#include "llvm/MC/TargetRegistry.h" + +using namespace llvm; + +Target &llvm::getTheSBFXTarget() { + static Target TheSBFTarget; + return TheSBFTarget; +} + +std::string llvm::cpuFromSubArch(const Triple &TT, const std::string &CPU) { + std::string CpuType; + switch (TT.getSubArch()) { + case Triple::SBFSubArch_v0: + CpuType = "generic"; + break; + case Triple::SBFSubArch_v1: + CpuType = "v1"; + break; + case Triple::SBFSubArch_v2: + CpuType = "v2"; + break; + case Triple::SBFSubArch_v3: + CpuType = "v3"; + break; + case Triple::SBFSubArch_v4: + CpuType = "v4"; + break; + default: + break; + } + + assert((CPU.empty() || CpuType.empty() || CPU == CpuType) && + "Subarch type must match CPU type"); + + if (!CpuType.empty()) { + return CpuType; + } + + return CPU; +} + +extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeSBFTargetInfo() { + TargetRegistry::RegisterTarget( + getTheSBFXTarget(), "sbf", "SBF new (little endian)", "SBF", + [](Triple::ArchType Aarch) { return Aarch == Triple::ArchType::sbf; }, + true); + RegisterTarget XX( + getTheSBFXTarget(), "sbf", "SBF new (little endian)", "SBF"); +} diff --git a/llvm/lib/Target/SBF/TargetInfo/SBFTargetInfo.h b/llvm/lib/Target/SBF/TargetInfo/SBFTargetInfo.h new file mode 100644 index 0000000000000..c095135ddb4e2 --- /dev/null +++ b/llvm/lib/Target/SBF/TargetInfo/SBFTargetInfo.h @@ -0,0 +1,21 @@ +//===-- SBFTargetInfo.h - SBF Target Implementation -------------*- 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/TargetParser/Triple.h" + +#ifndef LLVM_LIB_TARGET_SBF_TARGETINFO_SBFTARGETINFO_H +#define LLVM_LIB_TARGET_SBF_TARGETINFO_SBFTARGETINFO_H + +namespace llvm { + +class Target; + +Target &getTheSBFXTarget(); +std::string cpuFromSubArch(const Triple &TT, const std::string &CPU); +} // namespace llvm + +#endif // LLVM_LIB_TARGET_SBF_TARGETINFO_SBFTARGETINFO_H diff --git a/llvm/lib/TargetParser/Triple.cpp b/llvm/lib/TargetParser/Triple.cpp index e9e6f130f757c..89e14086e3ac1 100644 --- a/llvm/lib/TargetParser/Triple.cpp +++ b/llvm/lib/TargetParser/Triple.cpp @@ -84,6 +84,7 @@ StringRef Triple::getArchTypeName(ArchType Kind) { case x86_64: return "x86_64"; case xcore: return "xcore"; case xtensa: return "xtensa"; + case sbf: return "sbf"; } llvm_unreachable("Invalid ArchType!"); @@ -270,6 +271,7 @@ StringRef Triple::getVendorTypeName(VendorType Kind) { case PC: return "pc"; case SCEI: return "scei"; case SUSE: return "suse"; + case Solana: return "solana"; } llvm_unreachable("Invalid VendorType!"); @@ -319,6 +321,7 @@ StringRef Triple::getOSTypeName(OSType Kind) { case LiteOS: return "liteos"; case XROS: return "xros"; case Vulkan: return "vulkan"; + case SolanaOS: return "solana"; } llvm_unreachable("Invalid OSType"); @@ -414,6 +417,11 @@ static Triple::ArchType parseBPFArch(StringRef ArchName) { return Triple::bpfeb; } else if (ArchName == "bpf_le" || ArchName == "bpfel") { return Triple::bpfel; + } else if (ArchName == "sbf" || ArchName == "sbpf" || + ArchName == "sbpfv0" || ArchName == "sbpfv1" || + ArchName == "sbpfv2" || ArchName == "sbpfv3" || + ArchName == "sbpfv4") { + return Triple::sbf; } else { return Triple::UnknownArch; } @@ -449,6 +457,8 @@ Triple::ArchType Triple::getArchTypeForLLVMName(StringRef Name) { .Case("riscv32", riscv32) .Case("riscv64", riscv64) .Case("hexagon", hexagon) + .Case("sbf", BPFArch) + .Case("sbpf", BPFArch) .Case("sparc", sparc) .Case("sparcel", sparcel) .Case("sparcv9", sparcv9) @@ -640,7 +650,8 @@ static Triple::ArchType parseArch(StringRef ArchName) { if (ArchName.starts_with("arm") || ArchName.starts_with("thumb") || ArchName.starts_with("aarch64")) return parseARMArch(ArchName); - if (ArchName.starts_with("bpf")) + if (ArchName.starts_with("bpf") || ArchName.starts_with("sbf") || + ArchName.starts_with("sbpf")) return parseBPFArch(ArchName); } @@ -664,6 +675,7 @@ static Triple::VendorType parseVendor(StringRef VendorName) { .Case("suse", Triple::SUSE) .Case("oe", Triple::OpenEmbedded) .Case("intel", Triple::Intel) + .Case("solana", Triple::Solana) .Default(Triple::UnknownVendor); } @@ -711,6 +723,7 @@ static Triple::OSType parseOS(StringRef OSName) { .StartsWith("liteos", Triple::LiteOS) .StartsWith("serenity", Triple::Serenity) .StartsWith("vulkan", Triple::Vulkan) + .StartsWith("solana", Triple::SolanaOS) .Default(Triple::UnknownOS); } @@ -821,6 +834,16 @@ static Triple::SubArchType parseSubArch(StringRef SubArchName) { .EndsWith("v1.8", Triple::DXILSubArch_v1_8) .Default(Triple::NoSubArch); + if (SubArchName.starts_with("sbpf")) { + return StringSwitch(SubArchName) + .EndsWith("v0", Triple::SBFSubArch_v0) + .EndsWith("v1", Triple::SBFSubArch_v1) + .EndsWith("v2", Triple::SBFSubArch_v2) + .EndsWith("v3", Triple::SBFSubArch_v3) + .EndsWith("v4", Triple::SBFSubArch_v4) + .Default(Triple::NoSubArch); + } + StringRef ARMSubArch = ARM::getCanonicalArchName(SubArchName); // For now, this is the small part. Early return. @@ -973,6 +996,7 @@ static Triple::ObjectFormatType getDefaultFormat(const Triple &T) { case Triple::ve: case Triple::xcore: case Triple::xtensa: + case Triple::sbf: return Triple::ELF; case Triple::mipsel: @@ -1706,6 +1730,7 @@ unsigned Triple::getArchPointerBitWidth(llvm::Triple::ArchType Arch) { case llvm::Triple::ve: case llvm::Triple::wasm64: case llvm::Triple::x86_64: + case llvm::Triple::sbf: return 64; } llvm_unreachable("Invalid architecture value"); @@ -1754,6 +1779,7 @@ Triple Triple::get32BitArchVariant() const { case Triple::msp430: case Triple::systemz: case Triple::ve: + case Triple::sbf: T.setArch(UnknownArch); break; @@ -1867,6 +1893,7 @@ Triple Triple::get64BitArchVariant() const { case Triple::ve: case Triple::wasm64: case Triple::x86_64: + case Triple::sbf: // Already 64-bit. break; @@ -1927,6 +1954,7 @@ Triple Triple::getBigEndianArchVariant() const { case Triple::renderscript64: case Triple::riscv32: case Triple::riscv64: + case Triple::sbf: case Triple::shave: case Triple::spir64: case Triple::spir: @@ -1988,6 +2016,7 @@ Triple Triple::getLittleEndianArchVariant() const { case Triple::aarch64_be: T.setArch(Triple::aarch64); break; case Triple::bpfeb: T.setArch(Triple::bpfel); break; + case Triple::sbf: T.setArch(Triple::sbf); break; case Triple::mips64: T.setArch(Triple::mips64el, getSubArch()); break; @@ -2034,6 +2063,7 @@ bool Triple::isLittleEndian() const { case Triple::renderscript64: case Triple::riscv32: case Triple::riscv64: + case Triple::sbf: case Triple::shave: case Triple::sparcel: case Triple::spir64: diff --git a/llvm/test/CodeGen/SBF/32-bit-subreg-alu.ll b/llvm/test/CodeGen/SBF/32-bit-subreg-alu.ll new file mode 100644 index 0000000000000..6713375dbfa4d --- /dev/null +++ b/llvm/test/CodeGen/SBF/32-bit-subreg-alu.ll @@ -0,0 +1,329 @@ +; RUN: llc -O2 -march=sbf -mattr=+alu32 < %s | FileCheck --check-prefixes=CHECK,CHECK-V0 %s +; RUN: llc -O2 -march=sbf -mcpu=v3 < %s | FileCheck --check-prefixes=CHECK,CHECK-V3 %s +; +; int mov(int a) +; { +; return a; +; } +; +; int mov_ri(void) +; { +; return 0xff; +; } +; +; int add(int a, int b) +; { +; return a + b; +; } +; +; int add_i(int a) +; { +; return a + 0x7fffffff; +; } +; +; int sub(int a, int b) +; { +; return a - b; +; } +; +; int sub_i(int a) +; { +; return a - 0xffffffff; +; } +; +; int mul(int a, int b) +; { +; return a * b; +; } +; +; int mul_i(int a) +; { +; return a * 0xf; +; } +; +; unsigned div(unsigned a, unsigned b) +; { +; return a / b; +; } +; +; unsigned div_i(unsigned a) +; { +; return a / 0xf; +; } +; +; unsigned rem(unsigned a, unsigned b) +; { +; return a % b; +; } +; +; unsigned rem_i(unsigned a) +; { +; return a % 0xf; +; } +; +; int or(int a, int b) +; { +; return a | b; +; } +; +; int or_i(int a) +; { +; return a | 0xff; +; } +; +; int xor(int a, int b) +; { +; return a ^ b; +; } +; +; int xor_i(int a) +; { +; return a ^ 0xfff; +; } +; +; int and(int a, int b) +; { +; return a & b; +; } +; +; int and_i(int a) +; { +; return a & 0xffff; +; } +; +; int sll(int a, int b) +; { +; return a << b; +; } +; +; int sll_i(int a) +; { +; return a << 17; +; } +; +; unsigned srl(unsigned a, unsigned b) +; { +; return a >> b; +; } +; +; unsigned srl_i(unsigned a, unsigned b) +; { +; return a >> 31; +; } +; +; int sra(int a, int b) +; { +; return a >> b; +; } +; +; int sra_i(int a, int b) +; { +; return a >> 7; +; } +; +; int neg(int a) +; { +; return -a; +; } + +; Function Attrs: norecurse nounwind readnone +define dso_local i32 @mov(i32 returned %a) local_unnamed_addr #0 { +entry: + ret i32 %a +; CHECK-V0: mov32 w{{[0-9]+}}, w{{[0-9]+}} +; CHECK-V3: mov64 w{{[0-9]+}}, w{{[0-9]+}} +} + +; Function Attrs: norecurse nounwind readnone +define dso_local i32 @mov_ri() local_unnamed_addr #0 { +entry: + ret i32 255 +; CHECK: mov32 w{{[0-9]+}}, 255 +} + +; Function Attrs: norecurse nounwind readnone +define dso_local i32 @add(i32 %a, i32 %b) local_unnamed_addr #0 { +entry: + %add = add nsw i32 %b, %a +; CHECK: add32 w{{[0-9]+}}, w{{[0-9]+}} + ret i32 %add +} + +; Function Attrs: norecurse nounwind readnone +define dso_local i32 @add_i(i32 %a) local_unnamed_addr #0 { +entry: + %add = add nsw i32 %a, 2147483647 +; CHECK: add32 w{{[0-9]+}}, 2147483647 + ret i32 %add +} + +; Function Attrs: norecurse nounwind readnone +define dso_local i32 @sub(i32 %a, i32 %b) local_unnamed_addr #0 { +entry: + %sub = sub nsw i32 %a, %b +; CHECK: sub32 w{{[0-9]+}}, w{{[0-9]+}} + ret i32 %sub +} + +; Function Attrs: norecurse nounwind readnone +define dso_local i32 @sub_i(i32 %a) local_unnamed_addr #0 { +entry: + %sub = add i32 %a, 1 +; CHECK: add32 w{{[0-9]+}}, 1 + ret i32 %sub +} + +; Function Attrs: norecurse nounwind readnone +define dso_local i32 @mul(i32 %a, i32 %b) local_unnamed_addr #0 { +entry: + %mul = mul nsw i32 %b, %a +; CHECK: mul32 w{{[0-9]+}}, w{{[0-9]+}} + ret i32 %mul +} + +; Function Attrs: norecurse nounwind readnone +define dso_local i32 @mul_i(i32 %a) local_unnamed_addr #0 { +entry: + %mul = mul nsw i32 %a, 15 +; CHECK: mul32 w{{[0-9]+}}, 15 + ret i32 %mul +} + +; Function Attrs: norecurse nounwind readnone +define dso_local i32 @div(i32 %a, i32 %b) local_unnamed_addr #0 { +entry: + %div = udiv i32 %a, %b +; CHECK: div32 w{{[0-9]+}}, w{{[0-9]+}} + ret i32 %div +} + +; Function Attrs: norecurse nounwind readnone +define dso_local i32 @div_i(i32 %a) local_unnamed_addr #0 { +entry: + %div = udiv i32 %a, 15 +; CHECK: div32 w{{[0-9]+}}, 15 + ret i32 %div +} + +; Function Attrs: norecurse nounwind readnone +define dso_local i32 @rem(i32 %a, i32 %b) local_unnamed_addr #0 { +entry: + %rem = urem i32 %a, %b +; CHECK-V0: mod32 w{{[0-9]+}}, w{{[0-9]+}} +; CHECK-V3: urem32 w{{[0-9]+}}, w{{[0-9]+}} + ret i32 %rem +} + +; Function Attrs: norecurse nounwind readnone +define dso_local i32 @rem_i(i32 %a) local_unnamed_addr #0 { +entry: + %rem = urem i32 %a, 15 +; CHECK-V0: mod32 w{{[0-9]+}}, 15 +; CHECK-V3: urem32 w{{[0-9]+}}, 15 + ret i32 %rem +} + +; Function Attrs: norecurse nounwind readnone +define dso_local i32 @or(i32 %a, i32 %b) local_unnamed_addr #0 { +entry: + %or = or i32 %b, %a +; CHECK: or32 w{{[0-9]+}}, w{{[0-9]+}} + ret i32 %or +} + +; Function Attrs: norecurse nounwind readnone +define dso_local i32 @or_i(i32 %a) local_unnamed_addr #0 { +entry: + %or = or i32 %a, 255 +; CHECK: or32 w{{[0-9]+}}, 255 + ret i32 %or +} + +; Function Attrs: norecurse nounwind readnone +define dso_local i32 @xor(i32 %a, i32 %b) local_unnamed_addr #0 { +entry: + %xor = xor i32 %b, %a +; CHECK: xor32 w{{[0-9]+}}, w{{[0-9]+}} + ret i32 %xor +} + +; Function Attrs: norecurse nounwind readnone +define dso_local i32 @xor_i(i32 %a) local_unnamed_addr #0 { +entry: + %xor = xor i32 %a, 4095 +; CHECK: xor32 w{{[0-9]+}}, 4095 + ret i32 %xor +} + +; Function Attrs: norecurse nounwind readnone +define dso_local i32 @and(i32 %a, i32 %b) local_unnamed_addr #0 { +entry: + %and = and i32 %b, %a +; CHECK: and32 w{{[0-9]+}}, w{{[0-9]+}} + ret i32 %and +} + +; Function Attrs: norecurse nounwind readnone +define dso_local i32 @and_i(i32 %a) local_unnamed_addr #0 { +entry: + %and = and i32 %a, 65535 +; CHECK: and32 w{{[0-9]+}}, 65535 + ret i32 %and +} + +; Function Attrs: norecurse nounwind readnone +define dso_local i32 @sll(i32 %a, i32 %b) local_unnamed_addr #0 { +entry: + %shl = shl i32 %a, %b +; CHECK: lsh32 w{{[0-9]+}}, w{{[0-9]+}} + ret i32 %shl +} + +; Function Attrs: norecurse nounwind readnone +define dso_local i32 @sll_i(i32 %a) local_unnamed_addr #0 { +entry: + %shl = shl i32 %a, 17 +; CHECK: lsh32 w{{[0-9]+}}, 17 + ret i32 %shl +} + +; Function Attrs: norecurse nounwind readnone +define dso_local i32 @srl(i32 %a, i32 %b) local_unnamed_addr #0 { +entry: + %shr = lshr i32 %a, %b +; CHECK: rsh32 w{{[0-9]+}}, w{{[0-9]+}} + ret i32 %shr +} + +; Function Attrs: norecurse nounwind readnone +define dso_local i32 @srl_i(i32 %a, i32 %b) local_unnamed_addr #0 { +entry: + %shr = lshr i32 %a, 31 +; CHECK: rsh32 w{{[0-9]+}}, 31 + ret i32 %shr +} + +; Function Attrs: norecurse nounwind readnone +define dso_local i32 @sra(i32 %a, i32 %b) local_unnamed_addr #0 { +entry: + %shr = ashr i32 %a, %b +; CHECK: arsh32 w{{[0-9]+}}, w{{[0-9]+}} + ret i32 %shr +} + +; Function Attrs: norecurse nounwind readnone +define dso_local i32 @sra_i(i32 %a, i32 %b) local_unnamed_addr #0 { +entry: + %shr = ashr i32 %a, 7 +; CHECK: arsh32 w{{[0-9]+}}, 7 + ret i32 %shr +} + +; Function Attrs: norecurse nounwind readnone +define dso_local i32 @neg(i32 %a) local_unnamed_addr #0 { +entry: + %sub = sub nsw i32 0, %a +; CHECK-V0: mov32 w{{[0-9]+}}, w{{[0-9]+}} +; CHECK-V3: mov64 w{{[0-9]+}}, w{{[0-9]+}} + ret i32 %sub +} diff --git a/llvm/test/CodeGen/SBF/32-bit-subreg-cond-select.ll b/llvm/test/CodeGen/SBF/32-bit-subreg-cond-select.ll new file mode 100644 index 0000000000000..7cf5b774631dd --- /dev/null +++ b/llvm/test/CodeGen/SBF/32-bit-subreg-cond-select.ll @@ -0,0 +1,125 @@ +; RUN: llc -O2 -march=sbf -mattr=+alu32,+explicit-sext -verify-machineinstrs < %s | FileCheck %s +; +; unsigned int select_cc_32 (unsigned a, unsigned b, int c, int d) +; { +; if (a > b) +; return c; +; else +; return d; +; } +; +; long long select_cc_32_64 (unsigned a, unsigned b, long long c, long long d) +; { +; if (a > b) +; return c; +; else +; return d; +; } +; +; int select_cc_64_32 (long long a, long long b, int c, int d) +; { +; if (a > b) +; return c; +; else +; return d; +; } +; +; int selecti_cc_32 (unsigned a, int c, int d) +; { +; if (a > 10) +; return c; +; else +; return d; +; } +; +; long long selecti_cc_32_64 (unsigned a, long long c, long long d) +; { +; if (a > 11) +; return c; +; else +; return d; +; } +; +; int selecti_cc_64_32 (long long a, int c, int d) +; { +; if (a > 12) +; return c; +; else +; return d; +; } + +; Function Attrs: norecurse nounwind readnone +define dso_local i32 @select_cc_32(i32 %a, i32 %b, i32 %c, i32 %d) local_unnamed_addr #0 { +entry: + %cmp = icmp ugt i32 %a, %b + %c.d = select i1 %cmp, i32 %c, i32 %d + ret i32 %c.d +} +; CHECK-LABEL: select_cc_32 +; CHECK-NOT: mov64 r{{[0-9]+}}, w{{[0-9]+}} +; CHECK-NOT: mov64 r{{[0-9]+}}, w{{[0-9]+}} +; CHECK: jgt r{{[0-9]+}}, r{{[0-9]+}} +; CHECK-NOT: lsh64 r{{[0-9]+}}, 32 +; CHECK-NOT: rsh64 r{{[0-9]+}}, 32 + +; Function Attrs: norecurse nounwind readnone +define dso_local i64 @select_cc_32_64(i32 %a, i32 %b, i64 %c, i64 %d) local_unnamed_addr #0 { +entry: + %cmp = icmp sgt i32 %a, %b + %c.d = select i1 %cmp, i64 %c, i64 %d + ret i64 %c.d +} +; CHECK-LABEL: select_cc_32_64 +; CHECK: mov32 r{{[0-9]+}}, w{{[0-9]+}} +; CHECK: mov32 r{{[0-9]+}}, w{{[0-9]+}} +; CHECK: jsgt r{{[0-9]+}}, r{{[0-9]+}} +; CHECK-NOT: lsh64 r{{[0-9]+}}, 32 +; CHECK-NOT: rsh64 r{{[0-9]+}}, 32 + +; Function Attrs: norecurse nounwind readnone +define dso_local i32 @select_cc_64_32(i64 %a, i64 %b, i32 %c, i32 %d) local_unnamed_addr #0 { +entry: + %cmp = icmp sgt i64 %a, %b + %c.d = select i1 %cmp, i32 %c, i32 %d + ret i32 %c.d +} +; CHECK-LABEL: select_cc_64_32 +; CHECK: jsgt r{{[0-9]+}}, r{{[0-9]+}} +; CHECK-NOT: lsh64 r{{[0-9]+}}, 32 + +; Function Attrs: norecurse nounwind readnone +define dso_local i32 @selecti_cc_32(i32 %a, i32 %c, i32 %d) local_unnamed_addr #0 { +entry: + %cmp = icmp ugt i32 %a, 10 + %c.d = select i1 %cmp, i32 %c, i32 %d + ret i32 %c.d +} +; CHECK-LABEL: selecti_cc_32 +; CHECK: mov32 r{{[0-9]+}}, w{{[0-9]+}} +; CHECK: jgt r{{[0-9]+}}, 10 +; CHECK-NOT: lsh64 r{{[0-9]+}}, 32 +; CHECK-NOT: rsh64 r{{[0-9]+}}, 32 + +; Function Attrs: norecurse nounwind readnone +define dso_local i64 @selecti_cc_32_64(i32 %a, i64 %c, i64 %d) local_unnamed_addr #0 { +entry: + %cmp = icmp sgt i32 %a, 11 + %c.d = select i1 %cmp, i64 %c, i64 %d + ret i64 %c.d +} +; CHECK-LABEL: selecti_cc_32_64 +; CHECK: mov32 r{{[0-9]+}}, w{{[0-9]+}} +; CHECK: jsgt r{{[0-9]+}}, 11, +; CHECK-NOT: lsh64 r{{[0-9]+}}, 32 +; CHECK-NOT: rsh64 r{{[0-9]+}}, 32 + +; Function Attrs: norecurse nounwind readnone +define dso_local i32 @selecti_cc_64_32(i64 %a, i32 %c, i32 %d) local_unnamed_addr #0 { +entry: + %cmp = icmp sgt i64 %a, 12 + %c.d = select i1 %cmp, i32 %c, i32 %d + ret i32 %c.d +} +; CHECK-LABEL: selecti_cc_64_32 +; CHECK: jsgt r{{[0-9]+}}, 12 +; CHECK-NOT: lsh64 r{{[0-9]+}}, 32 diff --git a/llvm/test/CodeGen/SBF/32-bit-subreg-load-store.ll b/llvm/test/CodeGen/SBF/32-bit-subreg-load-store.ll new file mode 100644 index 0000000000000..c79daf1fd995d --- /dev/null +++ b/llvm/test/CodeGen/SBF/32-bit-subreg-load-store.ll @@ -0,0 +1,109 @@ +; RUN: llc -O2 -march=sbf -mattr=+alu32 < %s | FileCheck %s +; RUN: llc -O2 -march=sbf -mattr=+alu32,+mem-encoding < %s | FileCheck %s + +; +; unsigned char loadu8(unsigned char *p) +; { +; return *p; +; } +; +; unsigned short loadu16(unsigned short *p) +; { +; return *p; +; } +; +; unsigned loadu32(unsigned *p) +; { +; return *p; +; } +; +; unsigned long long loadu64(unsigned long long *p) +; { +; return *p; +; } +; +; void storeu8(unsigned char *p, unsigned long long v) +; { +; *p = (unsigned char)v; +; } +; +; void storeu16(unsigned short *p, unsigned long long v) +; { +; *p = (unsigned short)v; +; } +; +; void storeu32(unsigned *p, unsigned long long v) +; { +; *p = (unsigned)v; +; } +; +; void storeu64(unsigned long long *p, unsigned long long v) +; { +; *p = v; +; } +; Function Attrs: norecurse nounwind readonly +define dso_local zeroext i8 @loadu8(i8* nocapture readonly %p) local_unnamed_addr #0 { +entry: + %0 = load i8, i8* %p, align 1 +; CHECK: ldxb w{{[0-9]+}}, [r{{[0-9]+}} + 0] + ret i8 %0 +} + +; Function Attrs: norecurse nounwind readonly +define dso_local zeroext i16 @loadu16(i16* nocapture readonly %p) local_unnamed_addr #0 { +entry: + %0 = load i16, i16* %p, align 2 +; CHECK: ldxh w{{[0-9]+}}, [r{{[0-9]+}} + 0] + ret i16 %0 +} + +; Function Attrs: norecurse nounwind readonly +define dso_local i32 @loadu32(i32* nocapture readonly %p) local_unnamed_addr #0 { +entry: + %0 = load i32, i32* %p, align 4 +; CHECK: ldxw w{{[0-9]+}}, [r{{[0-9]+}} + 0] + ret i32 %0 +} + +; Function Attrs: norecurse nounwind readonly +define dso_local i64 @loadu64(i64* nocapture readonly %p) local_unnamed_addr #0 { +entry: + %0 = load i64, i64* %p, align 8 +; CHECK: ldxdw r{{[0-9]+}}, [r{{[0-9]+}} + 0] + ret i64 %0 +} + +; Function Attrs: norecurse nounwind +define dso_local void @storeu8(i8* nocapture %p, i64 %v) local_unnamed_addr #1 { +entry: + %conv = trunc i64 %v to i8 + store i8 %conv, i8* %p, align 1 +; CHECK: stxb [r{{[0-9]+}} + 0], w{{[0-9]+}} + ret void +} + +; Function Attrs: norecurse nounwind +define dso_local void @storeu16(i16* nocapture %p, i64 %v) local_unnamed_addr #1 { +entry: + %conv = trunc i64 %v to i16 + store i16 %conv, i16* %p, align 2 +; CHECK: stxh [r{{[0-9]+}} + 0], w{{[0-9]+}} + ret void +} + +; Function Attrs: norecurse nounwind +define dso_local void @storeu32(i32* nocapture %p, i64 %v) local_unnamed_addr #1 { +entry: + %conv = trunc i64 %v to i32 + store i32 %conv, i32* %p, align 4 +; CHECK: stxw [r{{[0-9]+}} + 0], w{{[0-9]+}} + ret void +} + +; Function Attrs: norecurse nounwind +define dso_local void @storeu64(i64* nocapture %p, i64 %v) local_unnamed_addr #1 { +entry: + store i64 %v, i64* %p, align 8 +; CHECK: stxdw [r{{[0-9]+}} + 0], r{{[0-9]+}} + ret void +} diff --git a/llvm/test/CodeGen/SBF/32-bit-subreg-peephole-phi-1.ll b/llvm/test/CodeGen/SBF/32-bit-subreg-peephole-phi-1.ll new file mode 100644 index 0000000000000..701d30ccdeca0 --- /dev/null +++ b/llvm/test/CodeGen/SBF/32-bit-subreg-peephole-phi-1.ll @@ -0,0 +1,34 @@ +; RUN: llc -O2 -march=sbf -mcpu=v2 -mattr=+alu32 < %s | FileCheck %s +; +; For the below test case, 'b' in 'ret == b' needs SLL/SLR. +; 'ret' in 'ret == b' does not need SLL/SLR as all 'ret' values +; are assigned through 'w = ' alu32 operations. +; +; extern int helper(int); +; int test(int a, int b, int c, int d) { +; int ret; +; if (a < b) +; ret = (c < d) ? -1 : 0; +; else +; ret = (c < a) ? 1 : 2; +; return helper(ret == b); +; } + +define dso_local i32 @test(i32 %a, i32 %b, i32 %c, i32 %d) local_unnamed_addr { +entry: + %cmp = icmp slt i32 %a, %b + %cmp1 = icmp slt i32 %c, %d + %cond = sext i1 %cmp1 to i32 + %cmp2 = icmp slt i32 %c, %a + %cond3 = select i1 %cmp2, i32 1, i32 2 + %ret.0 = select i1 %cmp, i32 %cond, i32 %cond3 + %cmp4 = icmp eq i32 %ret.0, %b + %conv = zext i1 %cmp4 to i32 + %call = tail call i32 @helper(i32 %conv) + ret i32 %call +} +; CHECK: mov32 r{{[0-9]+}}, w{{[0-9]+}} +; CHECK-NOT: rsh32 r{{[0-9]+}}, 32 +; CHECK: jeq r{{[0-9]+}}, r{{[0-9]+}}, + +declare dso_local i32 @helper(i32) local_unnamed_addr diff --git a/llvm/test/CodeGen/SBF/32-bit-subreg-peephole-phi-2.ll b/llvm/test/CodeGen/SBF/32-bit-subreg-peephole-phi-2.ll new file mode 100644 index 0000000000000..2fef555d3f418 --- /dev/null +++ b/llvm/test/CodeGen/SBF/32-bit-subreg-peephole-phi-2.ll @@ -0,0 +1,34 @@ +; RUN: llc -O2 -march=sbf -mcpu=v2 -mattr=+alu32 < %s | FileCheck %s +; +; For the below test case, both 'ret' and 'b' at 'ret == b' +; need SLL/SLR. For 'ret', 'ret = a' may receive the value +; from argument with high 32-bit invalid data. +; +; extern int helper(int); +; int test(int a, int b, int c, int d) { +; int ret; +; if (a < b) +; ret = (c < d) ? a : 0; +; else +; ret = (c < a) ? 1 : 2; +; return helper(ret == b); +; } + +define dso_local i32 @test(i32 %a, i32 %b, i32 %c, i32 %d) local_unnamed_addr { +entry: + %cmp = icmp slt i32 %a, %b + %cmp1 = icmp slt i32 %c, %d + %cond = select i1 %cmp1, i32 %a, i32 0 + %cmp2 = icmp slt i32 %c, %a + %cond3 = select i1 %cmp2, i32 1, i32 2 + %ret.0 = select i1 %cmp, i32 %cond, i32 %cond3 + %cmp4 = icmp eq i32 %ret.0, %b + %conv = zext i1 %cmp4 to i32 + %call = tail call i32 @helper(i32 %conv) + ret i32 %call +} +; CHECK: mov32 r{{[0-9]+}}, w{{[0-9]+}} +; CHECK: mov32 r{{[0-9]+}}, w{{[0-9]+}} +; CHECK: jeq r{{[0-9]+}}, r{{[0-9]+}}, + +declare dso_local i32 @helper(i32) local_unnamed_addr diff --git a/llvm/test/CodeGen/SBF/32-bit-subreg-peephole-phi-3.ll b/llvm/test/CodeGen/SBF/32-bit-subreg-peephole-phi-3.ll new file mode 100644 index 0000000000000..20d71af957fd1 --- /dev/null +++ b/llvm/test/CodeGen/SBF/32-bit-subreg-peephole-phi-3.ll @@ -0,0 +1,53 @@ +; RUN: llc -O2 -march=sbf -mcpu=v2 -mattr=+alu32 < %s | FileCheck %s +; +; For the below example, two phi node in the loop may depend on +; each other. So implementation must handle recursion properly. +; +; int test(unsigned long a, unsigned long b, unsigned long c) { +; int val = 0; +; +; #pragma clang loop unroll(disable) +; for (long i = 0; i < 100; i++) { +; if (a > b) +; val = 1; +; a += b; +; if (b > c) +; val = 1; +; b += c; +; } +; +; return val == 0 ? 1 : 0; +; } + + +define dso_local i32 @test(i64 %a, i64 %b, i64 %c) local_unnamed_addr { +entry: + br label %for.body + +for.cond.cleanup: ; preds = %for.body + %cmp6 = icmp eq i32 %val.2, 0 + %cond = zext i1 %cmp6 to i32 + ret i32 %cond + +for.body: ; preds = %for.body, %entry + %i.018 = phi i64 [ 0, %entry ], [ %inc, %for.body ] + %val.017 = phi i32 [ 0, %entry ], [ %val.2, %for.body ] + %a.addr.016 = phi i64 [ %a, %entry ], [ %add, %for.body ] + %b.addr.015 = phi i64 [ %b, %entry ], [ %add5, %for.body ] + %cmp1 = icmp ugt i64 %a.addr.016, %b.addr.015 + %add = add i64 %a.addr.016, %b.addr.015 + %cmp2 = icmp ugt i64 %b.addr.015, %c + %0 = or i1 %cmp2, %cmp1 + %val.2 = select i1 %0, i32 1, i32 %val.017 + %add5 = add i64 %b.addr.015, %c + %inc = add nuw nsw i64 %i.018, 1 + %exitcond = icmp eq i64 %inc, 100 + br i1 %exitcond, label %for.cond.cleanup, label %for.body, !llvm.loop !2 +} +; CHECK: mov32 [[VAL:r[0-9]+]], w{{[0-9]+}} +; CHECK-NOT: lsh32 [[VAL:r[0-9]+]], 32 +; CHECK-NOT: rsh32 [[VAL]], 32 +; CHECK: jeq [[VAL]], 0, + +!2 = distinct !{!2, !3} +!3 = !{!"llvm.loop.unroll.disable"} diff --git a/llvm/test/CodeGen/SBF/32-bit-subreg-peephole.ll b/llvm/test/CodeGen/SBF/32-bit-subreg-peephole.ll new file mode 100644 index 0000000000000..325374059c60a --- /dev/null +++ b/llvm/test/CodeGen/SBF/32-bit-subreg-peephole.ll @@ -0,0 +1,127 @@ +; RUN: llc -O2 -march=sbf -mcpu=v2 < %s | FileCheck %s +; +; long long select_u(unsigned a, unsigned b, long long c, long long d) +; { +; if (a > b) +; return c; +; else +; return d; +; } +; +; long long select_u_2(unsigned a, unsigned long long b, long long c, long long d) +; { +; if (a > b) +; return c; +; else +; return d; +; } +; +; long long select_s(signed a, signed b, long long c, long long d) +; { +; if (a > b) +; return c; +; else +; return d; +; } +; +; long long bar (); +; +; int foo (int b, int c) +; { +; unsigned int i32_val = (unsigned int) bar(); +; +; if (i32_val < 10) +; return b; +; else +; return c; +; } +; +; int *inc_p (int *p, unsigned a) +; { +; return p + a; +; } + +; Function Attrs: norecurse nounwind readnone +define dso_local i64 @select_u(i32 %a, i32 %b, i64 %c, i64 %d) local_unnamed_addr #0 { +; CHECK-LABEL: select_u: +entry: + %cmp = icmp ugt i32 %a, %b + %c.d = select i1 %cmp, i64 %c, i64 %d +; CHECK: mov64 r{{[0-9]+}}, r{{[0-9]+}} +; CHECK-NOT: lsh32 r{{[0-9]+}}, 32 +; CHECK-NOT: rsh32 r{{[0-9]+}}, 32 +; CHECK: {{jlt|jgt}} r{{[0-9]+}}, r{{[0-9]+}}, + ret i64 %c.d +} + +; Function Attrs: norecurse nounwind readnone +define dso_local i64 @select_u_2(i32 %a, i64 %b, i64 %c, i64 %d) local_unnamed_addr #0 { +; CHECK-LABEL: select_u_2: +entry: + %conv = zext i32 %a to i64 +; CHECK: mov64 r{{[0-9]+}}, r{{[0-9]+}} +; CHECK-NOT: lsh32 r{{[0-9]+}}, 32 +; CHECK-NOT: rsh32 r{{[0-9]+}}, 32 + %cmp = icmp ugt i64 %conv, %b + %c.d = select i1 %cmp, i64 %c, i64 %d + ret i64 %c.d +} + +; Function Attrs: norecurse nounwind readnone +define dso_local i64 @select_s(i32 %a, i32 %b, i64 %c, i64 %d) local_unnamed_addr #0 { +; CHECK-LABEL: select_s: +entry: + %cmp = icmp sgt i32 %a, %b + %c.d = select i1 %cmp, i64 %c, i64 %d +; CHECK: mov32 r{{[0-9]+}}, w{{[0-9]+}} +; CHECK-NEXT: mov32 r{{[0-9]+}}, w{{[0-9]+}} +; CHECK: {{jslt|jsgt}} r{{[0-9]+}}, r{{[0-9]+}}, + ret i64 %c.d +} + +; Function Attrs: nounwind +define dso_local i32 @foo(i32 %b, i32 %c) local_unnamed_addr #0 { +; CHECK-LABEL: foo: +entry: + %call = tail call i64 bitcast (i64 (...)* @bar to i64 ()*)() #2 + %conv = trunc i64 %call to i32 + %cmp = icmp ult i32 %conv, 10 +; %call comes from function call returning i64 so the high bits will need +; to be cleared. +; CHECK: and32 w{{[0-9]+}}, -1 +; CHECK-NOT: lsh32 r{{[0-9]+}}, 32 +; CHECK-NOT: rsh32 r{{[0-9]+}}, 32 +; CHECK: mov32 r{{[0-9]+}}, w{{[0-9]+}} + %b.c = select i1 %cmp, i32 %b, i32 %c +; CHECK: {{jlt|jgt}} r{{[0-9]+}}, 10, + ret i32 %b.c +} + +declare dso_local i64 @bar(...) local_unnamed_addr #1 + +; Function Attrs: norecurse nounwind readnone +define dso_local i32* @inc_p(i32* readnone %p, i32 %a) local_unnamed_addr #0 { +; CHECK-LABEL: inc_p: +entry: + %idx.ext = zext i32 %a to i64 +; CHECK: mov64 r{{[0-9]+}}, r{{[0-9]+}} +; CHECK-NOT: lsh32 r{{[0-9]+}}, 32 +; CHECK-NOT: rsh32 r{{[0-9]+}}, 32 + %add.ptr = getelementptr inbounds i32, i32* %p, i64 %idx.ext + ret i32* %add.ptr +} + +define dso_local i32 @test() local_unnamed_addr { +; CHECK-LABEL: test: +entry: + %call = tail call i32 bitcast (i32 (...)* @helper to i32 ()*)() + %cmp = icmp sgt i32 %call, 6 +; The shifts can't be optimized out because %call comes from function call +; return i32 so the high bits might be invalid. +; CHECK: mov64 w{{[0-9]+}}, w{{[0-9]+}} +; CHECK: mov32 r{{[0-9]+}}, w{{[0-9]+}} + %cond = zext i1 %cmp to i32 +; CHECK: {{jslt|jsgt}} r{{[0-9]+}}, {{[0-9]+}}, + ret i32 %cond +} +declare dso_local i32 @helper(...) local_unnamed_addr diff --git a/llvm/test/CodeGen/SBF/32-bit-subreg-zext.ll b/llvm/test/CodeGen/SBF/32-bit-subreg-zext.ll new file mode 100644 index 0000000000000..d6f2f9896aba0 --- /dev/null +++ b/llvm/test/CodeGen/SBF/32-bit-subreg-zext.ll @@ -0,0 +1,21 @@ +; RUN: llc -O2 -march=sbf -mattr=+alu32 < %s | FileCheck %s +; RUN: llc -O2 -march=sbf -mcpu=v3 < %s | FileCheck %s +; RUN: llc -O2 -march=sbf -mattr=+alu32 < %s | FileCheck %s +; RUN: llc -O2 -march=sbf -mcpu=v3 < %s | FileCheck %s +; +; long zext(unsigned int a) +; { +; long b = a; +; return b; +; } + +; Function Attrs: norecurse nounwind +define dso_local i64 @zext(i32 %a) local_unnamed_addr #0 { +entry: + %conv = zext i32 %a to i64 + ; CHECK-NOT: r[[#]] <<= 32 + ; CHECK-NOT: r[[#]] >>= 32 + ret i64 %conv +} + +attributes #0 = { norecurse nounwind } diff --git a/llvm/test/CodeGen/SBF/BTF/align.ll b/llvm/test/CodeGen/SBF/BTF/align.ll new file mode 100644 index 0000000000000..dda9223d1dcb6 --- /dev/null +++ b/llvm/test/CodeGen/SBF/BTF/align.ll @@ -0,0 +1,34 @@ +; RUN: llc -sbf-enable-btf-emission -march=sbf -filetype=obj < %s | llvm-readelf -S - | FileCheck %s +; Source: +; int foo() { return 0; } +; Compilation flags: +; clang -target bpf -O2 -g -S -emit-llvm t.c + +; Function Attrs: mustprogress nofree norecurse nosync nounwind readnone willreturn +define dso_local i32 @foo() local_unnamed_addr #0 !dbg !7 { +entry: + ret i32 0, !dbg !12 +} +; CHECK: Name Type Address Off Size ES Flg Lk Inf Al +; CHECK: .BTF PROGBITS 0000000000000000 {{[0-9a-f]+}} {{[0-9a-f]+}} 00 0 0 4 +; CHECK: .BTF.ext PROGBITS 0000000000000000 {{[0-9a-f]+}} {{[0-9a-f]+}} 00 0 0 4 + +attributes #0 = { mustprogress nofree norecurse nosync nounwind readnone willreturn "frame-pointer"="all" "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" } + +!llvm.dbg.cu = !{!0} +!llvm.module.flags = !{!2, !3, !4, !5} +!llvm.ident = !{!6} + +!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 14.0.0 (https://github.com/llvm/llvm-project.git b1ab2a57b83e4b7224c38b534532500cc90e5b9a)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, splitDebugInlining: false, nameTableKind: None) +!1 = !DIFile(filename: "t.c", directory: "/tmp/home/yhs/work/tests/llvm/align") +!2 = !{i32 7, !"Dwarf Version", i32 4} +!3 = !{i32 2, !"Debug Info Version", i32 3} +!4 = !{i32 1, !"wchar_size", i32 4} +!5 = !{i32 7, !"frame-pointer", i32 2} +!6 = !{!"clang version 14.0.0 (https://github.com/llvm/llvm-project.git b1ab2a57b83e4b7224c38b534532500cc90e5b9a)"} +!7 = distinct !DISubprogram(name: "foo", scope: !1, file: !1, line: 1, type: !8, scopeLine: 1, flags: DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !11) +!8 = !DISubroutineType(types: !9) +!9 = !{!10} +!10 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +!11 = !{} +!12 = !DILocation(line: 1, column: 13, scope: !7) diff --git a/llvm/test/CodeGen/SBF/BTF/array-1d-char.ll b/llvm/test/CodeGen/SBF/BTF/array-1d-char.ll new file mode 100644 index 0000000000000..65c2b0a540a2f --- /dev/null +++ b/llvm/test/CodeGen/SBF/BTF/array-1d-char.ll @@ -0,0 +1,56 @@ +; RUN: llc -sbf-enable-btf-emission -march=sbf -filetype=asm -o - %s | FileCheck -check-prefixes=CHECK %s + +; Source code: +; char a[10]; +; Compilation flag: +; clang -target bpf -O2 -g -S -emit-llvm t.c + +@a = common dso_local local_unnamed_addr global [10 x i8] zeroinitializer, align 1, !dbg !0 + +!llvm.dbg.cu = !{!2} +!llvm.module.flags = !{!10, !11, !12} +!llvm.ident = !{!13} + +; CHECK: .section .BTF,"",@progbits +; CHECK-NEXT: .short 60319 # 0xeb9f +; CHECK-NEXT: .byte 1 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .long 24 +; CHECK-NEXT: .long 0 +; CHECK-NEXT: .long 56 +; CHECK-NEXT: .long 56 +; CHECK-NEXT: .long 26 +; CHECK-NEXT: .long 1 # BTF_KIND_INT(id = 1) +; CHECK-NEXT: .long 16777216 # 0x1000000 +; CHECK-NEXT: .long 1 +; CHECK-NEXT: .long 16777224 # 0x1000008 +; CHECK-NEXT: .long 0 # BTF_KIND_ARRAY(id = 2) +; CHECK-NEXT: .long 50331648 # 0x3000000 +; CHECK-NEXT: .long 0 +; CHECK-NEXT: .long 1 +; CHECK-NEXT: .long 3 +; CHECK-NEXT: .long 10 +; CHECK-NEXT: .long 6 # BTF_KIND_INT(id = 3) +; CHECK-NEXT: .long 16777216 # 0x1000000 +; CHECK-NEXT: .long 4 +; CHECK-NEXT: .long 32 # 0x20 +; CHECK-NEXT: .byte 0 # string offset=0 +; CHECK-NEXT: .ascii "char" # string offset=1 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii "__ARRAY_SIZE_TYPE__" # string offset=6 +; CHECK-NEXT: .byte 0 + +!0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression()) +!1 = distinct !DIGlobalVariable(name: "a", scope: !2, file: !3, line: 1, type: !6, isLocal: false, isDefinition: true) +!2 = distinct !DICompileUnit(language: DW_LANG_C99, file: !3, producer: "clang version 8.0.0 (trunk 345296) (llvm/trunk 345297)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !4, globals: !5, nameTableKind: None) +!3 = !DIFile(filename: "t.c", directory: "/home/yhs/tmp") +!4 = !{} +!5 = !{!0} +!6 = !DICompositeType(tag: DW_TAG_array_type, baseType: !7, size: 80, elements: !8) +!7 = !DIBasicType(name: "char", size: 8, encoding: DW_ATE_signed_char) +!8 = !{!9} +!9 = !DISubrange(count: 10) +!10 = !{i32 2, !"Dwarf Version", i32 4} +!11 = !{i32 2, !"Debug Info Version", i32 3} +!12 = !{i32 1, !"wchar_size", i32 4} +!13 = !{!"clang version 8.0.0 (trunk 345296) (llvm/trunk 345297)"} diff --git a/llvm/test/CodeGen/SBF/BTF/array-1d-int.ll b/llvm/test/CodeGen/SBF/BTF/array-1d-int.ll new file mode 100644 index 0000000000000..779aa23fb7e30 --- /dev/null +++ b/llvm/test/CodeGen/SBF/BTF/array-1d-int.ll @@ -0,0 +1,56 @@ +; RUN: llc -sbf-enable-btf-emission -march=sbf -filetype=asm -o - %s | FileCheck -check-prefixes=CHECK %s + +; Source code: +; int a[10]; +; Compilation flag: +; clang -target bpf -O2 -g -S -emit-llvm t.c + +@a = common dso_local local_unnamed_addr global [10 x i32] zeroinitializer, align 4, !dbg !0 + +!llvm.dbg.cu = !{!2} +!llvm.module.flags = !{!10, !11, !12} +!llvm.ident = !{!13} + +; CHECK: .section .BTF,"",@progbits +; CHECK-NEXT: .short 60319 # 0xeb9f +; CHECK-NEXT: .byte 1 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .long 24 +; CHECK-NEXT: .long 0 +; CHECK-NEXT: .long 56 +; CHECK-NEXT: .long 56 +; CHECK-NEXT: .long 25 +; CHECK-NEXT: .long 1 # BTF_KIND_INT(id = 1) +; CHECK-NEXT: .long 16777216 # 0x1000000 +; CHECK-NEXT: .long 4 +; CHECK-NEXT: .long 16777248 # 0x1000020 +; CHECK-NEXT: .long 0 # BTF_KIND_ARRAY(id = 2) +; CHECK-NEXT: .long 50331648 # 0x3000000 +; CHECK-NEXT: .long 0 +; CHECK-NEXT: .long 1 +; CHECK-NEXT: .long 3 +; CHECK-NEXT: .long 10 +; CHECK-NEXT: .long 5 # BTF_KIND_INT(id = 3) +; CHECK-NEXT: .long 16777216 # 0x1000000 +; CHECK-NEXT: .long 4 +; CHECK-NEXT: .long 32 # 0x20 +; CHECK-NEXT: .byte 0 # string offset=0 +; CHECK-NEXT: .ascii "int" # string offset=1 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii "__ARRAY_SIZE_TYPE__" # string offset=5 +; CHECK-NEXT: .byte 0 + +!0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression()) +!1 = distinct !DIGlobalVariable(name: "a", scope: !2, file: !3, line: 1, type: !6, isLocal: false, isDefinition: true) +!2 = distinct !DICompileUnit(language: DW_LANG_C99, file: !3, producer: "clang version 8.0.0 (trunk 345296) (llvm/trunk 345297)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !4, globals: !5, nameTableKind: None) +!3 = !DIFile(filename: "t.c", directory: "/home/yhs/tmp") +!4 = !{} +!5 = !{!0} +!6 = !DICompositeType(tag: DW_TAG_array_type, baseType: !7, size: 320, elements: !8) +!7 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +!8 = !{!9} +!9 = !DISubrange(count: 10) +!10 = !{i32 2, !"Dwarf Version", i32 4} +!11 = !{i32 2, !"Debug Info Version", i32 3} +!12 = !{i32 1, !"wchar_size", i32 4} +!13 = !{!"clang version 8.0.0 (trunk 345296) (llvm/trunk 345297)"} diff --git a/llvm/test/CodeGen/SBF/BTF/array-2d-int.ll b/llvm/test/CodeGen/SBF/BTF/array-2d-int.ll new file mode 100644 index 0000000000000..5e74ac97fe1dc --- /dev/null +++ b/llvm/test/CodeGen/SBF/BTF/array-2d-int.ll @@ -0,0 +1,62 @@ +; RUN: llc -sbf-enable-btf-emission -march=sbf -filetype=asm -o - %s | FileCheck -check-prefixes=CHECK %s + +; Source code: +; int a[10][10]; +; Compilation flag: +; clang -target bpf -O2 -g -S -emit-llvm t.c + +@a = common dso_local local_unnamed_addr global [10 x [10 x i32]] zeroinitializer, align 4, !dbg !0 + +!llvm.dbg.cu = !{!2} +!llvm.module.flags = !{!10, !11, !12} +!llvm.ident = !{!13} + +; CHECK: .section .BTF,"",@progbits +; CHECK-NEXT: .short 60319 # 0xeb9f +; CHECK-NEXT: .byte 1 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .long 24 +; CHECK-NEXT: .long 0 +; CHECK-NEXT: .long 80 +; CHECK-NEXT: .long 80 +; CHECK-NEXT: .long 25 +; CHECK-NEXT: .long 1 # BTF_KIND_INT(id = 1) +; CHECK-NEXT: .long 16777216 # 0x1000000 +; CHECK-NEXT: .long 4 +; CHECK-NEXT: .long 16777248 # 0x1000020 +; CHECK-NEXT: .long 0 # BTF_KIND_ARRAY(id = 2) +; CHECK-NEXT: .long 50331648 # 0x3000000 +; CHECK-NEXT: .long 0 +; CHECK-NEXT: .long 1 +; CHECK-NEXT: .long 4 +; CHECK-NEXT: .long 10 +; CHECK-NEXT: .long 0 # BTF_KIND_ARRAY(id = 3) +; CHECK-NEXT: .long 50331648 # 0x3000000 +; CHECK-NEXT: .long 0 +; CHECK-NEXT: .long 2 +; CHECK-NEXT: .long 4 +; CHECK-NEXT: .long 10 +; CHECK-NEXT: .long 5 # BTF_KIND_INT(id = 4) +; CHECK-NEXT: .long 16777216 # 0x1000000 +; CHECK-NEXT: .long 4 +; CHECK-NEXT: .long 32 # 0x20 +; CHECK-NEXT: .byte 0 # string offset=0 +; CHECK-NEXT: .ascii "int" # string offset=1 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii "__ARRAY_SIZE_TYPE__" # string offset=5 +; CHECK-NEXT: .byte 0 + +!0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression()) +!1 = distinct !DIGlobalVariable(name: "a", scope: !2, file: !3, line: 1, type: !6, isLocal: false, isDefinition: true) +!2 = distinct !DICompileUnit(language: DW_LANG_C99, file: !3, producer: "clang version 8.0.0 (trunk 345296) (llvm/trunk 345297)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !4, globals: !5, nameTableKind: None) +!3 = !DIFile(filename: "t.c", directory: "/home/yhs/tmp") +!4 = !{} +!5 = !{!0} +!6 = !DICompositeType(tag: DW_TAG_array_type, baseType: !7, size: 3200, elements: !8) +!7 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +!8 = !{!9, !9} +!9 = !DISubrange(count: 10) +!10 = !{i32 2, !"Dwarf Version", i32 4} +!11 = !{i32 2, !"Debug Info Version", i32 3} +!12 = !{i32 1, !"wchar_size", i32 4} +!13 = !{!"clang version 8.0.0 (trunk 345296) (llvm/trunk 345297)"} diff --git a/llvm/test/CodeGen/SBF/BTF/array-size-0.ll b/llvm/test/CodeGen/SBF/BTF/array-size-0.ll new file mode 100644 index 0000000000000..fefbfdc4fb616 --- /dev/null +++ b/llvm/test/CodeGen/SBF/BTF/array-size-0.ll @@ -0,0 +1,58 @@ +; RUN: llc -sbf-enable-btf-emission -march=sbf -filetype=asm -o - %s | FileCheck -check-prefixes=CHECK %s + +; Source code: +; struct t {}; +; struct t a[10]; +; Compilation flag: +; clang -target bpf -O2 -g -S -emit-llvm t.c + +%struct.t = type {} + +@a = common dso_local local_unnamed_addr global [10 x %struct.t] zeroinitializer, align 1, !dbg !0 + +!llvm.dbg.cu = !{!2} +!llvm.module.flags = !{!10, !11, !12} +!llvm.ident = !{!13} + +; CHECK: .section .BTF,"",@progbits +; CHECK-NEXT: .short 60319 # 0xeb9f +; CHECK-NEXT: .byte 1 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .long 24 +; CHECK-NEXT: .long 0 +; CHECK-NEXT: .long 52 +; CHECK-NEXT: .long 52 +; CHECK-NEXT: .long 23 +; CHECK-NEXT: .long 1 # BTF_KIND_STRUCT(id = 1) +; CHECK-NEXT: .long 67108864 # 0x4000000 +; CHECK-NEXT: .long 0 +; CHECK-NEXT: .long 0 # BTF_KIND_ARRAY(id = 2) +; CHECK-NEXT: .long 50331648 # 0x3000000 +; CHECK-NEXT: .long 0 +; CHECK-NEXT: .long 1 +; CHECK-NEXT: .long 3 +; CHECK-NEXT: .long 10 +; CHECK-NEXT: .long 3 # BTF_KIND_INT(id = 3) +; CHECK-NEXT: .long 16777216 # 0x1000000 +; CHECK-NEXT: .long 4 +; CHECK-NEXT: .long 32 # 0x20 +; CHECK-NEXT: .byte 0 # string offset=0 +; CHECK-NEXT: .byte 116 # string offset=1 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii "__ARRAY_SIZE_TYPE__" # string offset=3 +; CHECK-NEXT: .byte 0 + +!0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression()) +!1 = distinct !DIGlobalVariable(name: "a", scope: !2, file: !3, line: 2, type: !6, isLocal: false, isDefinition: true) +!2 = distinct !DICompileUnit(language: DW_LANG_C99, file: !3, producer: "clang version 8.0.0 (trunk 345296) (llvm/trunk 345297)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !4, globals: !5, nameTableKind: None) +!3 = !DIFile(filename: "t.c", directory: "/home/yhs/tmp") +!4 = !{} +!5 = !{!0} +!6 = !DICompositeType(tag: DW_TAG_array_type, baseType: !7, elements: !8) +!7 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "t", file: !3, line: 1, elements: !4) +!8 = !{!9} +!9 = !DISubrange(count: 10) +!10 = !{i32 2, !"Dwarf Version", i32 4} +!11 = !{i32 2, !"Debug Info Version", i32 3} +!12 = !{i32 1, !"wchar_size", i32 4} +!13 = !{!"clang version 8.0.0 (trunk 345296) (llvm/trunk 345297)"} diff --git a/llvm/test/CodeGen/SBF/BTF/array-typedef.ll b/llvm/test/CodeGen/SBF/BTF/array-typedef.ll new file mode 100644 index 0000000000000..11bfd4e6bbaf0 --- /dev/null +++ b/llvm/test/CodeGen/SBF/BTF/array-typedef.ll @@ -0,0 +1,70 @@ +; RUN: llc -sbf-enable-btf-emission -march=sbf -filetype=asm -o - %s | FileCheck -check-prefixes=CHECK %s + +; Source code: +; typedef unsigned _int; +; typedef _int __int; +; __int a[10]; +; Compilation flag: +; clang -target bpf -O2 -g -S -emit-llvm t.c + +@a = common dso_local local_unnamed_addr global [10 x i32] zeroinitializer, align 4, !dbg !0 + +!llvm.dbg.cu = !{!2} +!llvm.module.flags = !{!12, !13, !14} +!llvm.ident = !{!15} + +; CHECK: .section .BTF,"",@progbits +; CHECK-NEXT: .short 60319 # 0xeb9f +; CHECK-NEXT: .byte 1 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .long 24 +; CHECK-NEXT: .long 0 +; CHECK-NEXT: .long 80 +; CHECK-NEXT: .long 80 +; CHECK-NEXT: .long 45 +; CHECK-NEXT: .long 1 # BTF_KIND_TYPEDEF(id = 1) +; CHECK-NEXT: .long 134217728 # 0x8000000 +; CHECK-NEXT: .long 2 +; CHECK-NEXT: .long 7 # BTF_KIND_TYPEDEF(id = 2) +; CHECK-NEXT: .long 134217728 # 0x8000000 +; CHECK-NEXT: .long 3 +; CHECK-NEXT: .long 12 # BTF_KIND_INT(id = 3) +; CHECK-NEXT: .long 16777216 # 0x1000000 +; CHECK-NEXT: .long 4 +; CHECK-NEXT: .long 32 # 0x20 +; CHECK-NEXT: .long 0 # BTF_KIND_ARRAY(id = 4) +; CHECK-NEXT: .long 50331648 # 0x3000000 +; CHECK-NEXT: .long 0 +; CHECK-NEXT: .long 1 +; CHECK-NEXT: .long 5 +; CHECK-NEXT: .long 10 +; CHECK-NEXT: .long 25 # BTF_KIND_INT(id = 5) +; CHECK-NEXT: .long 16777216 # 0x1000000 +; CHECK-NEXT: .long 4 +; CHECK-NEXT: .long 32 # 0x20 +; CHECK-NEXT: .byte 0 # string offset=0 +; CHECK-NEXT: .ascii "__int" # string offset=1 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii "_int" # string offset=7 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii "unsigned int" # string offset=12 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii "__ARRAY_SIZE_TYPE__" # string offset=25 +; CHECK-NEXT: .byte 0 + +!0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression()) +!1 = distinct !DIGlobalVariable(name: "a", scope: !2, file: !3, line: 3, type: !6, isLocal: false, isDefinition: true) +!2 = distinct !DICompileUnit(language: DW_LANG_C99, file: !3, producer: "clang version 8.0.0 (trunk 345296) (llvm/trunk 345297)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !4, globals: !5, nameTableKind: None) +!3 = !DIFile(filename: "t.c", directory: "/home/yhs/tmp") +!4 = !{} +!5 = !{!0} +!6 = !DICompositeType(tag: DW_TAG_array_type, baseType: !7, size: 320, elements: !10) +!7 = !DIDerivedType(tag: DW_TAG_typedef, name: "__int", file: !3, line: 2, baseType: !8) +!8 = !DIDerivedType(tag: DW_TAG_typedef, name: "_int", file: !3, line: 1, baseType: !9) +!9 = !DIBasicType(name: "unsigned int", size: 32, encoding: DW_ATE_unsigned) +!10 = !{!11} +!11 = !DISubrange(count: 10) +!12 = !{i32 2, !"Dwarf Version", i32 4} +!13 = !{i32 2, !"Debug Info Version", i32 3} +!14 = !{i32 1, !"wchar_size", i32 4} +!15 = !{!"clang version 8.0.0 (trunk 345296) (llvm/trunk 345297)"} diff --git a/llvm/test/CodeGen/SBF/BTF/binary-format.ll b/llvm/test/CodeGen/SBF/BTF/binary-format.ll new file mode 100644 index 0000000000000..5e84b67c16c1f --- /dev/null +++ b/llvm/test/CodeGen/SBF/BTF/binary-format.ll @@ -0,0 +1,56 @@ +; RUN: llc -sbf-enable-btf-emission -march=sbf -filetype=obj -o - %s | llvm-readelf -x ".BTF" -x ".BTF.ext" - | FileCheck -check-prefixes=CHECK,CHECK-EL %s + +; Source code: +; int f(int a) { return a; } +; Compilation flag: +; clang -target bpf -O2 -g -gdwarf-5 -gembed-source -S -emit-llvm t.c + +; Function Attrs: nounwind readnone +define dso_local i32 @f(i32 returned %a) local_unnamed_addr #0 !dbg !7 { +entry: + call void @llvm.dbg.value(metadata i32 %a, metadata !12, metadata !DIExpression()), !dbg !13 + ret i32 %a, !dbg !14 +} + +; CHECK: '.BTF' +; CHECK-EL: 0x00000000 9feb0100 18000000 00000000 30000000 +; CHECK-EL: 0x00000010 30000000 33000000 01000000 00000001 +; CHECK-EL: 0x00000020 04000000 20000001 00000000 0100000d +; CHECK-EL: 0x00000030 01000000 05000000 01000000 07000000 +; CHECK-EL: 0x00000040 0100000c 02000000 00696e74 00610066 +; CHECK: 0x00000050 002e7465 7874002f 746d702f 742e6300 +; CHECK: 0x00000060 696e7420 6628696e 74206129 207b2072 +; CHECK: 0x00000070 65747572 6e20613b 207d00 +; CHECK: '.BTF.ext' +; CHECK-EL: 0x00000000 9feb0100 20000000 00000000 14000000 +; CHECK-EL: 0x00000010 14000000 2c000000 40000000 00000000 +; CHECK-EL: 0x00000020 08000000 09000000 01000000 00000000 +; CHECK-EL: 0x00000030 03000000 10000000 09000000 02000000 +; CHECK-EL: 0x00000040 00000000 0f000000 18000000 00040000 +; CHECK-EL: 0x00000050 00000000 0f000000 18000000 10040000 + +; Function Attrs: nounwind readnone speculatable +declare void @llvm.dbg.value(metadata, metadata, metadata) #1 + +attributes #0 = { nounwind readnone "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "frame-pointer"="all" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" } +attributes #1 = { nounwind readnone speculatable } + +!llvm.dbg.cu = !{!0} +!llvm.module.flags = !{!3, !4, !5} +!llvm.ident = !{!6} + +!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 8.0.0 (trunk 344789) (llvm/trunk 344782)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, nameTableKind: None) +!1 = !DIFile(filename: "t.c", directory: "/tmp", checksumkind: CSK_MD5, checksum: "1924f0d78deb326ceb76cd8e9f450775", source: "int f(int a) { return a; }\0A") +!2 = !{} +!3 = !{i32 2, !"Dwarf Version", i32 5} +!4 = !{i32 2, !"Debug Info Version", i32 3} +!5 = !{i32 1, !"wchar_size", i32 4} +!6 = !{!"clang version 8.0.0 (trunk 344789) (llvm/trunk 344782)"} +!7 = distinct !DISubprogram(name: "f", scope: !1, file: !1, line: 1, type: !8, isLocal: false, isDefinition: true, scopeLine: 1, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, isOptimized: true, unit: !0, retainedNodes: !11) +!8 = !DISubroutineType(types: !9) +!9 = !{!10, !10} +!10 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +!11 = !{!12} +!12 = !DILocalVariable(name: "a", arg: 1, scope: !7, file: !1, line: 1, type: !10) +!13 = !DILocation(line: 1, column: 11, scope: !7) +!14 = !DILocation(line: 1, column: 16, scope: !7) diff --git a/llvm/test/CodeGen/SBF/BTF/builtin-btf-type-id-2.ll b/llvm/test/CodeGen/SBF/BTF/builtin-btf-type-id-2.ll new file mode 100644 index 0000000000000..af350faab13da --- /dev/null +++ b/llvm/test/CodeGen/SBF/BTF/builtin-btf-type-id-2.ll @@ -0,0 +1,73 @@ +; RUN: opt -O2 -mtriple=sbf -S -o %t1 %s +; RUN: llc -sbf-enable-btf-emission -filetype=asm -o - %t1 | FileCheck -check-prefixes=CHECK %s +; RUN: llc -sbf-enable-btf-emission -mattr=+alu32 -filetype=asm -o - %t1 | FileCheck -check-prefixes=CHECK %s +; Source code: +; struct s { +; int a; +; }; +; int test(void) { +; return __builtin_btf_type_id(*(const struct s *)0, 1); +; } +; Compilation flag: +; clang -target bpf -O2 -g -S -emit-llvm -Xclang -disable-llvm-passes test.c + +; Function Attrs: nounwind +define dso_local i32 @test() #0 !dbg !7 { +entry: + %0 = call i64 @llvm.bpf.btf.type.id(i32 0, i64 1), !dbg !11, !llvm.preserve.access.index !12 + %conv = trunc i64 %0 to i32, !dbg !11 + ret i32 %conv, !dbg !16 +} + +; CHECK: .long 1 # BTF_KIND_INT(id = 2) +; CHECK-NEXT: .long 16777216 # 0x1000000 +; CHECK-NEXT: .long 4 +; CHECK-NEXT: .long 16777248 # 0x1000020 + +; CHECK: .long 16 # BTF_KIND_STRUCT(id = 4) +; CHECK-NEXT: .long 67108865 # 0x4000001 +; CHECK-NEXT: .long 4 +; CHECK-NEXT: .long 18 +; CHECK-NEXT: .long 2 + +; CHECK: .ascii "int" # string offset=1 +; CHECK: .ascii ".text" # string offset=10 +; CHECK: .byte 115 # string offset=16 +; CHECK: .byte 97 # string offset=18 +; CHECK: .byte 48 # string offset=20 + +; CHECK: .long 16 # FieldReloc +; CHECK-NEXT: .long 10 # Field reloc section string offset=10 +; CHECK-NEXT: .long 1 +; CHECK-NEXT: .long .Ltmp{{[0-9]+}} +; CHECK-NEXT: .long 4 +; CHECK-NEXT: .long 20 +; CHECK-NEXT: .long 7 + +; Function Attrs: nounwind readnone +declare i64 @llvm.bpf.btf.type.id(i32, i64) #1 + +attributes #0 = { nounwind "frame-pointer"="all" "no-trapping-math"="true" "stack-protector-buffer-size"="8" } +attributes #1 = { nounwind readnone } + +!llvm.dbg.cu = !{!0} +!llvm.module.flags = !{!3, !4, !5} +!llvm.ident = !{!6} + +!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 13.0.0 (https://github.com/llvm/llvm-project.git 9783e2098800b954c55ae598a1ce5c4b93444fc0)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, splitDebugInlining: false, nameTableKind: None) +!1 = !DIFile(filename: "test.c", directory: "/tmp/home/yhs/bpf/test") +!2 = !{} +!3 = !{i32 7, !"Dwarf Version", i32 4} +!4 = !{i32 2, !"Debug Info Version", i32 3} +!5 = !{i32 1, !"wchar_size", i32 4} +!6 = !{!"clang version 13.0.0 (https://github.com/llvm/llvm-project.git 9783e2098800b954c55ae598a1ce5c4b93444fc0)"} +!7 = distinct !DISubprogram(name: "test", scope: !1, file: !1, line: 4, type: !8, scopeLine: 4, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !2) +!8 = !DISubroutineType(types: !9) +!9 = !{!10} +!10 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +!11 = !DILocation(line: 5, column: 10, scope: !7) +!12 = !DIDerivedType(tag: DW_TAG_const_type, baseType: !13) +!13 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "s", file: !1, line: 1, size: 32, elements: !14) +!14 = !{!15} +!15 = !DIDerivedType(tag: DW_TAG_member, name: "a", scope: !13, file: !1, line: 2, baseType: !10, size: 32) +!16 = !DILocation(line: 5, column: 3, scope: !7) diff --git a/llvm/test/CodeGen/SBF/BTF/builtin-btf-type-id.ll b/llvm/test/CodeGen/SBF/BTF/builtin-btf-type-id.ll new file mode 100644 index 0000000000000..e7ea449e1ae2c --- /dev/null +++ b/llvm/test/CodeGen/SBF/BTF/builtin-btf-type-id.ll @@ -0,0 +1,151 @@ +; RUN: opt -O2 -mtriple=sbf %s | llvm-dis > %t1 +; RUN: llc -sbf-enable-btf-emission -filetype=asm -o - %t1 | FileCheck -check-prefixes=CHECK %s +; RUN: llc -sbf-enable-btf-emission -mattr=+alu32 -filetype=asm -o - %t1 | FileCheck -check-prefixes=CHECK %s +; +; Source code: +; static int (*bpf_log)(unsigned long tid, void *data, int data_size) = (void *)999; +; struct { +; char f1[100]; +; typeof(3) f2; +; } tmp__abc = {1, 3}; +; void prog1() { +; bpf_log(__builtin_btf_type_id(tmp__abc, 0), &tmp__abc, sizeof(tmp__abc)); +; } +; void prog2() { +; bpf_log(__builtin_btf_type_id(&tmp__abc, 0), &tmp__abc, sizeof(tmp__abc)); +; } +; void prog3() { +; bpf_log(__builtin_btf_type_id(tmp__abc.f1[3], 1), &tmp__abc, sizeof(tmp__abc)); +; } +; Compilation flag: +; clang -target bpf -O2 -g -S -emit-llvm -Xclang -disable-llvm-passes test.c + +@tmp__abc = dso_local global { <{ i8, i8, [98 x i8] }>, i32 } { <{ i8, i8, [98 x i8] }> <{ i8 1, i8 3, [98 x i8] zeroinitializer }>, i32 0 }, align 4, !dbg !0 +@bpf_log = internal global i32 (i64, i8*, i32)* inttoptr (i64 999 to i32 (i64, i8*, i32)*), align 8, !dbg !17 + +; Function Attrs: nounwind +define dso_local void @prog1() #0 !dbg !28 { +entry: + %0 = load i32 (i64, i8*, i32)*, i32 (i64, i8*, i32)** @bpf_log, align 8, !dbg !31, !tbaa !32 + %1 = call i64 @llvm.bpf.btf.type.id(i32 0, i64 0), !dbg !36, !llvm.preserve.access.index !7 + %call = call i32 %0(i64 %1, i8* getelementptr inbounds ({ <{ i8, i8, [98 x i8] }>, i32 }, { <{ i8, i8, [98 x i8] }>, i32 }* @tmp__abc, i32 0, i32 0, i32 0), i32 104), !dbg !31 + ret void, !dbg !37 +} + +; Function Attrs: nounwind readnone +declare i64 @llvm.bpf.btf.type.id(i32, i64) #1 + +; Function Attrs: nounwind +define dso_local void @prog2() #0 !dbg !38 { +entry: + %0 = load i32 (i64, i8*, i32)*, i32 (i64, i8*, i32)** @bpf_log, align 8, !dbg !39, !tbaa !32 + %1 = call i64 @llvm.bpf.btf.type.id(i32 1, i64 0), !dbg !40, !llvm.preserve.access.index !6 + %call = call i32 %0(i64 %1, i8* getelementptr inbounds ({ <{ i8, i8, [98 x i8] }>, i32 }, { <{ i8, i8, [98 x i8] }>, i32 }* @tmp__abc, i32 0, i32 0, i32 0), i32 104), !dbg !39 + ret void, !dbg !41 +} + +; Function Attrs: nounwind +define dso_local void @prog3() #0 !dbg !42 { +entry: + %0 = load i32 (i64, i8*, i32)*, i32 (i64, i8*, i32)** @bpf_log, align 8, !dbg !43, !tbaa !32 + %1 = call i64 @llvm.bpf.btf.type.id(i32 2, i64 1), !dbg !44, !llvm.preserve.access.index !11 + %call = call i32 %0(i64 %1, i8* getelementptr inbounds ({ <{ i8, i8, [98 x i8] }>, i32 }, { <{ i8, i8, [98 x i8] }>, i32 }* @tmp__abc, i32 0, i32 0, i32 0), i32 104), !dbg !43 + ret void, !dbg !45 +} + +; CHECK-LABEL: prog1 +; CHECK: lddw r1, 3 +; CHECK-LABEL: prog2 +; CHECK: lddw r1, 10 +; CHECK-LABEL: prog3 +; CHECK: lddw r1, 4 + +; CHECK: .long 0 # BTF_KIND_STRUCT(id = 3) +; CHECK-NEXT: .long 67108866 # 0x4000002 +; CHECK-NEXT: .long 104 +; CHECK-NEXT: .long 13 +; CHECK-NEXT: .long 5 +; CHECK-NEXT: .long 0 # 0x0 +; CHECK-NEXT: .long 16 +; CHECK-NEXT: .long 7 +; CHECK-NEXT: .long 800 # 0x320 +; CHECK: .long 19 # BTF_KIND_INT(id = 4) +; CHECK: .long 0 # BTF_KIND_PTR(id = 10) +; CHECK-NEXT: .long 33554432 # 0x2000000 +; CHECK-NEXT: .long 3 + +; CHECK: .ascii ".text" # string offset=7 +; CHECK: .ascii "f1" # string offset=13 +; CHECK: .ascii "f2" # string offset=16 +; CHECK: .ascii "char" # string offset=19 +; CHECK: .byte 48 # string offset=48 + +; CHECK: .long 16 # FieldReloc +; CHECK-NEXT: .long 7 # Field reloc section string offset=7 +; CHECK-NEXT: .long 3 +; CHECK-NEXT: .long .Ltmp{{[0-9]+}} +; CHECK-NEXT: .long 3 +; CHECK-NEXT: .long 48 +; CHECK-NEXT: .long 6 +; CHECK-NEXT: .long .Ltmp{{[0-9]+}} +; CHECK-NEXT: .long 10 +; CHECK-NEXT: .long 48 +; CHECK-NEXT: .long 6 +; CHECK-NEXT: .long .Ltmp{{[0-9]+}} +; CHECK-NEXT: .long 4 +; CHECK-NEXT: .long 48 +; CHECK-NEXT: .long 7 + +attributes #0 = { nounwind "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" } +attributes #1 = { nounwind readnone } + +!llvm.dbg.cu = !{!2} +!llvm.module.flags = !{!24, !25, !26} +!llvm.ident = !{!27} + +!0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression()) +!1 = distinct !DIGlobalVariable(name: "tmp__abc", scope: !2, file: !3, line: 5, type: !7, isLocal: false, isDefinition: true) +!2 = distinct !DICompileUnit(language: DW_LANG_C99, file: !3, producer: "clang version 12.0.0 (https://github.com/llvm/llvm-project.git 630c2da0e967e27e2a4c678dfc6e452a74141880)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !4, retainedTypes: !5, globals: !16, splitDebugInlining: false, nameTableKind: None) +!3 = !DIFile(filename: "test.c", directory: "/tmp/home/yhs/work/tests/core") +!4 = !{} +!5 = !{!6, !11} +!6 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !7, size: 64) +!7 = distinct !DICompositeType(tag: DW_TAG_structure_type, file: !3, line: 2, size: 832, elements: !8) +!8 = !{!9, !14} +!9 = !DIDerivedType(tag: DW_TAG_member, name: "f1", scope: !7, file: !3, line: 3, baseType: !10, size: 800) +!10 = !DICompositeType(tag: DW_TAG_array_type, baseType: !11, size: 800, elements: !12) +!11 = !DIBasicType(name: "char", size: 8, encoding: DW_ATE_signed_char) +!12 = !{!13} +!13 = !DISubrange(count: 100) +!14 = !DIDerivedType(tag: DW_TAG_member, name: "f2", scope: !7, file: !3, line: 4, baseType: !15, size: 32, offset: 800) +!15 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +!16 = !{!0, !17} +!17 = !DIGlobalVariableExpression(var: !18, expr: !DIExpression()) +!18 = distinct !DIGlobalVariable(name: "bpf_log", scope: !2, file: !3, line: 1, type: !19, isLocal: true, isDefinition: true) +!19 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !20, size: 64) +!20 = !DISubroutineType(types: !21) +!21 = !{!15, !22, !23, !15} +!22 = !DIBasicType(name: "long unsigned int", size: 64, encoding: DW_ATE_unsigned) +!23 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: null, size: 64) +!24 = !{i32 7, !"Dwarf Version", i32 4} +!25 = !{i32 2, !"Debug Info Version", i32 3} +!26 = !{i32 1, !"wchar_size", i32 4} +!27 = !{!"clang version 12.0.0 (https://github.com/llvm/llvm-project.git 630c2da0e967e27e2a4c678dfc6e452a74141880)"} +!28 = distinct !DISubprogram(name: "prog1", scope: !3, file: !3, line: 6, type: !29, scopeLine: 6, flags: DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !2, retainedNodes: !4) +!29 = !DISubroutineType(types: !30) +!30 = !{null} +!31 = !DILocation(line: 7, column: 3, scope: !28) +!32 = !{!33, !33, i64 0} +!33 = !{!"any pointer", !34, i64 0} +!34 = !{!"omnipotent char", !35, i64 0} +!35 = !{!"Simple C/C++ TBAA"} +!36 = !DILocation(line: 7, column: 11, scope: !28) +!37 = !DILocation(line: 8, column: 1, scope: !28) +!38 = distinct !DISubprogram(name: "prog2", scope: !3, file: !3, line: 9, type: !29, scopeLine: 9, flags: DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !2, retainedNodes: !4) +!39 = !DILocation(line: 10, column: 3, scope: !38) +!40 = !DILocation(line: 10, column: 11, scope: !38) +!41 = !DILocation(line: 11, column: 1, scope: !38) +!42 = distinct !DISubprogram(name: "prog3", scope: !3, file: !3, line: 12, type: !29, scopeLine: 12, flags: DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !2, retainedNodes: !4) +!43 = !DILocation(line: 13, column: 3, scope: !42) +!44 = !DILocation(line: 13, column: 11, scope: !42) +!45 = !DILocation(line: 14, column: 1, scope: !42) diff --git a/llvm/test/CodeGen/SBF/BTF/char-no-debuginfo.ll b/llvm/test/CodeGen/SBF/BTF/char-no-debuginfo.ll new file mode 100644 index 0000000000000..befa09ec0c7bc --- /dev/null +++ b/llvm/test/CodeGen/SBF/BTF/char-no-debuginfo.ll @@ -0,0 +1,30 @@ +; RUN: llc -sbf-enable-btf-emission -march=sbf -filetype=asm -o - %s | FileCheck -check-prefixes=CHECK %s + +; Source code: +; int g __attribute__((section("maps"))) = 5; +; int test() { return g; } +; Compilation flag: +; clang -target bpf -O2 -S -emit-llvm t.c + +@g = dso_local local_unnamed_addr global i32 5, section "maps", align 4 + +; Function Attrs: norecurse nounwind readonly +define dso_local i32 @test() local_unnamed_addr #0 { + %1 = load i32, i32* @g, align 4, !tbaa !2 + ret i32 %1 +} + +; CHECK-NOT: .section .BTF +; CHECK-NOT: .section .BTF.ext + +attributes #0 = { norecurse nounwind readonly "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "frame-pointer"="all" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" } + +!llvm.module.flags = !{!0} +!llvm.ident = !{!1} + +!0 = !{i32 1, !"wchar_size", i32 4} +!1 = !{!"clang version 8.0.20181009 "} +!2 = !{!3, !3, i64 0} +!3 = !{!"int", !4, i64 0} +!4 = !{!"omnipotent char", !5, i64 0} +!5 = !{!"Simple C/C++ TBAA"} diff --git a/llvm/test/CodeGen/SBF/BTF/char.ll b/llvm/test/CodeGen/SBF/BTF/char.ll new file mode 100644 index 0000000000000..7b3da2984098a --- /dev/null +++ b/llvm/test/CodeGen/SBF/BTF/char.ll @@ -0,0 +1,41 @@ +; RUN: llc -sbf-enable-btf-emission -march=sbf -filetype=asm -o - %s | FileCheck -check-prefixes=CHECK %s + +; Source code: +; char a; +; Compilation flag: +; clang -target bpf -O2 -g -S -emit-llvm t.c + +@a = common dso_local local_unnamed_addr global i8 0, align 1, !dbg !0 + +!llvm.dbg.cu = !{!2} +!llvm.module.flags = !{!7, !8, !9} +!llvm.ident = !{!10} + +; CHECK: .section .BTF,"",@progbits +; CHECK-NEXT: .short 60319 # 0xeb9f +; CHECK-NEXT: .byte 1 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .long 24 +; CHECK-NEXT: .long 0 +; CHECK-NEXT: .long 16 +; CHECK-NEXT: .long 16 +; CHECK-NEXT: .long 6 +; CHECK-NEXT: .long 1 # BTF_KIND_INT(id = 1) +; CHECK-NEXT: .long 16777216 # 0x1000000 +; CHECK-NEXT: .long 1 +; CHECK-NEXT: .long 16777224 # 0x1000008 +; CHECK-NEXT: .byte 0 # string offset=0 +; CHECK-NEXT: .ascii "char" # string offset=1 +; CHECK-NEXT: .byte 0 + +!0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression()) +!1 = distinct !DIGlobalVariable(name: "a", scope: !2, file: !3, line: 1, type: !6, isLocal: false, isDefinition: true) +!2 = distinct !DICompileUnit(language: DW_LANG_C99, file: !3, producer: "clang version 8.0.0 (trunk 344789) (llvm/trunk 344782)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !4, globals: !5, nameTableKind: None) +!3 = !DIFile(filename: "t.c", directory: "/home/yhs/tmp") +!4 = !{} +!5 = !{!0} +!6 = !DIBasicType(name: "char", size: 8, encoding: DW_ATE_signed_char) +!7 = !{i32 2, !"Dwarf Version", i32 4} +!8 = !{i32 2, !"Debug Info Version", i32 3} +!9 = !{i32 1, !"wchar_size", i32 4} +!10 = !{!"clang version 8.0.0 (trunk 344789) (llvm/trunk 344782)"} diff --git a/llvm/test/CodeGen/SBF/BTF/double.ll b/llvm/test/CodeGen/SBF/BTF/double.ll new file mode 100644 index 0000000000000..46f287c10bb33 --- /dev/null +++ b/llvm/test/CodeGen/SBF/BTF/double.ll @@ -0,0 +1,57 @@ +; RUN: llc -sbf-enable-btf-emission -march=sbf -filetype=asm -o - %s | FileCheck -check-prefixes=CHECK %s + +; Source code: +; double a; +; Compilation flag: +; clang -target bpf -O2 -g -S -emit-llvm t.c + +@a = dso_local local_unnamed_addr global double 0.000000e+00, align 8, !dbg !0 + +!llvm.dbg.cu = !{!2} +!llvm.module.flags = !{!7, !8, !9} +!llvm.ident = !{!10} + +; CHECK: .section .BTF,"",@progbits +; CHECK-NEXT: .short 60319 # 0xeb9f +; CHECK-NEXT: .byte 1 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .long 24 +; CHECK-NEXT: .long 0 +; CHECK-NEXT: .long 52 +; CHECK-NEXT: .long 52 +; CHECK-NEXT: .long 15 +; [1] double, size=8 bytes (64 bits) +; CHECK-NEXT: .long 1 # BTF_KIND_FLOAT(id = 1) +; CHECK-NEXT: .long 268435456 # 0x10000000 +; CHECK-NEXT: .long 8 +; [2] a, type=double (1), global +; CHECK-NEXT: .long 8 # BTF_KIND_VAR(id = 2) +; CHECK-NEXT: .long 234881024 # 0xe000000 +; CHECK-NEXT: .long 1 +; CHECK-NEXT: .long 1 +; [3] .bss, 1 var, {a, offset=&a, size=8 bytes} +; CHECK-NEXT: .long 10 # BTF_KIND_DATASEC(id = 3) +; CHECK-NEXT: .long 251658241 # 0xf000001 +; CHECK-NEXT: .long 0 +; CHECK-NEXT: .long 2 +; CHECK-NEXT: .long a +; CHECK-NEXT: .long 8 +; CHECK-NEXT: .byte 0 # string offset=0 +; CHECK-NEXT: .ascii "double" # string offset=1 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .byte 97 # string offset=8 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii ".bss" # string offset=10 +; CHECK-NEXT: .byte 0 + +!0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression()) +!1 = distinct !DIGlobalVariable(name: "a", scope: !2, file: !3, line: 1, type: !6, isLocal: false, isDefinition: true) +!2 = distinct !DICompileUnit(language: DW_LANG_C99, file: !3, producer: "clang version 11.0.0 ", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !4, globals: !5, splitDebugInlining: false, nameTableKind: None) +!3 = !DIFile(filename: "t.c", directory: "/home/yhs/tmp") +!4 = !{} +!5 = !{!0} +!6 = !DIBasicType(name: "double", size: 64, encoding: DW_ATE_float) +!7 = !{i32 7, !"Dwarf Version", i32 4} +!8 = !{i32 2, !"Debug Info Version", i32 3} +!9 = !{i32 1, !"wchar_size", i32 4} +!10 = !{!"clang version 11.0.0 "} diff --git a/llvm/test/CodeGen/SBF/BTF/empty-btf.ll b/llvm/test/CodeGen/SBF/BTF/empty-btf.ll new file mode 100644 index 0000000000000..1ae3a307422f1 --- /dev/null +++ b/llvm/test/CodeGen/SBF/BTF/empty-btf.ll @@ -0,0 +1,21 @@ +; RUN: llc -sbf-enable-btf-emission -march=sbf -filetype=asm -o - %s | FileCheck -check-prefixes=CHECK %s + +; Source code: +; int test(int arg) { return arg; } +; Compilation flag: +; clang -target bpf -O2 -S -emit-llvm t.c + +; Function Attrs: norecurse nounwind readnone +define dso_local i32 @test(i32 returned) local_unnamed_addr #0 { + ret i32 %0 +} + +; CHECK-NOT: BTF + +attributes #0 = { norecurse nounwind readnone } + +!llvm.module.flags = !{!0} +!llvm.ident = !{!1} + +!0 = !{i32 1, !"wchar_size", i32 4} +!1 = !{!"clang version 8.0.20181009 "} diff --git a/llvm/test/CodeGen/SBF/BTF/enum-basic.ll b/llvm/test/CodeGen/SBF/BTF/enum-basic.ll new file mode 100644 index 0000000000000..65f64944a02c1 --- /dev/null +++ b/llvm/test/CodeGen/SBF/BTF/enum-basic.ll @@ -0,0 +1,50 @@ +; RUN: llc -sbf-enable-btf-emission -march=sbf -filetype=asm -o - %s | FileCheck -check-prefixes=CHECK %s + +; Source code: +; enum { A = -1, B = 2 } a; +; Compilation flag: +; clang -target bpf -O2 -g -S -emit-llvm t.c + +@a = common dso_local local_unnamed_addr global i32 0, align 4, !dbg !0 + +!llvm.dbg.cu = !{!2} +!llvm.module.flags = !{!11, !12, !13} +!llvm.ident = !{!14} + +; CHECK: .section .BTF,"",@progbits +; CHECK-NEXT: .short 60319 # 0xeb9f +; CHECK-NEXT: .byte 1 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .long 24 +; CHECK-NEXT: .long 0 +; CHECK-NEXT: .long 28 +; CHECK-NEXT: .long 28 +; CHECK-NEXT: .long 5 +; CHECK-NEXT: .long 0 # BTF_KIND_ENUM(id = 1) +; CHECK-NEXT: .long 2248146946 # 0x86000002 +; CHECK-NEXT: .long 4 +; CHECK-NEXT: .long 1 +; CHECK-NEXT: .long -1 +; CHECK-NEXT: .long 3 +; CHECK-NEXT: .long 2 +; CHECK-NEXT: .byte 0 # string offset=0 +; CHECK-NEXT: .byte 65 # string offset=1 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .byte 66 # string offset=3 +; CHECK-NEXT: .byte 0 + +!0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression()) +!1 = distinct !DIGlobalVariable(name: "a", scope: !2, file: !3, line: 1, type: !5, isLocal: false, isDefinition: true) +!2 = distinct !DICompileUnit(language: DW_LANG_C99, file: !3, producer: "clang version 8.0.0 (trunk 344789) (llvm/trunk 344782)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !4, globals: !10, nameTableKind: None) +!3 = !DIFile(filename: "t.c", directory: "/home/yhs/tmp") +!4 = !{!5} +!5 = !DICompositeType(tag: DW_TAG_enumeration_type, file: !3, line: 1, baseType: !6, size: 32, elements: !7) +!6 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +!7 = !{!8, !9} +!8 = !DIEnumerator(name: "A", value: -1) +!9 = !DIEnumerator(name: "B", value: 2) +!10 = !{!0} +!11 = !{i32 2, !"Dwarf Version", i32 4} +!12 = !{i32 2, !"Debug Info Version", i32 3} +!13 = !{i32 1, !"wchar_size", i32 4} +!14 = !{!"clang version 8.0.0 (trunk 344789) (llvm/trunk 344782)"} diff --git a/llvm/test/CodeGen/SBF/BTF/extern-builtin.ll b/llvm/test/CodeGen/SBF/BTF/extern-builtin.ll new file mode 100644 index 0000000000000..294b65fbae505 --- /dev/null +++ b/llvm/test/CodeGen/SBF/BTF/extern-builtin.ll @@ -0,0 +1,90 @@ +; RUN: llc -sbf-enable-btf-emission -march=sbf -filetype=asm -o - %s | FileCheck -check-prefixes=CHECK %s +; Note that llvm.bpd.load does not apply to SBF, delete eventually. +: XFAIL: * +; Source code: +; unsigned long long load_byte(void *skb, +; unsigned long long off) asm("llvm.bpf.load.byte"); +; unsigned long long test(void *skb) { +; return load_byte(skb, 10); +; } +; Compilation flag: +; clang -target bpf -O2 -g -S -emit-llvm test.c + +; Function Attrs: nounwind readonly +define dso_local i64 @test(i8* readonly %skb) local_unnamed_addr #0 !dbg !13 { +entry: + call void @llvm.dbg.value(metadata i8* %skb, metadata !17, metadata !DIExpression()), !dbg !18 + %call = tail call i64 @llvm.bpf.load.byte(i8* %skb, i64 10), !dbg !19 + ret i64 %call, !dbg !20 +} + +; CHECK: .section .BTF,"",@progbits +; CHECK-NEXT: .short 60319 # 0xeb9f +; CHECK-NEXT: .byte 1 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .long 24 +; CHECK-NEXT: .long 0 +; CHECK-NEXT: .long 60 +; CHECK-NEXT: .long 60 +; CHECK-NEXT: .long 78 +; CHECK-NEXT: .long 0 # BTF_KIND_PTR(id = 1) +; CHECK-NEXT: .long 33554432 # 0x2000000 +; CHECK-NEXT: .long 0 +; CHECK-NEXT: .long 0 # BTF_KIND_FUNC_PROTO(id = 2) +; CHECK-NEXT: .long 218103809 # 0xd000001 +; CHECK-NEXT: .long 3 +; CHECK-NEXT: .long 1 +; CHECK-NEXT: .long 1 +; CHECK-NEXT: .long 5 # BTF_KIND_INT(id = 3) +; CHECK-NEXT: .long 16777216 # 0x1000000 +; CHECK-NEXT: .long 8 +; CHECK-NEXT: .long 64 # 0x40 +; CHECK-NEXT: .long 28 # BTF_KIND_FUNC(id = 4) +; CHECK-NEXT: .long 201326593 # 0xc000001 +; CHECK-NEXT: .long 2 +; CHECK-NEXT: .byte 0 # string offset=0 +; CHECK-NEXT: .ascii "skb" # string offset=1 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii "long long unsigned int" # string offset=5 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii "test" # string offset=28 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii ".text" # string offset=33 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii "/tmp/home/yhs/work/tests/extern/test.c" # string offset=39 +; CHECK-NEXT: .byte 0 + +; Function Attrs: nounwind readonly +declare !dbg !4 i64 @llvm.bpf.load.byte(i8*, i64) #1 +; Function Attrs: nounwind readnone speculatable willreturn +declare void @llvm.dbg.value(metadata, metadata, metadata) #2 + +attributes #0 = { nounwind readonly "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" } +attributes #1 = { nounwind readonly } +attributes #2 = { nounwind readnone speculatable willreturn } + +!llvm.dbg.cu = !{!0} +!llvm.module.flags = !{!9, !10, !11} +!llvm.ident = !{!12} + +!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 10.0.0 (https://github.com/llvm/llvm-project.git 907019d835895443b198afcd992c42c9d3478fdf)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, retainedTypes: !3, splitDebugInlining: false, nameTableKind: None) +!1 = !DIFile(filename: "test.c", directory: "/tmp/home/yhs/work/tests/extern") +!2 = !{} +!3 = !{!4} +!4 = !DISubprogram(name: "load_byte", linkageName: "llvm.bpf.load.byte", scope: !1, file: !1, line: 1, type: !5, flags: DIFlagPrototyped, spFlags: DISPFlagOptimized, retainedNodes: !2) +!5 = !DISubroutineType(types: !6) +!6 = !{!7, !8, !7} +!7 = !DIBasicType(name: "long long unsigned int", size: 64, encoding: DW_ATE_unsigned) +!8 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: null, size: 64) +!9 = !{i32 7, !"Dwarf Version", i32 4} +!10 = !{i32 2, !"Debug Info Version", i32 3} +!11 = !{i32 1, !"wchar_size", i32 4} +!12 = !{!"clang version 10.0.0 (https://github.com/llvm/llvm-project.git 907019d835895443b198afcd992c42c9d3478fdf)"} +!13 = distinct !DISubprogram(name: "test", scope: !1, file: !1, line: 3, type: !14, scopeLine: 3, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !16) +!14 = !DISubroutineType(types: !15) +!15 = !{!7, !8} +!16 = !{!17} +!17 = !DILocalVariable(name: "skb", arg: 1, scope: !13, file: !1, line: 3, type: !8) +!18 = !DILocation(line: 0, scope: !13) +!19 = !DILocation(line: 4, column: 10, scope: !13) +!20 = !DILocation(line: 4, column: 3, scope: !13) diff --git a/llvm/test/CodeGen/SBF/BTF/extern-func-arg.ll b/llvm/test/CodeGen/SBF/BTF/extern-func-arg.ll new file mode 100644 index 0000000000000..8196d60c527e4 --- /dev/null +++ b/llvm/test/CodeGen/SBF/BTF/extern-func-arg.ll @@ -0,0 +1,78 @@ +; RUN: llc -sbf-enable-btf-emission -march=sbf -filetype=asm -o - %s | FileCheck -check-prefixes=CHECK %s +; +; Source code: +; extern int global_func(char arg); +; int test() { return global_func(0); } +; Compilation flag: +; clang -target bpf -O2 -g -S -emit-llvm test.c + +; Function Attrs: nounwind +define dso_local i32 @test() local_unnamed_addr #0 !dbg !13 { +entry: + %call = tail call i32 @global_func(i8 signext 0) #2, !dbg !16 + ret i32 %call, !dbg !17 +} + +; CHECK: .short 60319 # 0xeb9f +; CHECK-NEXT: .byte 1 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .long 24 +; CHECK-NEXT: .long 0 +; CHECK-NEXT: .long 88 +; CHECK-NEXT: .long 88 +; CHECK-NEXT: .long 72 +; CHECK-NEXT: .long 0 # BTF_KIND_FUNC_PROTO(id = 1) +; CHECK-NEXT: .long 218103808 # 0xd000000 +; CHECK-NEXT: .long 2 +; CHECK-NEXT: .long 1 # BTF_KIND_INT(id = 2) +; CHECK-NEXT: .long 16777216 # 0x1000000 +; CHECK-NEXT: .long 4 +; CHECK-NEXT: .long 16777248 # 0x1000020 +; CHECK-NEXT: .long 5 # BTF_KIND_FUNC(id = 3) +; CHECK-NEXT: .long 201326593 # 0xc000001 +; CHECK-NEXT: .long 1 +; CHECK-NEXT: .long 0 # BTF_KIND_FUNC_PROTO(id = 4) +; CHECK-NEXT: .long 218103809 # 0xd000001 +; CHECK-NEXT: .long 2 +; CHECK-NEXT: .long 0 +; CHECK-NEXT: .long 5 +; CHECK-NEXT: .long 55 # BTF_KIND_INT(id = 5) +; CHECK-NEXT: .long 16777216 # 0x1000000 +; CHECK-NEXT: .long 1 +; CHECK-NEXT: .long 16777224 # 0x1000008 +; CHECK-NEXT: .long 60 # BTF_KIND_FUNC(id = 6) +; CHECK-NEXT: .long 201326594 # 0xc000002 +; CHECK-NEXT: .long 4 +; CHECK: .ascii "int" # string offset=1 +; CHECK: .ascii "test" # string offset=5 +; CHECK: .ascii "char" # string offset=55 +; CHECK: .ascii "global_func" # string offset=60 + +declare !dbg !4 dso_local i32 @global_func(i8 signext) local_unnamed_addr #1 + +attributes #0 = { nounwind "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" } +attributes #1 = { "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" } +attributes #2 = { nounwind } + +!llvm.dbg.cu = !{!0} +!llvm.module.flags = !{!9, !10, !11} +!llvm.ident = !{!12} + +!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 10.0.0 (https://github.com/llvm/llvm-project.git 987c5665e81822b32c895fd0c97a9a084b0d3106)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, retainedTypes: !3, splitDebugInlining: false, nameTableKind: None) +!1 = !DIFile(filename: "test.c", directory: "/tmp/home/yhs/work/tests/extern") +!2 = !{} +!3 = !{!4} +!4 = !DISubprogram(name: "global_func", scope: !1, file: !1, line: 1, type: !5, flags: DIFlagPrototyped, spFlags: DISPFlagOptimized, retainedNodes: !2) +!5 = !DISubroutineType(types: !6) +!6 = !{!7, !8} +!7 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +!8 = !DIBasicType(name: "char", size: 8, encoding: DW_ATE_signed_char) +!9 = !{i32 7, !"Dwarf Version", i32 4} +!10 = !{i32 2, !"Debug Info Version", i32 3} +!11 = !{i32 1, !"wchar_size", i32 4} +!12 = !{!"clang version 10.0.0 (https://github.com/llvm/llvm-project.git 987c5665e81822b32c895fd0c97a9a084b0d3106)"} +!13 = distinct !DISubprogram(name: "test", scope: !1, file: !1, line: 2, type: !14, scopeLine: 2, flags: DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !2) +!14 = !DISubroutineType(types: !15) +!15 = !{!7} +!16 = !DILocation(line: 2, column: 21, scope: !13) +!17 = !DILocation(line: 2, column: 14, scope: !13) diff --git a/llvm/test/CodeGen/SBF/BTF/extern-func-ptr.ll b/llvm/test/CodeGen/SBF/BTF/extern-func-ptr.ll new file mode 100644 index 0000000000000..90dffc95a1e30 --- /dev/null +++ b/llvm/test/CodeGen/SBF/BTF/extern-func-ptr.ll @@ -0,0 +1,75 @@ +; RUN: llc -sbf-enable-btf-emission -march=sbf -filetype=asm -o - %s | FileCheck -check-prefixes=CHECK %s +; +; Source code: +; extern int do_work(int) __attribute__((section(".callback_fn"))); +; long bpf_helper(void *callback_fn); +; long prog() { +; return bpf_helper(&do_work); +; } +; Compilation flag: +; clang -target bpf -O2 -g -S -emit-llvm test.c + +; Function Attrs: nounwind +define dso_local i64 @prog() local_unnamed_addr #0 !dbg !7 { +entry: + %call = tail call i64 @bpf_helper(i8* bitcast (i32 (i32)* @do_work to i8*)) #2, !dbg !11 + ret i64 %call, !dbg !12 +} + +; CHECK: .long 0 # BTF_KIND_FUNC_PROTO(id = 4) +; CHECK-NEXT: .long 218103809 # 0xd000001 +; CHECK-NEXT: .long 5 +; CHECK-NEXT: .long 0 +; CHECK-NEXT: .long 5 +; CHECK-NEXT: .long 51 # BTF_KIND_INT(id = 5) +; CHECK-NEXT: .long 16777216 # 0x1000000 +; CHECK-NEXT: .long 4 +; CHECK-NEXT: .long 16777248 # 0x1000020 +; CHECK-NEXT: .long 55 # BTF_KIND_FUNC(id = 6) +; CHECK-NEXT: .long 201326594 # 0xc000002 +; CHECK-NEXT: .long 4 + +; CHECK: .long 74 # BTF_KIND_DATASEC(id = 10) +; CHECK-NEXT: .long 251658241 # 0xf000001 +; CHECK-NEXT: .long 0 +; CHECK-NEXT: .long 6 +; CHECK-NEXT: .long do_work +; CHECK-NEXT: .long 0 + +; CHECK: .ascii "int" # string offset=51 +; CHECK: .ascii "do_work" # string offset=55 +; CHECK: .ascii ".callback_fn" # string offset=74 + +declare !dbg !13 dso_local i64 @bpf_helper(i8*) local_unnamed_addr #1 + +declare !dbg !17 dso_local i32 @do_work(i32) #1 section ".callback_fn" + +attributes #0 = { nounwind "frame-pointer"="all" "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" } +attributes #1 = { "frame-pointer"="all" "no-trapping-math"="true" "stack-protector-buffer-size"="8" } +attributes #2 = { nounwind } + +!llvm.dbg.cu = !{!0} +!llvm.module.flags = !{!3, !4, !5} +!llvm.ident = !{!6} + +!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 13.0.0 (https://github.com/llvm/llvm-project.git aa382ed8a38d5efa118e1b2617544f5c253658a9)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, splitDebugInlining: false, nameTableKind: None) +!1 = !DIFile(filename: "test.c", directory: "/tmp/home/yhs/btf/core") +!2 = !{} +!3 = !{i32 7, !"Dwarf Version", i32 4} +!4 = !{i32 2, !"Debug Info Version", i32 3} +!5 = !{i32 1, !"wchar_size", i32 4} +!6 = !{!"clang version 13.0.0 (https://github.com/llvm/llvm-project.git aa382ed8a38d5efa118e1b2617544f5c253658a9)"} +!7 = distinct !DISubprogram(name: "prog", scope: !1, file: !1, line: 3, type: !8, scopeLine: 3, flags: DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !2) +!8 = !DISubroutineType(types: !9) +!9 = !{!10} +!10 = !DIBasicType(name: "long int", size: 64, encoding: DW_ATE_signed) +!11 = !DILocation(line: 4, column: 12, scope: !7) +!12 = !DILocation(line: 4, column: 5, scope: !7) +!13 = !DISubprogram(name: "bpf_helper", scope: !1, file: !1, line: 2, type: !14, flags: DIFlagPrototyped, spFlags: DISPFlagOptimized, retainedNodes: !2) +!14 = !DISubroutineType(types: !15) +!15 = !{!10, !16} +!16 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: null, size: 64) +!17 = !DISubprogram(name: "do_work", scope: !1, file: !1, line: 1, type: !18, flags: DIFlagPrototyped, spFlags: DISPFlagOptimized, retainedNodes: !2) +!18 = !DISubroutineType(types: !19) +!19 = !{!20, !20} +!20 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) diff --git a/llvm/test/CodeGen/SBF/BTF/extern-global-var.ll b/llvm/test/CodeGen/SBF/BTF/extern-global-var.ll new file mode 100644 index 0000000000000..0388067026bbf --- /dev/null +++ b/llvm/test/CodeGen/SBF/BTF/extern-global-var.ll @@ -0,0 +1,68 @@ +; RUN: llc -sbf-enable-btf-emission -march=sbf -filetype=asm -o - %s | FileCheck -check-prefixes=CHECK %s + +; Source code: +; extern char a; +; int foo() { return a; } +; Compilation flag: +; clang -target bpf -O2 -g -S -emit-llvm test.c + +@a = external dso_local local_unnamed_addr global i8, align 1 + +; Function Attrs: norecurse nounwind readonly +define dso_local i32 @foo() local_unnamed_addr #0 !dbg !7 { + %1 = load i8, i8* @a, align 1, !dbg !11, !tbaa !12 + %2 = sext i8 %1 to i32, !dbg !11 + ret i32 %2, !dbg !15 +} + +; CHECK: .section .BTF,"",@progbits +; CHECK-NEXT: .short 60319 # 0xeb9f +; CHECK-NEXT: .byte 1 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .long 24 +; CHECK-NEXT: .long 0 +; CHECK-NEXT: .long 40 +; CHECK-NEXT: .long 40 +; CHECK-NEXT: .long 52 +; CHECK-NEXT: .long 0 # BTF_KIND_FUNC_PROTO(id = 1) +; CHECK-NEXT: .long 218103808 # 0xd000000 +; CHECK-NEXT: .long 2 +; CHECK-NEXT: .long 1 # BTF_KIND_INT(id = 2) +; CHECK-NEXT: .long 16777216 # 0x1000000 +; CHECK-NEXT: .long 4 +; CHECK-NEXT: .long 16777248 # 0x1000020 +; CHECK-NEXT: .long 5 # BTF_KIND_FUNC(id = 3) +; CHECK-NEXT: .long 201326593 # 0xc000001 +; CHECK-NEXT: .long 1 +; CHECK-NEXT: .byte 0 # string offset=0 +; CHECK-NEXT: .ascii "int" # string offset=1 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii "foo" # string offset=5 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii ".text" # string offset=9 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii "/home/yhs/work/tests/llvm/bug/test.c" # string offset=15 +; CHECK-NEXT: .byte 0 + +attributes #0 = { norecurse nounwind readonly "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "frame-pointer"="all" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" } + +!llvm.dbg.cu = !{!0} +!llvm.module.flags = !{!3, !4, !5} +!llvm.ident = !{!6} + +!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 8.0.20181009 ", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, nameTableKind: None) +!1 = !DIFile(filename: "test.c", directory: "/home/yhs/work/tests/llvm/bug") +!2 = !{} +!3 = !{i32 2, !"Dwarf Version", i32 4} +!4 = !{i32 2, !"Debug Info Version", i32 3} +!5 = !{i32 1, !"wchar_size", i32 4} +!6 = !{!"clang version 8.0.20181009 "} +!7 = distinct !DISubprogram(name: "foo", scope: !1, file: !1, line: 2, type: !8, isLocal: false, isDefinition: true, scopeLine: 2, isOptimized: true, unit: !0, retainedNodes: !2) +!8 = !DISubroutineType(types: !9) +!9 = !{!10} +!10 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +!11 = !DILocation(line: 2, column: 20, scope: !7) +!12 = !{!13, !13, i64 0} +!13 = !{!"omnipotent char", !14, i64 0} +!14 = !{!"Simple C/C++ TBAA"} +!15 = !DILocation(line: 2, column: 13, scope: !7) diff --git a/llvm/test/CodeGen/SBF/BTF/extern-var-func-weak-section.ll b/llvm/test/CodeGen/SBF/BTF/extern-var-func-weak-section.ll new file mode 100644 index 0000000000000..62a7ac77e88a9 --- /dev/null +++ b/llvm/test/CodeGen/SBF/BTF/extern-var-func-weak-section.ll @@ -0,0 +1,96 @@ +; RUN: llc -sbf-enable-btf-emission -march=sbf -filetype=asm -o - %s | FileCheck -check-prefixes=CHECK %s +; +; Source code: +; extern int global_func(char c) __attribute__((weak, section("abc"))); +; int test() { +; return global_func(0); +; } +; Compilation flag: +; clang -target bpf -O2 -g -S -emit-llvm test.c + +; Function Attrs: nounwind +define dso_local i32 @test() local_unnamed_addr #0 !dbg !13 { +entry: + %call = tail call i32 @global_func(i8 signext 0) #2, !dbg !16 + ret i32 %call, !dbg !17 +} +declare !dbg !4 extern_weak dso_local i32 @global_func(i8 signext) local_unnamed_addr #1 section "abc" + +; CHECK: .section .BTF,"",@progbits +; CHECK-NEXT: .short 60319 # 0xeb9f +; CHECK-NEXT: .byte 1 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .long 24 +; CHECK-NEXT: .long 0 +; CHECK-NEXT: .long 112 +; CHECK-NEXT: .long 112 +; CHECK-NEXT: .long 76 +; CHECK-NEXT: .long 0 # BTF_KIND_FUNC_PROTO(id = 1) +; CHECK-NEXT: .long 218103808 # 0xd000000 +; CHECK-NEXT: .long 2 +; CHECK-NEXT: .long 1 # BTF_KIND_INT(id = 2) +; CHECK-NEXT: .long 16777216 # 0x1000000 +; CHECK-NEXT: .long 4 +; CHECK-NEXT: .long 16777248 # 0x1000020 +; CHECK-NEXT: .long 5 # BTF_KIND_FUNC(id = 3) +; CHECK-NEXT: .long 201326593 # 0xc000001 +; CHECK-NEXT: .long 1 +; CHECK-NEXT: .long 0 # BTF_KIND_FUNC_PROTO(id = 4) +; CHECK-NEXT: .long 218103809 # 0xd000001 +; CHECK-NEXT: .long 2 +; CHECK-NEXT: .long 0 +; CHECK-NEXT: .long 5 +; CHECK-NEXT: .long 55 # BTF_KIND_INT(id = 5) +; CHECK-NEXT: .long 16777216 # 0x1000000 +; CHECK-NEXT: .long 1 +; CHECK-NEXT: .long 16777224 # 0x1000008 +; CHECK-NEXT: .long 60 # BTF_KIND_FUNC(id = 6) +; CHECK-NEXT: .long 201326594 # 0xc000002 +; CHECK-NEXT: .long 4 +; CHECK-NEXT: .long 72 # BTF_KIND_DATASEC(id = 7) +; CHECK-NEXT: .long 251658241 # 0xf000001 +; CHECK-NEXT: .long 0 +; CHECK-NEXT: .long 6 +; CHECK-NEXT: .long global_func +; CHECK-NEXT: .long 0 +; CHECK-NEXT: .byte 0 # string offset=0 +; CHECK-NEXT: .ascii "int" # string offset=1 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii "test" # string offset=5 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii ".text" # string offset=10 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii "/tmp/home/yhs/work/tests/extern/test.c" # string offset=16 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii "char" # string offset=55 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii "global_func" # string offset=60 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii "abc" # string offset=72 + +attributes #0 = { nounwind "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" } +attributes #1 = { "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" } +attributes #2 = { nounwind } + +!llvm.dbg.cu = !{!0} +!llvm.module.flags = !{!9, !10, !11} +!llvm.ident = !{!12} + +!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 10.0.0 (https://github.com/llvm/llvm-project.git 71a9518c93fe1dce9611c24bc707e5baf1f39f0d)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, retainedTypes: !3, nameTableKind: None) +!1 = !DIFile(filename: "test.c", directory: "/tmp/home/yhs/work/tests/extern") +!2 = !{} +!3 = !{!4} +!4 = !DISubprogram(name: "global_func", scope: !1, file: !1, line: 1, type: !5, flags: DIFlagPrototyped, spFlags: DISPFlagOptimized, retainedNodes: !2) +!5 = !DISubroutineType(types: !6) +!6 = !{!7, !8} +!7 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +!8 = !DIBasicType(name: "char", size: 8, encoding: DW_ATE_signed_char) +!9 = !{i32 7, !"Dwarf Version", i32 4} +!10 = !{i32 2, !"Debug Info Version", i32 3} +!11 = !{i32 1, !"wchar_size", i32 4} +!12 = !{!"clang version 10.0.0 (https://github.com/llvm/llvm-project.git 71a9518c93fe1dce9611c24bc707e5baf1f39f0d)"} +!13 = distinct !DISubprogram(name: "test", scope: !1, file: !1, line: 2, type: !14, scopeLine: 2, flags: DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !2) +!14 = !DISubroutineType(types: !15) +!15 = !{!7} +!16 = !DILocation(line: 3, column: 11, scope: !13) +!17 = !DILocation(line: 3, column: 4, scope: !13) diff --git a/llvm/test/CodeGen/SBF/BTF/extern-var-func-weak.ll b/llvm/test/CodeGen/SBF/BTF/extern-var-func-weak.ll new file mode 100644 index 0000000000000..d4ea7b139e702 --- /dev/null +++ b/llvm/test/CodeGen/SBF/BTF/extern-var-func-weak.ll @@ -0,0 +1,89 @@ +; RUN: llc -sbf-enable-btf-emission -march=sbf -filetype=asm -o - %s | FileCheck -check-prefixes=CHECK %s +; +; Source code: +; extern int global_func(char c) __attribute__((weak)); +; int test() { +; return global_func(0); +; } +; Compilation flag: +; clang -target bpf -O2 -g -S -emit-llvm test.c + +; Function Attrs: nounwind +define dso_local i32 @test() local_unnamed_addr #0 !dbg !13 { +entry: + %call = tail call i32 @global_func(i8 signext 0) #2, !dbg !16 + ret i32 %call, !dbg !17 +} +declare !dbg !4 extern_weak dso_local i32 @global_func(i8 signext) local_unnamed_addr #1 + +; CHECK: .section .BTF,"",@progbits +; CHECK-NEXT: .short 60319 # 0xeb9f +; CHECK-NEXT: .byte 1 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .long 24 +; CHECK-NEXT: .long 0 +; CHECK-NEXT: .long 88 +; CHECK-NEXT: .long 88 +; CHECK-NEXT: .long 72 +; CHECK-NEXT: .long 0 # BTF_KIND_FUNC_PROTO(id = 1) +; CHECK-NEXT: .long 218103808 # 0xd000000 +; CHECK-NEXT: .long 2 +; CHECK-NEXT: .long 1 # BTF_KIND_INT(id = 2) +; CHECK-NEXT: .long 16777216 # 0x1000000 +; CHECK-NEXT: .long 4 +; CHECK-NEXT: .long 16777248 # 0x1000020 +; CHECK-NEXT: .long 5 # BTF_KIND_FUNC(id = 3) +; CHECK-NEXT: .long 201326593 # 0xc000001 +; CHECK-NEXT: .long 1 +; CHECK-NEXT: .long 0 # BTF_KIND_FUNC_PROTO(id = 4) +; CHECK-NEXT: .long 218103809 # 0xd000001 +; CHECK-NEXT: .long 2 +; CHECK-NEXT: .long 0 +; CHECK-NEXT: .long 5 +; CHECK-NEXT: .long 55 # BTF_KIND_INT(id = 5) +; CHECK-NEXT: .long 16777216 # 0x1000000 +; CHECK-NEXT: .long 1 +; CHECK-NEXT: .long 16777224 # 0x1000008 +; CHECK-NEXT: .long 60 # BTF_KIND_FUNC(id = 6) +; CHECK-NEXT: .long 201326594 # 0xc000002 +; CHECK-NEXT: .long 4 +; CHECK-NEXT: .byte 0 # string offset=0 +; CHECK-NEXT: .ascii "int" # string offset=1 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii "test" # string offset=5 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii ".text" # string offset=10 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii "/tmp/home/yhs/work/tests/extern/test.c" # string offset=16 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii "char" # string offset=55 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii "global_func" # string offset=60 +; CHECK-NEXT: .byte 0 + +attributes #0 = { nounwind "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" } +attributes #1 = { "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" } +attributes #2 = { nounwind } + +!llvm.dbg.cu = !{!0} +!llvm.module.flags = !{!9, !10, !11} +!llvm.ident = !{!12} + +!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 10.0.0 (https://github.com/llvm/llvm-project.git 71a9518c93fe1dce9611c24bc707e5baf1f39f0d)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, retainedTypes: !3, nameTableKind: None) +!1 = !DIFile(filename: "test.c", directory: "/tmp/home/yhs/work/tests/extern") +!2 = !{} +!3 = !{!4} +!4 = !DISubprogram(name: "global_func", scope: !1, file: !1, line: 1, type: !5, flags: DIFlagPrototyped, spFlags: DISPFlagOptimized, retainedNodes: !2) +!5 = !DISubroutineType(types: !6) +!6 = !{!7, !8} +!7 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +!8 = !DIBasicType(name: "char", size: 8, encoding: DW_ATE_signed_char) +!9 = !{i32 7, !"Dwarf Version", i32 4} +!10 = !{i32 2, !"Debug Info Version", i32 3} +!11 = !{i32 1, !"wchar_size", i32 4} +!12 = !{!"clang version 10.0.0 (https://github.com/llvm/llvm-project.git 71a9518c93fe1dce9611c24bc707e5baf1f39f0d)"} +!13 = distinct !DISubprogram(name: "test", scope: !1, file: !1, line: 2, type: !14, scopeLine: 2, flags: DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !2) +!14 = !DISubroutineType(types: !15) +!15 = !{!7} +!16 = !DILocation(line: 3, column: 11, scope: !13) +!17 = !DILocation(line: 3, column: 4, scope: !13) diff --git a/llvm/test/CodeGen/SBF/BTF/extern-var-func.ll b/llvm/test/CodeGen/SBF/BTF/extern-var-func.ll new file mode 100644 index 0000000000000..d7e819b3d07b7 --- /dev/null +++ b/llvm/test/CodeGen/SBF/BTF/extern-var-func.ll @@ -0,0 +1,90 @@ +; RUN: llc -sbf-enable-btf-emission -march=sbf -filetype=asm -o - %s | FileCheck -check-prefixes=CHECK %s +; +; Source code: +; extern int global_func(char c); +; int test() { +; return global_func(0); +; } +; Compilation flag: +; clang -target bpf -O2 -g -S -emit-llvm test.c + +; Function Attrs: nounwind +define dso_local i32 @test() local_unnamed_addr #0 !dbg !13 { +entry: + %call = tail call i32 @global_func(i8 signext 0) #2, !dbg !16 + ret i32 %call, !dbg !17 +} + +; CHECK: .section .BTF,"",@progbits +; CHECK-NEXT: .short 60319 # 0xeb9f +; CHECK-NEXT: .byte 1 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .long 24 +; CHECK-NEXT: .long 0 +; CHECK-NEXT: .long 88 +; CHECK-NEXT: .long 88 +; CHECK-NEXT: .long 72 +; CHECK-NEXT: .long 0 # BTF_KIND_FUNC_PROTO(id = 1) +; CHECK-NEXT: .long 218103808 # 0xd000000 +; CHECK-NEXT: .long 2 +; CHECK-NEXT: .long 1 # BTF_KIND_INT(id = 2) +; CHECK-NEXT: .long 16777216 # 0x1000000 +; CHECK-NEXT: .long 4 +; CHECK-NEXT: .long 16777248 # 0x1000020 +; CHECK-NEXT: .long 5 # BTF_KIND_FUNC(id = 3) +; CHECK-NEXT: .long 201326593 # 0xc000001 +; CHECK-NEXT: .long 1 +; CHECK-NEXT: .long 0 # BTF_KIND_FUNC_PROTO(id = 4) +; CHECK-NEXT: .long 218103809 # 0xd000001 +; CHECK-NEXT: .long 2 +; CHECK-NEXT: .long 0 +; CHECK-NEXT: .long 5 +; CHECK-NEXT: .long 55 # BTF_KIND_INT(id = 5) +; CHECK-NEXT: .long 16777216 # 0x1000000 +; CHECK-NEXT: .long 1 +; CHECK-NEXT: .long 16777224 # 0x1000008 +; CHECK-NEXT: .long 60 # BTF_KIND_FUNC(id = 6) +; CHECK-NEXT: .long 201326594 # 0xc000002 +; CHECK-NEXT: .long 4 +; CHECK-NEXT: .byte 0 # string offset=0 +; CHECK-NEXT: .ascii "int" # string offset=1 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii "test" # string offset=5 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii ".text" # string offset=10 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii "/tmp/home/yhs/work/tests/extern/test.c" # string offset=16 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii "char" # string offset=55 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii "global_func" # string offset=60 +; CHECK-NEXT: .byte 0 + +declare !dbg !4 dso_local i32 @global_func(i8 signext) local_unnamed_addr #1 + +attributes #0 = { nounwind "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" } +attributes #1 = { "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" } +attributes #2 = { nounwind } + +!llvm.dbg.cu = !{!0} +!llvm.module.flags = !{!9, !10, !11} +!llvm.ident = !{!12} + +!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 10.0.0 (https://github.com/llvm/llvm-project.git 77e5c60f04c4597ba5704d3cee61c6d359404ccd)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, retainedTypes: !3, nameTableKind: None) +!1 = !DIFile(filename: "test.c", directory: "/tmp/home/yhs/work/tests/extern") +!2 = !{} +!3 = !{!4} +!4 = !DISubprogram(name: "global_func", scope: !1, file: !1, line: 1, type: !5, flags: DIFlagPrototyped, spFlags: DISPFlagOptimized, retainedNodes: !2) +!5 = !DISubroutineType(types: !6) +!6 = !{!7, !8} +!7 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +!8 = !DIBasicType(name: "char", size: 8, encoding: DW_ATE_signed_char) +!9 = !{i32 2, !"Dwarf Version", i32 4} +!10 = !{i32 2, !"Debug Info Version", i32 3} +!11 = !{i32 1, !"wchar_size", i32 4} +!12 = !{!"clang version 10.0.0 (https://github.com/llvm/llvm-project.git 77e5c60f04c4597ba5704d3cee61c6d359404ccd)"} +!13 = distinct !DISubprogram(name: "test", scope: !1, file: !1, line: 2, type: !14, scopeLine: 2, flags: DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !2) +!14 = !DISubroutineType(types: !15) +!15 = !{!7} +!16 = !DILocation(line: 3, column: 10, scope: !13) +!17 = !DILocation(line: 3, column: 3, scope: !13) diff --git a/llvm/test/CodeGen/SBF/BTF/extern-var-section.ll b/llvm/test/CodeGen/SBF/BTF/extern-var-section.ll new file mode 100644 index 0000000000000..3b078ac25b00d --- /dev/null +++ b/llvm/test/CodeGen/SBF/BTF/extern-var-section.ll @@ -0,0 +1,121 @@ +; RUN: llc -sbf-enable-btf-emission -march=sbf -filetype=asm -o - %s | FileCheck -check-prefixes=CHECK %s +; +; Source code: +; extern int global_func(char c) __attribute__((section("abc"))); +; extern char ch __attribute__((section("abc"))); +; int test() { +; return global_func(0) + ch; +; } +; Compilation flag: +; clang -target bpf -O2 -g -S -emit-llvm test.c + +@ch = external dso_local local_unnamed_addr global i8, section "abc", align 1, !dbg !0 + +; Function Attrs: nounwind +define dso_local i32 @test() local_unnamed_addr #0 !dbg !16 { +entry: + %call = tail call i32 @global_func(i8 signext 0) #2, !dbg !19 + %0 = load i8, i8* @ch, align 1, !dbg !20, !tbaa !21 + %conv = sext i8 %0 to i32, !dbg !20 + %add = add nsw i32 %call, %conv, !dbg !24 + ret i32 %add, !dbg !25 +} + +; CHECK: .section .BTF,"",@progbits +; CHECK-NEXT: .short 60319 # 0xeb9f +; CHECK-NEXT: .byte 1 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .long 24 +; CHECK-NEXT: .long 0 +; CHECK-NEXT: .long 140 +; CHECK-NEXT: .long 140 +; CHECK-NEXT: .long 79 +; CHECK-NEXT: .long 0 # BTF_KIND_FUNC_PROTO(id = 1) +; CHECK-NEXT: .long 218103808 # 0xd000000 +; CHECK-NEXT: .long 2 +; CHECK-NEXT: .long 1 # BTF_KIND_INT(id = 2) +; CHECK-NEXT: .long 16777216 # 0x1000000 +; CHECK-NEXT: .long 4 +; CHECK-NEXT: .long 16777248 # 0x1000020 +; CHECK-NEXT: .long 5 # BTF_KIND_FUNC(id = 3) +; CHECK-NEXT: .long 201326593 # 0xc000001 +; CHECK-NEXT: .long 1 +; CHECK-NEXT: .long 0 # BTF_KIND_FUNC_PROTO(id = 4) +; CHECK-NEXT: .long 218103809 # 0xd000001 +; CHECK-NEXT: .long 2 +; CHECK-NEXT: .long 0 +; CHECK-NEXT: .long 5 +; CHECK-NEXT: .long 55 # BTF_KIND_INT(id = 5) +; CHECK-NEXT: .long 16777216 # 0x1000000 +; CHECK-NEXT: .long 1 +; CHECK-NEXT: .long 16777224 # 0x1000008 +; CHECK-NEXT: .long 60 # BTF_KIND_FUNC(id = 6) +; CHECK-NEXT: .long 201326594 # 0xc000002 +; CHECK-NEXT: .long 4 +; CHECK-NEXT: .long 72 # BTF_KIND_VAR(id = 7) +; CHECK-NEXT: .long 234881024 # 0xe000000 +; CHECK-NEXT: .long 5 +; CHECK-NEXT: .long 2 +; CHECK-NEXT: .long 75 # BTF_KIND_DATASEC(id = 8) +; CHECK-NEXT: .long 251658242 # 0xf000002 +; CHECK-NEXT: .long 0 +; CHECK-NEXT: .long 6 +; CHECK-NEXT: .long global_func +; CHECK-NEXT: .long 0 +; CHECK-NEXT: .long 7 +; CHECK-NEXT: .long ch +; CHECK-NEXT: .long 1 +; CHECK-NEXT: .byte 0 # string offset=0 +; CHECK-NEXT: .ascii "int" # string offset=1 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii "test" # string offset=5 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii ".text" # string offset=10 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii "/tmp/home/yhs/work/tests/extern/test.c" # string offset=16 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii "char" # string offset=55 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii "global_func" # string offset=60 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii "ch" # string offset=72 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii "abc" # string offset=75 +; CHECK-NEXT: .byte 0 + +declare !dbg !6 dso_local i32 @global_func(i8 signext) local_unnamed_addr #1 section "abc" + +attributes #0 = { nounwind "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" } +attributes #1 = { "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" } +attributes #2 = { nounwind } + +!llvm.dbg.cu = !{!2} +!llvm.module.flags = !{!12, !13, !14} +!llvm.ident = !{!15} + +!0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression()) +!1 = distinct !DIGlobalVariable(name: "ch", scope: !2, file: !3, line: 2, type: !10, isLocal: false, isDefinition: false) +!2 = distinct !DICompileUnit(language: DW_LANG_C99, file: !3, producer: "clang version 10.0.0 (https://github.com/llvm/llvm-project.git 0ad024346185b3f0b5167438e126568982b1168d)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !4, retainedTypes: !5, globals: !11, nameTableKind: None) +!3 = !DIFile(filename: "test.c", directory: "/tmp/home/yhs/work/tests/extern") +!4 = !{} +!5 = !{!6} +!6 = !DISubprogram(name: "global_func", scope: !3, file: !3, line: 1, type: !7, flags: DIFlagPrototyped, spFlags: DISPFlagOptimized, retainedNodes: !4) +!7 = !DISubroutineType(types: !8) +!8 = !{!9, !10} +!9 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +!10 = !DIBasicType(name: "char", size: 8, encoding: DW_ATE_signed_char) +!11 = !{!0} +!12 = !{i32 2, !"Dwarf Version", i32 4} +!13 = !{i32 2, !"Debug Info Version", i32 3} +!14 = !{i32 1, !"wchar_size", i32 4} +!15 = !{!"clang version 10.0.0 (https://github.com/llvm/llvm-project.git 0ad024346185b3f0b5167438e126568982b1168d)"} +!16 = distinct !DISubprogram(name: "test", scope: !3, file: !3, line: 3, type: !17, scopeLine: 3, flags: DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !2, retainedNodes: !4) +!17 = !DISubroutineType(types: !18) +!18 = !{!9} +!19 = !DILocation(line: 4, column: 10, scope: !16) +!20 = !DILocation(line: 4, column: 27, scope: !16) +!21 = !{!22, !22, i64 0} +!22 = !{!"omnipotent char", !23, i64 0} +!23 = !{!"Simple C/C++ TBAA"} +!24 = !DILocation(line: 4, column: 25, scope: !16) +!25 = !DILocation(line: 4, column: 3, scope: !16) diff --git a/llvm/test/CodeGen/SBF/BTF/extern-var-struct-weak.ll b/llvm/test/CodeGen/SBF/BTF/extern-var-struct-weak.ll new file mode 100644 index 0000000000000..78100b5730e56 --- /dev/null +++ b/llvm/test/CodeGen/SBF/BTF/extern-var-struct-weak.ll @@ -0,0 +1,100 @@ +; RUN: llc -sbf-enable-btf-emission -march=sbf -filetype=asm -o - %s | FileCheck -check-prefixes=CHECK %s +; +; Source code: +; typedef struct t1 { int f1; } __t1; +; extern __t1 global __attribute__((weak)); +; int test() { return global.f1; } +; Compilation flag: +; clang -target bpf -O2 -g -S -emit-llvm test.c + +%struct.t1 = type { i32 } + +@global = extern_weak dso_local local_unnamed_addr global %struct.t1, align 4, !dbg !0 +; Function Attrs: norecurse nounwind readonly +define dso_local i32 @test() local_unnamed_addr #0 !dbg !15 { +entry: + %0 = load i32, i32* getelementptr (%struct.t1, %struct.t1* @global, i64 0, i32 0), align 4, !dbg !18, !tbaa !19 + ret i32 %0, !dbg !24 +} + +; CHECK: .section .BTF,"",@progbits +; CHECK-NEXT: .short 60319 # 0xeb9f +; CHECK-NEXT: .byte 1 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .long 24 +; CHECK-NEXT: .long 0 +; CHECK-NEXT: .long 92 +; CHECK-NEXT: .long 92 +; CHECK-NEXT: .long 73 +; CHECK-NEXT: .long 0 # BTF_KIND_FUNC_PROTO(id = 1) +; CHECK-NEXT: .long 218103808 # 0xd000000 +; CHECK-NEXT: .long 2 +; CHECK-NEXT: .long 1 # BTF_KIND_INT(id = 2) +; CHECK-NEXT: .long 16777216 # 0x1000000 +; CHECK-NEXT: .long 4 +; CHECK-NEXT: .long 16777248 # 0x1000020 +; CHECK-NEXT: .long 5 # BTF_KIND_FUNC(id = 3) +; CHECK-NEXT: .long 201326593 # 0xc000001 +; CHECK-NEXT: .long 1 +; CHECK-NEXT: .long 55 # BTF_KIND_TYPEDEF(id = 4) +; CHECK-NEXT: .long 134217728 # 0x8000000 +; CHECK-NEXT: .long 5 +; CHECK-NEXT: .long 60 # BTF_KIND_STRUCT(id = 5) +; CHECK-NEXT: .long 67108865 # 0x4000001 +; CHECK-NEXT: .long 4 +; CHECK-NEXT: .long 63 +; CHECK-NEXT: .long 2 +; CHECK-NEXT: .long 0 # 0x0 +; CHECK-NEXT: .long 66 # BTF_KIND_VAR(id = 6) +; CHECK-NEXT: .long 234881024 # 0xe000000 +; CHECK-NEXT: .long 4 +; CHECK-NEXT: .long 2 +; CHECK-NEXT: .byte 0 # string offset=0 +; CHECK-NEXT: .ascii "int" # string offset=1 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii "test" # string offset=5 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii ".text" # string offset=10 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii "/tmp/home/yhs/work/tests/extern/test.c" # string offset=16 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii "__t1" # string offset=55 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii "t1" # string offset=60 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii "f1" # string offset=63 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii "global" # string offset=66 +; CHECK-NEXT: .byte 0 + +attributes #0 = { norecurse nounwind readonly "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" } + +!llvm.dbg.cu = !{!2} +!llvm.module.flags = !{!11, !12, !13} +!llvm.ident = !{!14} + +!0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression()) +!1 = distinct !DIGlobalVariable(name: "global", scope: !2, file: !3, line: 2, type: !6, isLocal: false, isDefinition: false) +!2 = distinct !DICompileUnit(language: DW_LANG_C99, file: !3, producer: "clang version 10.0.0 (https://github.com/llvm/llvm-project.git 71a9518c93fe1dce9611c24bc707e5baf1f39f0d)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !4, globals: !5, nameTableKind: None) +!3 = !DIFile(filename: "test.c", directory: "/tmp/home/yhs/work/tests/extern") +!4 = !{} +!5 = !{!0} +!6 = !DIDerivedType(tag: DW_TAG_typedef, name: "__t1", file: !3, line: 1, baseType: !7) +!7 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "t1", file: !3, line: 1, size: 32, elements: !8) +!8 = !{!9} +!9 = !DIDerivedType(tag: DW_TAG_member, name: "f1", scope: !7, file: !3, line: 1, baseType: !10, size: 32) +!10 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +!11 = !{i32 7, !"Dwarf Version", i32 4} +!12 = !{i32 2, !"Debug Info Version", i32 3} +!13 = !{i32 1, !"wchar_size", i32 4} +!14 = !{!"clang version 10.0.0 (https://github.com/llvm/llvm-project.git 71a9518c93fe1dce9611c24bc707e5baf1f39f0d)"} +!15 = distinct !DISubprogram(name: "test", scope: !3, file: !3, line: 3, type: !16, scopeLine: 3, flags: DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !2, retainedNodes: !4) +!16 = !DISubroutineType(types: !17) +!17 = !{!10} +!18 = !DILocation(line: 3, column: 28, scope: !15) +!19 = !{!20, !21, i64 0} +!20 = !{!"t1", !21, i64 0} +!21 = !{!"int", !22, i64 0} +!22 = !{!"omnipotent char", !23, i64 0} +!23 = !{!"Simple C/C++ TBAA"} +!24 = !DILocation(line: 3, column: 14, scope: !15) diff --git a/llvm/test/CodeGen/SBF/BTF/extern-var-struct.ll b/llvm/test/CodeGen/SBF/BTF/extern-var-struct.ll new file mode 100644 index 0000000000000..45988465b9d66 --- /dev/null +++ b/llvm/test/CodeGen/SBF/BTF/extern-var-struct.ll @@ -0,0 +1,101 @@ +; RUN: llc -sbf-enable-btf-emission -march=sbf -filetype=asm -o - %s | FileCheck -check-prefixes=CHECK %s +; +; Source code: +; typedef struct t1 { int f1; } __t1; +; extern __t1 global; +; int test() { return global.f1; } +; Compilation flag: +; clang -target bpf -O2 -g -S -emit-llvm test.c + +%struct.t1 = type { i32 } + +@global = external dso_local local_unnamed_addr global %struct.t1, align 4, !dbg !0 + +; Function Attrs: norecurse nounwind readonly +define dso_local i32 @test() local_unnamed_addr #0 !dbg !15 { +entry: + %0 = load i32, i32* getelementptr inbounds (%struct.t1, %struct.t1* @global, i64 0, i32 0), align 4, !dbg !18, !tbaa !19 + ret i32 %0, !dbg !24 +} + +; CHECK: .section .BTF,"",@progbits +; CHECK-NEXT: .short 60319 # 0xeb9f +; CHECK-NEXT: .byte 1 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .long 24 +; CHECK-NEXT: .long 0 +; CHECK-NEXT: .long 92 +; CHECK-NEXT: .long 92 +; CHECK-NEXT: .long 73 +; CHECK-NEXT: .long 0 # BTF_KIND_FUNC_PROTO(id = 1) +; CHECK-NEXT: .long 218103808 # 0xd000000 +; CHECK-NEXT: .long 2 +; CHECK-NEXT: .long 1 # BTF_KIND_INT(id = 2) +; CHECK-NEXT: .long 16777216 # 0x1000000 +; CHECK-NEXT: .long 4 +; CHECK-NEXT: .long 16777248 # 0x1000020 +; CHECK-NEXT: .long 5 # BTF_KIND_FUNC(id = 3) +; CHECK-NEXT: .long 201326593 # 0xc000001 +; CHECK-NEXT: .long 1 +; CHECK-NEXT: .long 55 # BTF_KIND_TYPEDEF(id = 4) +; CHECK-NEXT: .long 134217728 # 0x8000000 +; CHECK-NEXT: .long 5 +; CHECK-NEXT: .long 60 # BTF_KIND_STRUCT(id = 5) +; CHECK-NEXT: .long 67108865 # 0x4000001 +; CHECK-NEXT: .long 4 +; CHECK-NEXT: .long 63 +; CHECK-NEXT: .long 2 +; CHECK-NEXT: .long 0 # 0x0 +; CHECK-NEXT: .long 66 # BTF_KIND_VAR(id = 6) +; CHECK-NEXT: .long 234881024 # 0xe000000 +; CHECK-NEXT: .long 4 +; CHECK-NEXT: .long 2 +; CHECK-NEXT: .byte 0 # string offset=0 +; CHECK-NEXT: .ascii "int" # string offset=1 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii "test" # string offset=5 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii ".text" # string offset=10 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii "/tmp/home/yhs/work/tests/extern/test.c" # string offset=16 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii "__t1" # string offset=55 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii "t1" # string offset=60 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii "f1" # string offset=63 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii "global" # string offset=66 +; CHECK-NEXT: .byte 0 + +attributes #0 = { norecurse nounwind readonly "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" } + +!llvm.dbg.cu = !{!2} +!llvm.module.flags = !{!11, !12, !13} +!llvm.ident = !{!14} + +!0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression()) +!1 = distinct !DIGlobalVariable(name: "global", scope: !2, file: !3, line: 2, type: !6, isLocal: false, isDefinition: false) +!2 = distinct !DICompileUnit(language: DW_LANG_C99, file: !3, producer: "clang version 10.0.0 (https://github.com/llvm/llvm-project.git 2798d63180f4cc873bdaf689705fd4f9521ae89f)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !4, globals: !5, nameTableKind: None) +!3 = !DIFile(filename: "test.c", directory: "/tmp/home/yhs/work/tests/extern") +!4 = !{} +!5 = !{!0} +!6 = !DIDerivedType(tag: DW_TAG_typedef, name: "__t1", file: !3, line: 1, baseType: !7) +!7 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "t1", file: !3, line: 1, size: 32, elements: !8) +!8 = !{!9} +!9 = !DIDerivedType(tag: DW_TAG_member, name: "f1", scope: !7, file: !3, line: 1, baseType: !10, size: 32) +!10 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +!11 = !{i32 2, !"Dwarf Version", i32 4} +!12 = !{i32 2, !"Debug Info Version", i32 3} +!13 = !{i32 1, !"wchar_size", i32 4} +!14 = !{!"clang version 10.0.0 (https://github.com/llvm/llvm-project.git 2798d63180f4cc873bdaf689705fd4f9521ae89f)"} +!15 = distinct !DISubprogram(name: "test", scope: !3, file: !3, line: 4, type: !16, scopeLine: 4, flags: DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !2, retainedNodes: !4) +!16 = !DISubroutineType(types: !17) +!17 = !{!10} +!18 = !DILocation(line: 4, column: 28, scope: !15) +!19 = !{!20, !21, i64 0} +!20 = !{!"t1", !21, i64 0} +!21 = !{!"int", !22, i64 0} +!22 = !{!"omnipotent char", !23, i64 0} +!23 = !{!"Simple C/C++ TBAA"} +!24 = !DILocation(line: 4, column: 14, scope: !15) diff --git a/llvm/test/CodeGen/SBF/BTF/extern-var-weak-section.ll b/llvm/test/CodeGen/SBF/BTF/extern-var-weak-section.ll new file mode 100644 index 0000000000000..39a1dcf9241a5 --- /dev/null +++ b/llvm/test/CodeGen/SBF/BTF/extern-var-weak-section.ll @@ -0,0 +1,119 @@ +; RUN: llc -sbf-enable-btf-emission -march=sbf -filetype=asm -o - %s | FileCheck -check-prefixes=CHECK %s +; +; Source code: +; extern int global_func(char c) __attribute__((weak, section("abc"))); +; extern char ch __attribute__((weak, section("abc"))); +; int test() { +; return global_func(0) + ch; +; } +; Compilation flag: +; clang -target bpf -O2 -g -S -emit-llvm test.c + +@ch = extern_weak dso_local local_unnamed_addr global i8, section "abc", align 1, !dbg !0 +; Function Attrs: nounwind +define dso_local i32 @test() local_unnamed_addr #0 !dbg !16 { +entry: + %call = tail call i32 @global_func(i8 signext 0) #2, !dbg !19 + %0 = load i8, i8* @ch, align 1, !dbg !20, !tbaa !21 + %conv = sext i8 %0 to i32, !dbg !20 + %add = add nsw i32 %call, %conv, !dbg !24 + ret i32 %add, !dbg !25 +} +declare !dbg !6 extern_weak dso_local i32 @global_func(i8 signext) local_unnamed_addr #1 section "abc" + +; CHECK: .section .BTF,"",@progbits +; CHECK-NEXT: .short 60319 # 0xeb9f +; CHECK-NEXT: .byte 1 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .long 24 +; CHECK-NEXT: .long 0 +; CHECK-NEXT: .long 140 +; CHECK-NEXT: .long 140 +; CHECK-NEXT: .long 79 +; CHECK-NEXT: .long 0 # BTF_KIND_FUNC_PROTO(id = 1) +; CHECK-NEXT: .long 218103808 # 0xd000000 +; CHECK-NEXT: .long 2 +; CHECK-NEXT: .long 1 # BTF_KIND_INT(id = 2) +; CHECK-NEXT: .long 16777216 # 0x1000000 +; CHECK-NEXT: .long 4 +; CHECK-NEXT: .long 16777248 # 0x1000020 +; CHECK-NEXT: .long 5 # BTF_KIND_FUNC(id = 3) +; CHECK-NEXT: .long 201326593 # 0xc000001 +; CHECK-NEXT: .long 1 +; CHECK-NEXT: .long 0 # BTF_KIND_FUNC_PROTO(id = 4) +; CHECK-NEXT: .long 218103809 # 0xd000001 +; CHECK-NEXT: .long 2 +; CHECK-NEXT: .long 0 +; CHECK-NEXT: .long 5 +; CHECK-NEXT: .long 55 # BTF_KIND_INT(id = 5) +; CHECK-NEXT: .long 16777216 # 0x1000000 +; CHECK-NEXT: .long 1 +; CHECK-NEXT: .long 16777224 # 0x1000008 +; CHECK-NEXT: .long 60 # BTF_KIND_FUNC(id = 6) +; CHECK-NEXT: .long 201326594 # 0xc000002 +; CHECK-NEXT: .long 4 +; CHECK-NEXT: .long 72 # BTF_KIND_VAR(id = 7) +; CHECK-NEXT: .long 234881024 # 0xe000000 +; CHECK-NEXT: .long 5 +; CHECK-NEXT: .long 2 +; CHECK-NEXT: .long 75 # BTF_KIND_DATASEC(id = 8) +; CHECK-NEXT: .long 251658242 # 0xf000002 +; CHECK-NEXT: .long 0 +; CHECK-NEXT: .long 6 +; CHECK-NEXT: .long global_func +; CHECK-NEXT: .long 0 +; CHECK-NEXT: .long 7 +; CHECK-NEXT: .long ch +; CHECK-NEXT: .long 1 +; CHECK-NEXT: .byte 0 # string offset=0 +; CHECK-NEXT: .ascii "int" # string offset=1 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii "test" # string offset=5 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii ".text" # string offset=10 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii "/tmp/home/yhs/work/tests/extern/test.c" # string offset=16 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii "char" # string offset=55 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii "global_func" # string offset=60 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii "ch" # string offset=72 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii "abc" # string offset=75 +; CHECK-NEXT: .byte 0 + +attributes #0 = { nounwind "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" } +attributes #1 = { "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" } +attributes #2 = { nounwind } + +!llvm.dbg.cu = !{!2} +!llvm.module.flags = !{!12, !13, !14} +!llvm.ident = !{!15} + +!0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression()) +!1 = distinct !DIGlobalVariable(name: "ch", scope: !2, file: !3, line: 2, type: !10, isLocal: false, isDefinition: false) +!2 = distinct !DICompileUnit(language: DW_LANG_C99, file: !3, producer: "clang version 10.0.0 (https://github.com/llvm/llvm-project.git 71a9518c93fe1dce9611c24bc707e5baf1f39f0d)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !4, retainedTypes: !5, globals: !11, nameTableKind: None) +!3 = !DIFile(filename: "test.c", directory: "/tmp/home/yhs/work/tests/extern") +!4 = !{} +!5 = !{!6} +!6 = !DISubprogram(name: "global_func", scope: !3, file: !3, line: 1, type: !7, flags: DIFlagPrototyped, spFlags: DISPFlagOptimized, retainedNodes: !4) +!7 = !DISubroutineType(types: !8) +!8 = !{!9, !10} +!9 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +!10 = !DIBasicType(name: "char", size: 8, encoding: DW_ATE_signed_char) +!11 = !{!0} +!12 = !{i32 7, !"Dwarf Version", i32 4} +!13 = !{i32 2, !"Debug Info Version", i32 3} +!14 = !{i32 1, !"wchar_size", i32 4} +!15 = !{!"clang version 10.0.0 (https://github.com/llvm/llvm-project.git 71a9518c93fe1dce9611c24bc707e5baf1f39f0d)"} +!16 = distinct !DISubprogram(name: "test", scope: !3, file: !3, line: 3, type: !17, scopeLine: 3, flags: DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !2, retainedNodes: !4) +!17 = !DISubroutineType(types: !18) +!18 = !{!9} +!19 = !DILocation(line: 4, column: 10, scope: !16) +!20 = !DILocation(line: 4, column: 27, scope: !16) +!21 = !{!22, !22, i64 0} +!22 = !{!"omnipotent char", !23, i64 0} +!23 = !{!"Simple C/C++ TBAA"} +!24 = !DILocation(line: 4, column: 25, scope: !16) +!25 = !DILocation(line: 4, column: 3, scope: !16) diff --git a/llvm/test/CodeGen/SBF/BTF/filename.ll b/llvm/test/CodeGen/SBF/BTF/filename.ll new file mode 100644 index 0000000000000..170e079353175 --- /dev/null +++ b/llvm/test/CodeGen/SBF/BTF/filename.ll @@ -0,0 +1,82 @@ +; RUN: llc -sbf-enable-btf-emission -march=sbf -filetype=asm -o - %s | FileCheck -check-prefixes=CHECK %s + +; Source code: +; int test() { return 0; } +; Compilation flag: +; clang -target bpf -O2 -g -S -emit-llvm t.c + +; Function Attrs: norecurse nounwind readnone uwtable +define dso_local i32 @test() local_unnamed_addr #0 !dbg !7 { + ret i32 0, !dbg !11 +} + +; CHECK: .section .BTF,"",@progbits +; CHECK-NEXT: .short 60319 # 0xeb9f +; CHECK-NEXT: .byte 1 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .long 24 +; CHECK-NEXT: .long 0 +; CHECK-NEXT: .long 40 +; CHECK-NEXT: .long 40 +; CHECK-NEXT: .long 35 +; CHECK-NEXT: .long 0 # BTF_KIND_FUNC_PROTO(id = 1) +; CHECK-NEXT: .long 218103808 # 0xd000000 +; CHECK-NEXT: .long 2 +; CHECK-NEXT: .long 1 # BTF_KIND_INT(id = 2) +; CHECK-NEXT: .long 16777216 # 0x1000000 +; CHECK-NEXT: .long 4 +; CHECK-NEXT: .long 16777248 # 0x1000020 +; CHECK-NEXT: .long 5 # BTF_KIND_FUNC(id = 3) +; CHECK-NEXT: .long 201326593 # 0xc000001 +; CHECK-NEXT: .long 1 +; CHECK-NEXT: .byte 0 # string offset=0 +; CHECK-NEXT: .ascii "int" # string offset=1 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii "test" # string offset=5 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii ".text" # string offset=10 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii "/home/yhs/ttmp/t.c" # string offset=16 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .section .BTF.ext,"",@progbits +; CHECK-NEXT: .short 60319 # 0xeb9f +; CHECK-NEXT: .byte 1 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .long 32 +; CHECK-NEXT: .long 0 +; CHECK-NEXT: .long 20 +; CHECK-NEXT: .long 20 +; CHECK-NEXT: .long 28 +; CHECK-NEXT: .long 48 +; CHECK-NEXT: .long 0 +; CHECK-NEXT: .long 8 # FuncInfo +; CHECK-NEXT: .long 10 # FuncInfo section string offset=10 +; CHECK-NEXT: .long 1 +; CHECK-NEXT: .long .Lfunc_begin{{[0-9]+}} +; CHECK-NEXT: .long 3 +; CHECK-NEXT: .long 16 # LineInfo +; CHECK-NEXT: .long 10 # LineInfo section string offset=10 +; CHECK-NEXT: .long 1 +; CHECK-NEXT: .long .Ltmp{{[0-9]+}} +; CHECK-NEXT: .long 16 +; CHECK-NEXT: .long 0 +; CHECK-NEXT: .long 1038 # Line 1 Col 14 + +attributes #0 = { norecurse nounwind readnone uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "frame-pointer"="none" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+fxsr,+mmx,+sse,+sse2,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } + +!llvm.dbg.cu = !{!0} +!llvm.module.flags = !{!3, !4, !5} +!llvm.ident = !{!6} + +!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 8.0.20181009 ", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, nameTableKind: None) +!1 = !DIFile(filename: "/home/yhs/ttmp/t.c", directory: "/home/yhs/ttmp") +!2 = !{} +!3 = !{i32 2, !"Dwarf Version", i32 4} +!4 = !{i32 2, !"Debug Info Version", i32 3} +!5 = !{i32 1, !"wchar_size", i32 4} +!6 = !{!"clang version 8.0.20181009 "} +!7 = distinct !DISubprogram(name: "test", scope: !1, file: !1, line: 1, type: !8, isLocal: false, isDefinition: true, scopeLine: 1, isOptimized: true, unit: !0, retainedNodes: !2) +!8 = !DISubroutineType(types: !9) +!9 = !{!10} +!10 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +!11 = !DILocation(line: 1, column: 14, scope: !7) diff --git a/llvm/test/CodeGen/SBF/BTF/float.ll b/llvm/test/CodeGen/SBF/BTF/float.ll new file mode 100644 index 0000000000000..df2e19d2ccb8f --- /dev/null +++ b/llvm/test/CodeGen/SBF/BTF/float.ll @@ -0,0 +1,57 @@ +; RUN: llc -sbf-enable-btf-emission -march=sbf -filetype=asm -o - %s | FileCheck -check-prefixes=CHECK %s + +; Source code: +; float a; +; Compilation flag: +; clang -target bpf -O2 -g -S -emit-llvm t.c + +@a = dso_local local_unnamed_addr global float 0.000000e+00, align 4, !dbg !0 + +!llvm.dbg.cu = !{!2} +!llvm.module.flags = !{!7, !8, !9} +!llvm.ident = !{!10} + +; CHECK: .section .BTF,"",@progbits +; CHECK-NEXT: .short 60319 # 0xeb9f +; CHECK-NEXT: .byte 1 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .long 24 +; CHECK-NEXT: .long 0 +; CHECK-NEXT: .long 52 +; CHECK-NEXT: .long 52 +; CHECK-NEXT: .long 14 +; [1] float, size=4 bytes (32 bits) +; CHECK-NEXT: .long 1 # BTF_KIND_FLOAT(id = 1) +; CHECK-NEXT: .long 268435456 # 0x10000000 +; CHECK-NEXT: .long 4 +; [2] a, type=float (1), global +; CHECK-NEXT: .long 7 # BTF_KIND_VAR(id = 2) +; CHECK-NEXT: .long 234881024 # 0xe000000 +; CHECK-NEXT: .long 1 +; CHECK-NEXT: .long 1 +; [3] .bss, 1 var, {a, offset=&a, size=4 bytes} +; CHECK-NEXT: .long 9 # BTF_KIND_DATASEC(id = 3) +; CHECK-NEXT: .long 251658241 # 0xf000001 +; CHECK-NEXT: .long 0 +; CHECK-NEXT: .long 2 +; CHECK-NEXT: .long a +; CHECK-NEXT: .long 4 +; CHECK-NEXT: .byte 0 # string offset=0 +; CHECK-NEXT: .ascii "float" # string offset=1 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .byte 97 # string offset=7 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii ".bss" # string offset=9 +; CHECK-NEXT: .byte 0 + +!0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression()) +!1 = distinct !DIGlobalVariable(name: "a", scope: !2, file: !3, line: 1, type: !6, isLocal: false, isDefinition: true) +!2 = distinct !DICompileUnit(language: DW_LANG_C99, file: !3, producer: "clang version 11.0.0 ", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !4, globals: !5, splitDebugInlining: false, nameTableKind: None) +!3 = !DIFile(filename: "t.c", directory: "/home/yhs/tmp") +!4 = !{} +!5 = !{!0} +!6 = !DIBasicType(name: "float", size: 32, encoding: DW_ATE_float) +!7 = !{i32 7, !"Dwarf Version", i32 4} +!8 = !{i32 2, !"Debug Info Version", i32 3} +!9 = !{i32 1, !"wchar_size", i32 4} +!10 = !{!"clang version 11.0.0 "} diff --git a/llvm/test/CodeGen/SBF/BTF/func-func-ptr.ll b/llvm/test/CodeGen/SBF/BTF/func-func-ptr.ll new file mode 100644 index 0000000000000..a8fa3a5361eef --- /dev/null +++ b/llvm/test/CodeGen/SBF/BTF/func-func-ptr.ll @@ -0,0 +1,129 @@ +; RUN: llc -sbf-enable-btf-emission -march=sbf -filetype=asm -o - %s | FileCheck -check-prefixes=CHECK %s + +; Source code: +; void (*a1)(int p1); +; struct t1 { void (*a1)(int p1); } b1; +; void f1(int p2) { } +; Compilation flag: +; clang -target bpf -O2 -g -S -emit-llvm t.c + +%struct.t1 = type { void (i32)* } + +@a1 = common dso_local local_unnamed_addr global void (i32)* null, align 8, !dbg !0 +@b1 = common dso_local local_unnamed_addr global %struct.t1 zeroinitializer, align 8, !dbg !6 + +; Function Attrs: nounwind readnone +define dso_local void @f1(i32 %p2) local_unnamed_addr #0 !dbg !19 { +entry: + call void @llvm.dbg.value(metadata i32 %p2, metadata !21, metadata !DIExpression()), !dbg !22 + ret void, !dbg !23 +} + +; CHECK: .section .BTF,"",@progbits +; CHECK-NEXT: .short 60319 # 0xeb9f +; CHECK-NEXT: .byte 1 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .long 24 +; CHECK-NEXT: .long 0 +; CHECK-NEXT: .long 104 +; CHECK-NEXT: .long 104 +; CHECK-NEXT: .long 32 +; CHECK-NEXT: .long 1 # BTF_KIND_INT(id = 1) +; CHECK-NEXT: .long 16777216 # 0x1000000 +; CHECK-NEXT: .long 4 +; CHECK-NEXT: .long 16777248 # 0x1000020 +; CHECK-NEXT: .long 0 # BTF_KIND_FUNC_PROTO(id = 2) +; CHECK-NEXT: .long 218103809 # 0xd000001 +; CHECK-NEXT: .long 0 +; CHECK-NEXT: .long 5 +; CHECK-NEXT: .long 1 +; CHECK-NEXT: .long 8 # BTF_KIND_FUNC(id = 3) +; CHECK-NEXT: .long 201326593 # 0xc000001 +; CHECK-NEXT: .long 2 +; CHECK-NEXT: .long 0 # BTF_KIND_PTR(id = 4) +; CHECK-NEXT: .long 33554432 # 0x2000000 +; CHECK-NEXT: .long 5 +; CHECK-NEXT: .long 0 # BTF_KIND_FUNC_PROTO(id = 5) +; CHECK-NEXT: .long 218103809 # 0xd000001 +; CHECK-NEXT: .long 0 +; CHECK-NEXT: .long 0 +; CHECK-NEXT: .long 1 +; CHECK-NEXT: .long 26 # BTF_KIND_STRUCT(id = 6) +; CHECK-NEXT: .long 67108865 # 0x4000001 +; CHECK-NEXT: .long 8 +; CHECK-NEXT: .long 29 +; CHECK-NEXT: .long 4 +; CHECK-NEXT: .long 0 # 0x0 +; CHECK-NEXT: .byte 0 # string offset=0 +; CHECK-NEXT: .ascii "int" # string offset=1 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii "p2" # string offset=5 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii "f1" # string offset=8 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii ".text" # string offset=11 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii "/tmp/t.c" # string offset=17 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii "t1" # string offset=26 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii "a1" # string offset=29 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .section .BTF.ext,"",@progbits +; CHECK-NEXT: .short 60319 # 0xeb9f +; CHECK-NEXT: .byte 1 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .long 32 +; CHECK-NEXT: .long 0 +; CHECK-NEXT: .long 20 +; CHECK-NEXT: .long 20 +; CHECK-NEXT: .long 28 +; CHECK-NEXT: .long 48 +; CHECK-NEXT: .long 0 +; CHECK-NEXT: .long 8 # FuncInfo +; CHECK-NEXT: .long 11 # FuncInfo section string offset=11 +; CHECK-NEXT: .long 1 +; CHECK-NEXT: .long .Lfunc_begin0 +; CHECK-NEXT: .long 3 +; CHECK-NEXT: .long 16 # LineInfo +; CHECK-NEXT: .long 11 # LineInfo section string offset=11 +; CHECK-NEXT: .long 1 +; CHECK-NEXT: .long .Ltmp{{[0-9]+}} +; CHECK-NEXT: .long 17 +; CHECK-NEXT: .long 0 +; CHECK-NEXT: .long 3091 # Line 3 Col 19 + +; Function Attrs: nounwind readnone speculatable +declare void @llvm.dbg.value(metadata, metadata, metadata) #1 + +attributes #0 = { nounwind readnone "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "frame-pointer"="all" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" } +attributes #1 = { nounwind readnone speculatable } + +!llvm.dbg.cu = !{!2} +!llvm.module.flags = !{!15, !16, !17} +!llvm.ident = !{!18} + +!0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression()) +!1 = distinct !DIGlobalVariable(name: "a1", scope: !2, file: !3, line: 1, type: !11, isLocal: false, isDefinition: true) +!2 = distinct !DICompileUnit(language: DW_LANG_C99, file: !3, producer: "clang version 8.0.0 (trunk 345296) (llvm/trunk 345297)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !4, globals: !5, nameTableKind: None) +!3 = !DIFile(filename: "t.c", directory: "/tmp") +!4 = !{} +!5 = !{!0, !6} +!6 = !DIGlobalVariableExpression(var: !7, expr: !DIExpression()) +!7 = distinct !DIGlobalVariable(name: "b1", scope: !2, file: !3, line: 2, type: !8, isLocal: false, isDefinition: true) +!8 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "t1", file: !3, line: 2, size: 64, elements: !9) +!9 = !{!10} +!10 = !DIDerivedType(tag: DW_TAG_member, name: "a1", scope: !8, file: !3, line: 2, baseType: !11, size: 64) +!11 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !12, size: 64) +!12 = !DISubroutineType(types: !13) +!13 = !{null, !14} +!14 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +!15 = !{i32 2, !"Dwarf Version", i32 4} +!16 = !{i32 2, !"Debug Info Version", i32 3} +!17 = !{i32 1, !"wchar_size", i32 4} +!18 = !{!"clang version 8.0.0 (trunk 345296) (llvm/trunk 345297)"} +!19 = distinct !DISubprogram(name: "f1", scope: !3, file: !3, line: 3, type: !12, isLocal: false, isDefinition: true, scopeLine: 3, flags: DIFlagPrototyped, isOptimized: true, unit: !2, retainedNodes: !20) +!20 = !{!21} +!21 = !DILocalVariable(name: "p2", arg: 1, scope: !19, file: !3, line: 3, type: !14) +!22 = !DILocation(line: 3, column: 13, scope: !19) +!23 = !DILocation(line: 3, column: 19, scope: !19) diff --git a/llvm/test/CodeGen/SBF/BTF/func-non-void.ll b/llvm/test/CodeGen/SBF/BTF/func-non-void.ll new file mode 100644 index 0000000000000..331a7ab99b65a --- /dev/null +++ b/llvm/test/CodeGen/SBF/BTF/func-non-void.ll @@ -0,0 +1,98 @@ +; RUN: llc -sbf-enable-btf-emission -march=sbf -filetype=asm -o - %s | FileCheck -check-prefixes=CHECK %s + +; Source code: +; int f1(int a1) { return a1; } +; Compilation flag: +; clang -target bpf -O2 -g -S -emit-llvm t.c + +; Function Attrs: nounwind readnone +define dso_local i32 @f1(i32 returned) local_unnamed_addr #0 !dbg !7 { + call void @llvm.dbg.value(metadata i32 %0, metadata !12, metadata !DIExpression()), !dbg !13 + ret i32 %0, !dbg !14 +} + +; CHECK: .section .BTF,"",@progbits +; CHECK-NEXT: .short 60319 # 0xeb9f +; CHECK-NEXT: .byte 1 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .long 24 +; CHECK-NEXT: .long 0 +; CHECK-NEXT: .long 48 +; CHECK-NEXT: .long 48 +; CHECK-NEXT: .long 26 +; CHECK-NEXT: .long 1 # BTF_KIND_INT(id = 1) +; CHECK-NEXT: .long 16777216 # 0x1000000 +; CHECK-NEXT: .long 4 +; CHECK-NEXT: .long 16777248 # 0x1000020 +; CHECK-NEXT: .long 0 # BTF_KIND_FUNC_PROTO(id = 2) +; CHECK-NEXT: .long 218103809 # 0xd000001 +; CHECK-NEXT: .long 1 +; CHECK-NEXT: .long 5 +; CHECK-NEXT: .long 1 +; CHECK-NEXT: .long 8 # BTF_KIND_FUNC(id = 3) +; CHECK-NEXT: .long 201326593 # 0xc000001 +; CHECK-NEXT: .long 2 +; CHECK-NEXT: .byte 0 # string offset=0 +; CHECK-NEXT: .ascii "int" # string offset=1 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii "a1" # string offset=5 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii "f1" # string offset=8 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii ".text" # string offset=11 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii "/DNE/t.c" # string offset=17 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .section .BTF.ext,"",@progbits +; CHECK-NEXT: .short 60319 # 0xeb9f +; CHECK-NEXT: .byte 1 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .long 32 +; CHECK-NEXT: .long 0 +; CHECK-NEXT: .long 20 +; CHECK-NEXT: .long 20 +; CHECK-NEXT: .long 44 +; CHECK-NEXT: .long 64 +; CHECK-NEXT: .long 0 +; CHECK-NEXT: .long 8 # FuncInfo +; CHECK-NEXT: .long 11 # FuncInfo section string offset=11 +; CHECK-NEXT: .long 1 +; CHECK-NEXT: .long .Lfunc_begin0 +; CHECK-NEXT: .long 3 +; CHECK-NEXT: .long 16 # LineInfo +; CHECK-NEXT: .long 11 # LineInfo section string offset=11 +; CHECK-NEXT: .long 2 +; CHECK-NEXT: .long .Lfunc_begin0 +; CHECK-NEXT: .long 17 +; CHECK-NEXT: .long 0 +; CHECK-NEXT: .long 1024 # Line 1 Col 0 +; CHECK-NEXT: .long .Ltmp{{[0-9]+}} +; CHECK-NEXT: .long 17 +; CHECK-NEXT: .long 0 +; CHECK-NEXT: .long 1042 # Line 1 Col 18 + +; Function Attrs: nounwind readnone speculatable +declare void @llvm.dbg.value(metadata, metadata, metadata) #1 + +attributes #0 = { nounwind readnone "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "frame-pointer"="all" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" } +attributes #1 = { nounwind readnone speculatable } + +!llvm.dbg.cu = !{!0} +!llvm.module.flags = !{!3, !4, !5} +!llvm.ident = !{!6} + +!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 8.0.0 (trunk 345562) (llvm/trunk 345560)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, nameTableKind: None) +!1 = !DIFile(filename: "t.c", directory: "/DNE") +!2 = !{} +!3 = !{i32 2, !"Dwarf Version", i32 4} +!4 = !{i32 2, !"Debug Info Version", i32 3} +!5 = !{i32 1, !"wchar_size", i32 4} +!6 = !{!"clang version 8.0.0 (trunk 345562) (llvm/trunk 345560)"} +!7 = distinct !DISubprogram(name: "f1", scope: !1, file: !1, line: 1, type: !8, isLocal: false, isDefinition: true, scopeLine: 1, flags: DIFlagPrototyped, isOptimized: true, unit: !0, retainedNodes: !11) +!8 = !DISubroutineType(types: !9) +!9 = !{!10, !10} +!10 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +!11 = !{!12} +!12 = !DILocalVariable(name: "a1", arg: 1, scope: !7, file: !1, line: 1, type: !10) +!13 = !DILocation(line: 1, column: 12, scope: !7) +!14 = !DILocation(line: 1, column: 18, scope: !7) diff --git a/llvm/test/CodeGen/SBF/BTF/func-source.ll b/llvm/test/CodeGen/SBF/BTF/func-source.ll new file mode 100644 index 0000000000000..f4dc37a52f481 --- /dev/null +++ b/llvm/test/CodeGen/SBF/BTF/func-source.ll @@ -0,0 +1,81 @@ +; RUN: llc -sbf-enable-btf-emission -march=sbf -filetype=asm -o - %s | FileCheck -check-prefixes=CHECK %s + +; Source code: +; void f(void) { } +; Compilation flag: +; clang -target bpf -O2 -g -gdwarf-5 -gembed-source -S -emit-llvm t.c +; +; This test embeds the source code in the IR, so the line info should have +; correct reference to the lines in the string table. + +; Function Attrs: norecurse nounwind readnone +define dso_local void @f() local_unnamed_addr #0 !dbg !7 { +entry: + ret void, !dbg !10 +} + +; CHECK: .section .BTF,"",@progbits +; CHECK-NEXT: .short 60319 # 0xeb9f +; CHECK-NEXT: .byte 1 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .long 24 +; CHECK-NEXT: .long 0 +; CHECK-NEXT: .long 24 +; CHECK-NEXT: .long 24 +; CHECK-NEXT: .long 35 +; CHECK-NEXT: .long 0 # BTF_KIND_FUNC_PROTO(id = 1) +; CHECK-NEXT: .long 218103808 # 0xd000000 +; CHECK-NEXT: .long 0 +; CHECK-NEXT: .long 1 # BTF_KIND_FUNC(id = 2) +; CHECK-NEXT: .long 201326593 # 0xc000001 +; CHECK-NEXT: .long 1 +; CHECK-NEXT: .byte 0 # string offset=0 +; CHECK-NEXT: .byte 102 # string offset=1 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii ".text" # string offset=3 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii "/tmp/t.c" # string offset=9 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii "void f(void) { }" # string offset=18 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .section .BTF.ext,"",@progbits +; CHECK-NEXT: .short 60319 # 0xeb9f +; CHECK-NEXT: .byte 1 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .long 32 +; CHECK-NEXT: .long 0 +; CHECK-NEXT: .long 20 +; CHECK-NEXT: .long 20 +; CHECK-NEXT: .long 28 +; CHECK-NEXT: .long 48 +; CHECK-NEXT: .long 0 +; CHECK-NEXT: .long 8 # FuncInfo +; CHECK-NEXT: .long 3 # FuncInfo section string offset=3 +; CHECK-NEXT: .long 1 +; CHECK-NEXT: .long .Lfunc_begin0 +; CHECK-NEXT: .long 2 +; CHECK-NEXT: .long 16 # LineInfo +; CHECK-NEXT: .long 3 # LineInfo section string offset=3 +; CHECK-NEXT: .long 1 +; CHECK-NEXT: .long .Ltmp{{[0-9]+}} +; CHECK-NEXT: .long 9 +; CHECK-NEXT: .long 18 +; CHECK-NEXT: .long 1040 # Line 1 Col 16 + +attributes #0 = { norecurse nounwind readnone "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "frame-pointer"="all" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" } + +!llvm.dbg.cu = !{!0} +!llvm.module.flags = !{!3, !4, !5} +!llvm.ident = !{!6} + +!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 8.0.0 (trunk 344789) (llvm/trunk 344782)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, nameTableKind: None) +!1 = !DIFile(filename: "t.c", directory: "/tmp", checksumkind: CSK_MD5, checksum: "978599fafe3a080b456e3d95a3710359", source: "void f(void) { }\0A") +!2 = !{} +!3 = !{i32 2, !"Dwarf Version", i32 5} +!4 = !{i32 2, !"Debug Info Version", i32 3} +!5 = !{i32 1, !"wchar_size", i32 4} +!6 = !{!"clang version 8.0.0 (trunk 344789) (llvm/trunk 344782)"} +!7 = distinct !DISubprogram(name: "f", scope: !1, file: !1, line: 1, type: !8, isLocal: false, isDefinition: true, scopeLine: 1, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, isOptimized: true, unit: !0, retainedNodes: !2) +!8 = !DISubroutineType(types: !9) +!9 = !{null} +!10 = !DILocation(line: 1, column: 16, scope: !7) diff --git a/llvm/test/CodeGen/SBF/BTF/func-typedef.ll b/llvm/test/CodeGen/SBF/BTF/func-typedef.ll new file mode 100644 index 0000000000000..dfc8e5bd6a638 --- /dev/null +++ b/llvm/test/CodeGen/SBF/BTF/func-typedef.ll @@ -0,0 +1,114 @@ +; RUN: llc -sbf-enable-btf-emission -march=sbf -filetype=asm -o - %s | FileCheck -check-prefixes=CHECK %s + +; Source code: +; typedef int _int; +; typedef _int __int; +; __int f(__int a) { return a; } +; Compilation flag: +; clang -target bpf -O2 -g -S -emit-llvm t.c + +; Function Attrs: nounwind readnone +define dso_local i32 @f(i32 returned %a) local_unnamed_addr #0 !dbg !7 { +entry: + call void @llvm.dbg.value(metadata i32 %a, metadata !14, metadata !DIExpression()), !dbg !15 + ret i32 %a, !dbg !16 +} + +; CHECK: .section .BTF,"",@progbits +; CHECK-NEXT: .short 60319 # 0xeb9f +; CHECK-NEXT: .byte 1 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .long 24 +; CHECK-NEXT: .long 0 +; CHECK-NEXT: .long 72 +; CHECK-NEXT: .long 72 +; CHECK-NEXT: .long 35 +; CHECK-NEXT: .long 1 # BTF_KIND_TYPEDEF(id = 1) +; CHECK-NEXT: .long 134217728 # 0x8000000 +; CHECK-NEXT: .long 2 +; CHECK-NEXT: .long 7 # BTF_KIND_TYPEDEF(id = 2) +; CHECK-NEXT: .long 134217728 # 0x8000000 +; CHECK-NEXT: .long 3 +; CHECK-NEXT: .long 12 # BTF_KIND_INT(id = 3) +; CHECK-NEXT: .long 16777216 # 0x1000000 +; CHECK-NEXT: .long 4 +; CHECK-NEXT: .long 16777248 # 0x1000020 +; CHECK-NEXT: .long 0 # BTF_KIND_FUNC_PROTO(id = 4) +; CHECK-NEXT: .long 218103809 # 0xd000001 +; CHECK-NEXT: .long 1 +; CHECK-NEXT: .long 16 +; CHECK-NEXT: .long 1 +; CHECK-NEXT: .long 18 # BTF_KIND_FUNC(id = 5) +; CHECK-NEXT: .long 201326593 # 0xc000001 +; CHECK-NEXT: .long 4 +; CHECK-NEXT: .byte 0 # string offset=0 +; CHECK-NEXT: .ascii "__int" # string offset=1 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii "_int" # string offset=7 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii "int" # string offset=12 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .byte 97 # string offset=16 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .byte 102 # string offset=18 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii ".text" # string offset=20 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii "/tmp/t.c" # string offset=26 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .section .BTF.ext,"",@progbits +; CHECK-NEXT: .short 60319 # 0xeb9f +; CHECK-NEXT: .byte 1 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .long 32 +; CHECK-NEXT: .long 0 +; CHECK-NEXT: .long 20 +; CHECK-NEXT: .long 20 +; CHECK-NEXT: .long 44 +; CHECK-NEXT: .long 64 +; CHECK-NEXT: .long 0 +; CHECK-NEXT: .long 8 # FuncInfo +; CHECK-NEXT: .long 20 # FuncInfo section string offset=20 +; CHECK-NEXT: .long 1 +; CHECK-NEXT: .long .Lfunc_begin0 +; CHECK-NEXT: .long 5 +; CHECK-NEXT: .long 16 # LineInfo +; CHECK-NEXT: .long 20 # LineInfo section string offset=20 +; CHECK-NEXT: .long 2 +; CHECK-NEXT: .long .Lfunc_begin0 +; CHECK-NEXT: .long 26 +; CHECK-NEXT: .long 0 +; CHECK-NEXT: .long 3072 # Line 3 Col 0 +; CHECK-NEXT: .long .Ltmp{{[0-9]+}} +; CHECK-NEXT: .long 26 +; CHECK-NEXT: .long 0 +; CHECK-NEXT: .long 3092 # Line 3 Col 20 + + +; Function Attrs: nounwind readnone speculatable +declare void @llvm.dbg.value(metadata, metadata, metadata) #1 + +attributes #0 = { nounwind readnone "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "frame-pointer"="all" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" } +attributes #1 = { nounwind readnone speculatable } + +!llvm.dbg.cu = !{!0} +!llvm.module.flags = !{!3, !4, !5} +!llvm.ident = !{!6} + +!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 8.0.0 (trunk 344789) (llvm/trunk 344782)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, nameTableKind: None) +!1 = !DIFile(filename: "t.c", directory: "/tmp") +!2 = !{} +!3 = !{i32 2, !"Dwarf Version", i32 4} +!4 = !{i32 2, !"Debug Info Version", i32 3} +!5 = !{i32 1, !"wchar_size", i32 4} +!6 = !{!"clang version 8.0.0 (trunk 344789) (llvm/trunk 344782)"} +!7 = distinct !DISubprogram(name: "f", scope: !1, file: !1, line: 3, type: !8, isLocal: false, isDefinition: true, scopeLine: 3, flags: DIFlagPrototyped, isOptimized: true, unit: !0, retainedNodes: !13) +!8 = !DISubroutineType(types: !9) +!9 = !{!10, !10} +!10 = !DIDerivedType(tag: DW_TAG_typedef, name: "__int", file: !1, line: 2, baseType: !11) +!11 = !DIDerivedType(tag: DW_TAG_typedef, name: "_int", file: !1, line: 1, baseType: !12) +!12 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +!13 = !{!14} +!14 = !DILocalVariable(name: "a", arg: 1, scope: !7, file: !1, line: 3, type: !10) +!15 = !DILocation(line: 3, column: 15, scope: !7) +!16 = !DILocation(line: 3, column: 20, scope: !7) diff --git a/llvm/test/CodeGen/SBF/BTF/func-unused-arg.ll b/llvm/test/CodeGen/SBF/BTF/func-unused-arg.ll new file mode 100644 index 0000000000000..ff071582810a8 --- /dev/null +++ b/llvm/test/CodeGen/SBF/BTF/func-unused-arg.ll @@ -0,0 +1,94 @@ +; RUN: llc -sbf-enable-btf-emission -march=sbf -filetype=asm -o - %s | FileCheck -check-prefixes=CHECK %s + +; Source code: +; int f1(int a1) { return 0; } +; Compilation flag: +; clang -target bpf -O2 -g -S -emit-llvm t.c + +; Function Attrs: nounwind readnone +define dso_local i32 @f1(i32) local_unnamed_addr #0 !dbg !7 { + call void @llvm.dbg.value(metadata i32 %0, metadata !12, metadata !DIExpression()), !dbg !13 + ret i32 0, !dbg !14 +} + +; CHECK: .section .BTF,"",@progbits +; CHECK-NEXT: .short 60319 # 0xeb9f +; CHECK-NEXT: .byte 1 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .long 24 +; CHECK-NEXT: .long 0 +; CHECK-NEXT: .long 48 +; CHECK-NEXT: .long 48 +; CHECK-NEXT: .long 26 +; CHECK-NEXT: .long 1 # BTF_KIND_INT(id = 1) +; CHECK-NEXT: .long 16777216 # 0x1000000 +; CHECK-NEXT: .long 4 +; CHECK-NEXT: .long 16777248 # 0x1000020 +; CHECK-NEXT: .long 0 # BTF_KIND_FUNC_PROTO(id = 2) +; CHECK-NEXT: .long 218103809 # 0xd000001 +; CHECK-NEXT: .long 1 +; CHECK-NEXT: .long 5 +; CHECK-NEXT: .long 1 +; CHECK-NEXT: .long 8 # BTF_KIND_FUNC(id = 3) +; CHECK-NEXT: .long 201326593 # 0xc000001 +; CHECK-NEXT: .long 2 +; CHECK-NEXT: .byte 0 # string offset=0 +; CHECK-NEXT: .ascii "int" # string offset=1 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii "a1" # string offset=5 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii "f1" # string offset=8 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii ".text" # string offset=11 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii "/DNE/t.c" # string offset=17 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .section .BTF.ext,"",@progbits +; CHECK-NEXT: .short 60319 # 0xeb9f +; CHECK-NEXT: .byte 1 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .long 32 +; CHECK-NEXT: .long 0 +; CHECK-NEXT: .long 20 +; CHECK-NEXT: .long 20 +; CHECK-NEXT: .long 28 +; CHECK-NEXT: .long 48 +; CHECK-NEXT: .long 0 +; CHECK-NEXT: .long 8 # FuncInfo +; CHECK-NEXT: .long 11 # FuncInfo section string offset=11 +; CHECK-NEXT: .long 1 +; CHECK-NEXT: .long .Lfunc_begin0 +; CHECK-NEXT: .long 3 +; CHECK-NEXT: .long 16 # LineInfo +; CHECK-NEXT: .long 11 # LineInfo section string offset=11 +; CHECK-NEXT: .long 1 +; CHECK-NEXT: .long .Ltmp{{[0-9]+}} +; CHECK-NEXT: .long 17 +; CHECK-NEXT: .long 0 +; CHECK-NEXT: .long 1042 # Line 1 Col 18 + +; Function Attrs: nounwind readnone speculatable +declare void @llvm.dbg.value(metadata, metadata, metadata) #1 + +attributes #0 = { nounwind readnone "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "frame-pointer"="all" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" } +attributes #1 = { nounwind readnone speculatable } + +!llvm.dbg.cu = !{!0} +!llvm.module.flags = !{!3, !4, !5} +!llvm.ident = !{!6} + +!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 8.0.0 (trunk 345562) (llvm/trunk 345560)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, nameTableKind: None) +!1 = !DIFile(filename: "t.c", directory: "/DNE") +!2 = !{} +!3 = !{i32 2, !"Dwarf Version", i32 4} +!4 = !{i32 2, !"Debug Info Version", i32 3} +!5 = !{i32 1, !"wchar_size", i32 4} +!6 = !{!"clang version 8.0.0 (trunk 345562) (llvm/trunk 345560)"} +!7 = distinct !DISubprogram(name: "f1", scope: !1, file: !1, line: 1, type: !8, isLocal: false, isDefinition: true, scopeLine: 1, flags: DIFlagPrototyped, isOptimized: true, unit: !0, retainedNodes: !11) +!8 = !DISubroutineType(types: !9) +!9 = !{!10, !10} +!10 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +!11 = !{!12} +!12 = !DILocalVariable(name: "a1", arg: 1, scope: !7, file: !1, line: 1, type: !10) +!13 = !DILocation(line: 1, column: 12, scope: !7) +!14 = !DILocation(line: 1, column: 18, scope: !7) diff --git a/llvm/test/CodeGen/SBF/BTF/func-void.ll b/llvm/test/CodeGen/SBF/BTF/func-void.ll new file mode 100644 index 0000000000000..460103383f471 --- /dev/null +++ b/llvm/test/CodeGen/SBF/BTF/func-void.ll @@ -0,0 +1,75 @@ +; RUN: llc -sbf-enable-btf-emission -march=sbf -filetype=asm -o - %s | FileCheck -check-prefixes=CHECK %s + +; Source code: +; void f1(void) {} +; Compilation flag: +; clang -target bpf -O2 -g -S -emit-llvm t.c + +; Function Attrs: norecurse nounwind readnone +define dso_local void @f1() local_unnamed_addr #0 !dbg !7 { + ret void, !dbg !10 +} + +; CHECK: .section .BTF,"",@progbits +; CHECK-NEXT: .short 60319 # 0xeb9f +; CHECK-NEXT: .byte 1 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .long 24 +; CHECK-NEXT: .long 0 +; CHECK-NEXT: .long 24 +; CHECK-NEXT: .long 24 +; CHECK-NEXT: .long 19 +; CHECK-NEXT: .long 0 # BTF_KIND_FUNC_PROTO(id = 1) +; CHECK-NEXT: .long 218103808 # 0xd000000 +; CHECK-NEXT: .long 0 +; CHECK-NEXT: .long 1 # BTF_KIND_FUNC(id = 2) +; CHECK-NEXT: .long 201326593 # 0xc000001 +; CHECK-NEXT: .long 1 +; CHECK-NEXT: .byte 0 # string offset=0 +; CHECK-NEXT: .ascii "f1" # string offset=1 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii ".text" # string offset=4 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii "/DNE/t.c" # string offset=10 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .section .BTF.ext,"",@progbits +; CHECK-NEXT: .short 60319 # 0xeb9f +; CHECK-NEXT: .byte 1 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .long 32 +; CHECK-NEXT: .long 0 +; CHECK-NEXT: .long 20 +; CHECK-NEXT: .long 20 +; CHECK-NEXT: .long 28 +; CHECK-NEXT: .long 48 +; CHECK-NEXT: .long 0 +; CHECK-NEXT: .long 8 # FuncInfo +; CHECK-NEXT: .long 4 # FuncInfo section string offset=4 +; CHECK-NEXT: .long 1 +; CHECK-NEXT: .long .Lfunc_begin0 +; CHECK-NEXT: .long 2 +; CHECK-NEXT: .long 16 # LineInfo +; CHECK-NEXT: .long 4 # LineInfo section string offset=4 +; CHECK-NEXT: .long 1 +; CHECK-NEXT: .long .Ltmp{{[0-9]+}} +; CHECK-NEXT: .long 10 +; CHECK-NEXT: .long 0 +; CHECK-NEXT: .long 1040 # Line 1 Col 16 + +attributes #0 = { norecurse nounwind readnone "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "frame-pointer"="all" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" } + +!llvm.dbg.cu = !{!0} +!llvm.module.flags = !{!3, !4, !5} +!llvm.ident = !{!6} + +!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 8.0.0 (trunk 345562) (llvm/trunk 345560)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, nameTableKind: None) +!1 = !DIFile(filename: "t.c", directory: "/DNE") +!2 = !{} +!3 = !{i32 2, !"Dwarf Version", i32 4} +!4 = !{i32 2, !"Debug Info Version", i32 3} +!5 = !{i32 1, !"wchar_size", i32 4} +!6 = !{!"clang version 8.0.0 (trunk 345562) (llvm/trunk 345560)"} +!7 = distinct !DISubprogram(name: "f1", scope: !1, file: !1, line: 1, type: !8, isLocal: false, isDefinition: true, scopeLine: 1, flags: DIFlagPrototyped, isOptimized: true, unit: !0, retainedNodes: !2) +!8 = !DISubroutineType(types: !9) +!9 = !{null} +!10 = !DILocation(line: 1, column: 16, scope: !7) diff --git a/llvm/test/CodeGen/SBF/BTF/fwd-no-define.ll b/llvm/test/CodeGen/SBF/BTF/fwd-no-define.ll new file mode 100644 index 0000000000000..1353abed37567 --- /dev/null +++ b/llvm/test/CodeGen/SBF/BTF/fwd-no-define.ll @@ -0,0 +1,61 @@ +; RUN: llc -sbf-enable-btf-emission -march=sbf -filetype=asm -o - %s | FileCheck -check-prefixes=CHECK %s + +; Source code: +; struct t1; +; struct t2 {struct t1 *p;} a; +; Compilation flag: +; clang -target bpf -O2 -g -S -emit-llvm t.c + +%struct.t2 = type { %struct.t1* } +%struct.t1 = type opaque + +@a = common dso_local local_unnamed_addr global %struct.t2 zeroinitializer, align 8, !dbg !0 + +!llvm.dbg.cu = !{!2} +!llvm.module.flags = !{!11, !12, !13} +!llvm.ident = !{!14} + +; CHECK: .section .BTF,"",@progbits +; CHECK-NEXT: .short 60319 # 0xeb9f +; CHECK-NEXT: .byte 1 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .long 24 +; CHECK-NEXT: .long 0 +; CHECK-NEXT: .long 48 +; CHECK-NEXT: .long 48 +; CHECK-NEXT: .long 9 +; CHECK-NEXT: .long 1 # BTF_KIND_STRUCT(id = 1) +; CHECK-NEXT: .long 67108865 # 0x4000001 +; CHECK-NEXT: .long 8 +; CHECK-NEXT: .long 4 +; CHECK-NEXT: .long 2 +; CHECK-NEXT: .long 0 +; CHECK-NEXT: .long 0 # BTF_KIND_PTR(id = 2) +; CHECK-NEXT: .long 33554432 # 0x2000000 +; CHECK-NEXT: .long 3 +; CHECK-NEXT: .long 6 # BTF_KIND_FWD(id = 3) +; CHECK-NEXT: .long 117440512 # 0x7000000 +; CHECK-NEXT: .long 0 +; CHECK-NEXT: .byte 0 # string offset=0 +; CHECK-NEXT: .ascii "t2" # string offset=1 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .byte 112 # string offset=4 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii "t1" # string offset=6 +; CHECK-NEXT: .byte 0 + +!0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression()) +!1 = distinct !DIGlobalVariable(name: "a", scope: !2, file: !3, line: 2, type: !6, isLocal: false, isDefinition: true) +!2 = distinct !DICompileUnit(language: DW_LANG_C99, file: !3, producer: "clang version 8.0.0 (trunk 344789) (llvm/trunk 344782)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !4, globals: !5, nameTableKind: None) +!3 = !DIFile(filename: "t.c", directory: "/home/yhs/tmp") +!4 = !{} +!5 = !{!0} +!6 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "t2", file: !3, line: 2, size: 64, elements: !7) +!7 = !{!8} +!8 = !DIDerivedType(tag: DW_TAG_member, name: "p", scope: !6, file: !3, line: 2, baseType: !9, size: 64) +!9 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !10, size: 64) +!10 = !DICompositeType(tag: DW_TAG_structure_type, name: "t1", file: !3, line: 1, flags: DIFlagFwdDecl) +!11 = !{i32 2, !"Dwarf Version", i32 4} +!12 = !{i32 2, !"Debug Info Version", i32 3} +!13 = !{i32 1, !"wchar_size", i32 4} +!14 = !{!"clang version 8.0.0 (trunk 344789) (llvm/trunk 344782)"} diff --git a/llvm/test/CodeGen/SBF/BTF/fwd-with-define.ll b/llvm/test/CodeGen/SBF/BTF/fwd-with-define.ll new file mode 100644 index 0000000000000..1b39475b2e688 --- /dev/null +++ b/llvm/test/CodeGen/SBF/BTF/fwd-with-define.ll @@ -0,0 +1,54 @@ +; RUN: llc -sbf-enable-btf-emission -march=sbf -filetype=asm -o - %s | FileCheck -check-prefixes=CHECK %s + +; Source code: +; struct t1; +; struct t1 {struct t1 *p;} a; +; Compilation flag: +; clang -target bpf -O2 -g -S -emit-llvm t.c + +%struct.t1 = type { %struct.t1* } + +@a = common dso_local local_unnamed_addr global %struct.t1 zeroinitializer, align 8, !dbg !0 + +!llvm.dbg.cu = !{!2} +!llvm.module.flags = !{!10, !11, !12} +!llvm.ident = !{!13} + +; CHECK: .section .BTF,"",@progbits +; CHECK-NEXT: .short 60319 # 0xeb9f +; CHECK-NEXT: .byte 1 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .long 24 +; CHECK-NEXT: .long 0 +; CHECK-NEXT: .long 36 +; CHECK-NEXT: .long 36 +; CHECK-NEXT: .long 6 +; CHECK-NEXT: .long 1 # BTF_KIND_STRUCT(id = 1) +; CHECK-NEXT: .long 67108865 # 0x4000001 +; CHECK-NEXT: .long 8 +; CHECK-NEXT: .long 4 +; CHECK-NEXT: .long 2 +; CHECK-NEXT: .long 0 +; CHECK-NEXT: .long 0 # BTF_KIND_PTR(id = 2) +; CHECK-NEXT: .long 33554432 # 0x2000000 +; CHECK-NEXT: .long 1 +; CHECK-NEXT: .byte 0 # string offset=0 +; CHECK-NEXT: .ascii "t1" # string offset=1 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .byte 112 # string offset=4 +; CHECK-NEXT: .byte 0 + +!0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression()) +!1 = distinct !DIGlobalVariable(name: "a", scope: !2, file: !3, line: 2, type: !6, isLocal: false, isDefinition: true) +!2 = distinct !DICompileUnit(language: DW_LANG_C99, file: !3, producer: "clang version 8.0.0 (trunk 344789) (llvm/trunk 344782)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !4, globals: !5, nameTableKind: None) +!3 = !DIFile(filename: "t.c", directory: "/home/yhs/tmp") +!4 = !{} +!5 = !{!0} +!6 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "t1", file: !3, line: 2, size: 64, elements: !7) +!7 = !{!8} +!8 = !DIDerivedType(tag: DW_TAG_member, name: "p", scope: !6, file: !3, line: 2, baseType: !9, size: 64) +!9 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !6, size: 64) +!10 = !{i32 2, !"Dwarf Version", i32 4} +!11 = !{i32 2, !"Debug Info Version", i32 3} +!12 = !{i32 1, !"wchar_size", i32 4} +!13 = !{!"clang version 8.0.0 (trunk 344789) (llvm/trunk 344782)"} diff --git a/llvm/test/CodeGen/SBF/BTF/global-var-inited.ll b/llvm/test/CodeGen/SBF/BTF/global-var-inited.ll new file mode 100644 index 0000000000000..7766f2676002e --- /dev/null +++ b/llvm/test/CodeGen/SBF/BTF/global-var-inited.ll @@ -0,0 +1,55 @@ +; RUN: llc -sbf-enable-btf-emission -march=sbf -filetype=asm -o - %s | FileCheck -check-prefixes=CHECK %s + +; Source code: +; int a = 3; +; Compilation flag: +; clang -target bpf -O2 -g -S -emit-llvm test.c + +@a = dso_local local_unnamed_addr global i32 3, align 4, !dbg !0 + +; CHECK: .section .BTF,"",@progbits +; CHECK-NEXT: .short 60319 # 0xeb9f +; CHECK-NEXT: .byte 1 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .long 24 +; CHECK-NEXT: .long 0 +; CHECK-NEXT: .long 56 +; CHECK-NEXT: .long 56 +; CHECK-NEXT: .long 13 +; CHECK-NEXT: .long 1 # BTF_KIND_INT(id = 1) +; CHECK-NEXT: .long 16777216 # 0x1000000 +; CHECK-NEXT: .long 4 +; CHECK-NEXT: .long 16777248 # 0x1000020 +; CHECK-NEXT: .long 5 # BTF_KIND_VAR(id = 2) +; CHECK-NEXT: .long 234881024 # 0xe000000 +; CHECK-NEXT: .long 1 +; CHECK-NEXT: .long 1 +; CHECK-NEXT: .long 7 # BTF_KIND_DATASEC(id = 3) +; CHECK-NEXT: .long 251658241 # 0xf000001 +; CHECK-NEXT: .long 0 +; CHECK-NEXT: .long 2 +; CHECK-NEXT: .long a +; CHECK-NEXT: .long 4 +; CHECK-NEXT: .byte 0 # string offset=0 +; CHECK-NEXT: .ascii "int" # string offset=1 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .byte 97 # string offset=5 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii ".data" # string offset=7 +; CHECK-NEXT: .byte 0 + +!llvm.dbg.cu = !{!2} +!llvm.module.flags = !{!7, !8, !9} +!llvm.ident = !{!10} + +!0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression()) +!1 = distinct !DIGlobalVariable(name: "a", scope: !2, file: !3, line: 1, type: !6, isLocal: false, isDefinition: true) +!2 = distinct !DICompileUnit(language: DW_LANG_C99, file: !3, producer: "clang version 8.0.20181009 ", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !4, globals: !5, nameTableKind: None) +!3 = !DIFile(filename: "test.c", directory: "/home/yhs/work/tests/llvm/bug") +!4 = !{} +!5 = !{!0} +!6 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +!7 = !{i32 2, !"Dwarf Version", i32 4} +!8 = !{i32 2, !"Debug Info Version", i32 3} +!9 = !{i32 1, !"wchar_size", i32 4} +!10 = !{!"clang version 8.0.20181009 "} diff --git a/llvm/test/CodeGen/SBF/BTF/global-var-sec-readonly.ll b/llvm/test/CodeGen/SBF/BTF/global-var-sec-readonly.ll new file mode 100644 index 0000000000000..a5c41c2a525b5 --- /dev/null +++ b/llvm/test/CodeGen/SBF/BTF/global-var-sec-readonly.ll @@ -0,0 +1,72 @@ +; RUN: llc -sbf-enable-btf-emission -march=sbf -filetype=asm -o - %s | FileCheck -check-prefixes=CHECK %s + +; Source code: +; const int gv1 __attribute__((section("maps"))); +; const int gv2 __attribute__((section("maps"))) = 5; +; Compilation flag: +; clang -target bpf -O2 -g -S -emit-llvm test.c + +@gv2 = dso_local local_unnamed_addr constant i32 5, section "maps", align 4, !dbg !0 +@gv1 = dso_local local_unnamed_addr constant i32 0, section "maps", align 4, !dbg !6 + +; CHECK: .section .BTF,"",@progbits +; CHECK-NEXT: .short 60319 # 0xeb9f +; CHECK-NEXT: .byte 1 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .long 24 +; CHECK-NEXT: .long 0 +; CHECK-NEXT: .long 96 +; CHECK-NEXT: .long 96 +; CHECK-NEXT: .long 18 +; CHECK-NEXT: .long 0 # BTF_KIND_CONST(id = 1) +; CHECK-NEXT: .long 167772160 # 0xa000000 +; CHECK-NEXT: .long 2 +; CHECK-NEXT: .long 1 # BTF_KIND_INT(id = 2) +; CHECK-NEXT: .long 16777216 # 0x1000000 +; CHECK-NEXT: .long 4 +; CHECK-NEXT: .long 16777248 # 0x1000020 +; CHECK-NEXT: .long 5 # BTF_KIND_VAR(id = 3) +; CHECK-NEXT: .long 234881024 # 0xe000000 +; CHECK-NEXT: .long 1 +; CHECK-NEXT: .long 1 +; CHECK-NEXT: .long 9 # BTF_KIND_VAR(id = 4) +; CHECK-NEXT: .long 234881024 # 0xe000000 +; CHECK-NEXT: .long 1 +; CHECK-NEXT: .long 1 +; CHECK-NEXT: .long 13 # BTF_KIND_DATASEC(id = 5) +; CHECK-NEXT: .long 251658242 # 0xf000002 +; CHECK-NEXT: .long 0 +; CHECK-NEXT: .long 3 +; CHECK-NEXT: .long gv2 +; CHECK-NEXT: .long 4 +; CHECK-NEXT: .long 4 +; CHECK-NEXT: .long gv1 +; CHECK-NEXT: .long 4 +; CHECK-NEXT: .byte 0 # string offset=0 +; CHECK-NEXT: .ascii "int" # string offset=1 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii "gv2" # string offset=5 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii "gv1" # string offset=9 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii "maps" # string offset=13 +; CHECK-NEXT: .byte 0 + +!llvm.dbg.cu = !{!2} +!llvm.module.flags = !{!10, !11, !12} +!llvm.ident = !{!13} + +!0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression()) +!1 = distinct !DIGlobalVariable(name: "gv2", scope: !2, file: !3, line: 2, type: !8, isLocal: false, isDefinition: true) +!2 = distinct !DICompileUnit(language: DW_LANG_C99, file: !3, producer: "clang version 8.0.20181009 ", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !4, globals: !5, nameTableKind: None) +!3 = !DIFile(filename: "test.c", directory: "/home/yhs/work/tests/llvm/bug") +!4 = !{} +!5 = !{!0, !6} +!6 = !DIGlobalVariableExpression(var: !7, expr: !DIExpression()) +!7 = distinct !DIGlobalVariable(name: "gv1", scope: !2, file: !3, line: 1, type: !8, isLocal: false, isDefinition: true) +!8 = !DIDerivedType(tag: DW_TAG_const_type, baseType: !9) +!9 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +!10 = !{i32 2, !"Dwarf Version", i32 4} +!11 = !{i32 2, !"Debug Info Version", i32 3} +!12 = !{i32 1, !"wchar_size", i32 4} +!13 = !{!"clang version 8.0.20181009 "} diff --git a/llvm/test/CodeGen/SBF/BTF/global-var-sec.ll b/llvm/test/CodeGen/SBF/BTF/global-var-sec.ll new file mode 100644 index 0000000000000..8e90d3b70a858 --- /dev/null +++ b/llvm/test/CodeGen/SBF/BTF/global-var-sec.ll @@ -0,0 +1,68 @@ +; RUN: llc -sbf-enable-btf-emission -march=sbf -filetype=asm -o - %s | FileCheck -check-prefixes=CHECK %s + +; Source code: +; int gv1 __attribute__((section("maps"))); +; int gv2 __attribute__((section("maps"))) = 5; +; Compilation flag: +; clang -target bpf -O2 -g -S -emit-llvm test.c + +@gv2 = dso_local local_unnamed_addr global i32 5, section "maps", align 4, !dbg !0 +@gv1 = dso_local local_unnamed_addr global i32 0, section "maps", align 4, !dbg !6 + +; CHECK: .section .BTF,"",@progbits +; CHECK-NEXT: .short 60319 # 0xeb9f +; CHECK-NEXT: .byte 1 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .long 24 +; CHECK-NEXT: .long 0 +; CHECK-NEXT: .long 84 +; CHECK-NEXT: .long 84 +; CHECK-NEXT: .long 18 +; CHECK-NEXT: .long 1 # BTF_KIND_INT(id = 1) +; CHECK-NEXT: .long 16777216 # 0x1000000 +; CHECK-NEXT: .long 4 +; CHECK-NEXT: .long 16777248 # 0x1000020 +; CHECK-NEXT: .long 5 # BTF_KIND_VAR(id = 2) +; CHECK-NEXT: .long 234881024 # 0xe000000 +; CHECK-NEXT: .long 1 +; CHECK-NEXT: .long 1 +; CHECK-NEXT: .long 9 # BTF_KIND_VAR(id = 3) +; CHECK-NEXT: .long 234881024 # 0xe000000 +; CHECK-NEXT: .long 1 +; CHECK-NEXT: .long 1 +; CHECK-NEXT: .long 13 # BTF_KIND_DATASEC(id = 4) +; CHECK-NEXT: .long 251658242 # 0xf000002 +; CHECK-NEXT: .long 0 +; CHECK-NEXT: .long 2 +; CHECK-NEXT: .long gv2 +; CHECK-NEXT: .long 4 +; CHECK-NEXT: .long 3 +; CHECK-NEXT: .long gv1 +; CHECK-NEXT: .long 4 +; CHECK-NEXT: .byte 0 # string offset=0 +; CHECK-NEXT: .ascii "int" # string offset=1 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii "gv2" # string offset=5 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii "gv1" # string offset=9 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii "maps" # string offset=13 +; CHECK-NEXT: .byte 0 + +!llvm.dbg.cu = !{!2} +!llvm.module.flags = !{!9, !10, !11} +!llvm.ident = !{!12} + +!0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression()) +!1 = distinct !DIGlobalVariable(name: "gv2", scope: !2, file: !3, line: 2, type: !8, isLocal: false, isDefinition: true) +!2 = distinct !DICompileUnit(language: DW_LANG_C99, file: !3, producer: "clang version 8.0.20181009 ", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !4, globals: !5, nameTableKind: None) +!3 = !DIFile(filename: "test.c", directory: "/home/yhs/work/tests/llvm/bug") +!4 = !{} +!5 = !{!0, !6} +!6 = !DIGlobalVariableExpression(var: !7, expr: !DIExpression()) +!7 = distinct !DIGlobalVariable(name: "gv1", scope: !2, file: !3, line: 1, type: !8, isLocal: false, isDefinition: true) +!8 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +!9 = !{i32 2, !"Dwarf Version", i32 4} +!10 = !{i32 2, !"Debug Info Version", i32 3} +!11 = !{i32 1, !"wchar_size", i32 4} +!12 = !{!"clang version 8.0.20181009 "} diff --git a/llvm/test/CodeGen/SBF/BTF/int.ll b/llvm/test/CodeGen/SBF/BTF/int.ll new file mode 100644 index 0000000000000..da97c30682272 --- /dev/null +++ b/llvm/test/CodeGen/SBF/BTF/int.ll @@ -0,0 +1,41 @@ +; RUN: llc -sbf-enable-btf-emission -march=sbf -filetype=asm -o - %s | FileCheck -check-prefixes=CHECK %s + +; Source code: +; int a; +; Compilation flag: +; clang -target bpf -O2 -g -S -emit-llvm t.c + +@a = common dso_local local_unnamed_addr global i32 0, align 4, !dbg !0 + +!llvm.dbg.cu = !{!2} +!llvm.module.flags = !{!7, !8, !9} +!llvm.ident = !{!10} + +; CHECK: .section .BTF,"",@progbits +; CHECK-NEXT: .short 60319 # 0xeb9f +; CHECK-NEXT: .byte 1 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .long 24 +; CHECK-NEXT: .long 0 +; CHECK-NEXT: .long 16 +; CHECK-NEXT: .long 16 +; CHECK-NEXT: .long 5 +; CHECK-NEXT: .long 1 # BTF_KIND_INT(id = 1) +; CHECK-NEXT: .long 16777216 # 0x1000000 +; CHECK-NEXT: .long 4 +; CHECK-NEXT: .long 16777248 # 0x1000020 +; CHECK-NEXT: .byte 0 # string offset=0 +; CHECK-NEXT: .ascii "int" # string offset=1 +; CHECK-NEXT: .byte 0 + +!0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression()) +!1 = distinct !DIGlobalVariable(name: "a", scope: !2, file: !3, line: 1, type: !6, isLocal: false, isDefinition: true) +!2 = distinct !DICompileUnit(language: DW_LANG_C99, file: !3, producer: "clang version 8.0.0 (trunk 344789) (llvm/trunk 344782)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !4, globals: !5, nameTableKind: None) +!3 = !DIFile(filename: "t.c", directory: "/home/yhs/tmp") +!4 = !{} +!5 = !{!0} +!6 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +!7 = !{i32 2, !"Dwarf Version", i32 4} +!8 = !{i32 2, !"Debug Info Version", i32 3} +!9 = !{i32 1, !"wchar_size", i32 4} +!10 = !{!"clang version 8.0.0 (trunk 344789) (llvm/trunk 344782)"} diff --git a/llvm/test/CodeGen/SBF/BTF/local-var-readonly-1.ll b/llvm/test/CodeGen/SBF/BTF/local-var-readonly-1.ll new file mode 100644 index 0000000000000..ff4aa9e298157 --- /dev/null +++ b/llvm/test/CodeGen/SBF/BTF/local-var-readonly-1.ll @@ -0,0 +1,104 @@ +; RUN: llc -sbf-enable-btf-emission -march=sbf -filetype=asm -o - %s | FileCheck -check-prefixes=CHECK %s +; +; Source: +; void foo(const void *); +; int test() { +; const char *str = "abcd"; +; const struct { +; unsigned a[4]; +; } val = { .a = {2, 3, 4, 5} }; +; foo(str); +; foo(&val); +; return 0; +; } +; Compilation flag: +; clang -target bpf -O2 -g -S -emit-llvm t.c + +%struct.anon = type { [4 x i32] } + +@.str = private unnamed_addr constant [5 x i8] c"abcd\00", align 1 +@__const.test.val = private unnamed_addr constant %struct.anon { [4 x i32] [i32 2, i32 3, i32 4, i32 5] }, align 4 + +; Function Attrs: nounwind +define dso_local i32 @test() local_unnamed_addr #0 !dbg !7 { +entry: + %val = alloca %struct.anon, align 4 + call void @llvm.dbg.value(metadata i8* getelementptr inbounds ([5 x i8], [5 x i8]* @.str, i64 0, i64 0), metadata !12, metadata !DIExpression()), !dbg !25 + %0 = bitcast %struct.anon* %val to i8*, !dbg !26 + call void @llvm.lifetime.start.p0i8(i64 16, i8* nonnull %0) #4, !dbg !26 + call void @llvm.dbg.declare(metadata %struct.anon* %val, metadata !16, metadata !DIExpression()), !dbg !27 + call void @llvm.memcpy.p0i8.p0i8.i64(i8* nonnull align 4 dereferenceable(16) %0, i8* nonnull align 4 dereferenceable(16) bitcast (%struct.anon* @__const.test.val to i8*), i64 16, i1 false), !dbg !27 + tail call void @foo(i8* getelementptr inbounds ([5 x i8], [5 x i8]* @.str, i64 0, i64 0)) #4, !dbg !28 + call void @foo(i8* nonnull %0) #4, !dbg !29 + call void @llvm.lifetime.end.p0i8(i64 16, i8* nonnull %0) #4, !dbg !30 + ret i32 0, !dbg !31 +} + +; the initial value of "str" is stored in section .rodata.str1.1 +; the initial value of "val" is stored in section .rodata.cst16 +; CHECK-NOT: BTF_KIND_DATASEC + +; Function Attrs: argmemonly nounwind willreturn +declare void @llvm.lifetime.start.p0i8(i64 immarg, i8* nocapture) #1 + +; Function Attrs: nounwind readnone speculatable willreturn +declare void @llvm.dbg.declare(metadata, metadata, metadata) #2 + +; Function Attrs: argmemonly nounwind willreturn +declare void @llvm.memcpy.p0i8.p0i8.i64(i8* noalias nocapture writeonly, i8* noalias nocapture readonly, i64, i1 immarg) #1 + +declare !dbg !32 dso_local void @foo(i8*) local_unnamed_addr #3 + +; Function Attrs: argmemonly nounwind willreturn +declare void @llvm.lifetime.end.p0i8(i64 immarg, i8* nocapture) #1 + +; Function Attrs: nounwind readnone speculatable willreturn +declare void @llvm.dbg.value(metadata, metadata, metadata) #2 + +attributes #0 = { nounwind "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" } +attributes #1 = { argmemonly nounwind willreturn } +attributes #2 = { nounwind readnone speculatable willreturn } +attributes #3 = { "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" } +attributes #4 = { nounwind } + +!llvm.dbg.cu = !{!0} +!llvm.module.flags = !{!3, !4, !5} +!llvm.ident = !{!6} + +!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 11.0.0 (https://github.com/llvm/llvm-project.git 1e92cffe18a07c12042b57504dfa7fb709b833c8)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, splitDebugInlining: false, nameTableKind: None) +!1 = !DIFile(filename: "t.c", directory: "/tmp/home/yhs/tmp") +!2 = !{} +!3 = !{i32 7, !"Dwarf Version", i32 4} +!4 = !{i32 2, !"Debug Info Version", i32 3} +!5 = !{i32 1, !"wchar_size", i32 4} +!6 = !{!"clang version 11.0.0 (https://github.com/llvm/llvm-project.git 1e92cffe18a07c12042b57504dfa7fb709b833c8)"} +!7 = distinct !DISubprogram(name: "test", scope: !1, file: !1, line: 2, type: !8, scopeLine: 2, flags: DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !11) +!8 = !DISubroutineType(types: !9) +!9 = !{!10} +!10 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +!11 = !{!12, !16} +!12 = !DILocalVariable(name: "str", scope: !7, file: !1, line: 3, type: !13) +!13 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !14, size: 64) +!14 = !DIDerivedType(tag: DW_TAG_const_type, baseType: !15) +!15 = !DIBasicType(name: "char", size: 8, encoding: DW_ATE_signed_char) +!16 = !DILocalVariable(name: "val", scope: !7, file: !1, line: 6, type: !17) +!17 = !DIDerivedType(tag: DW_TAG_const_type, baseType: !18) +!18 = distinct !DICompositeType(tag: DW_TAG_structure_type, scope: !7, file: !1, line: 4, size: 128, elements: !19) +!19 = !{!20} +!20 = !DIDerivedType(tag: DW_TAG_member, name: "a", scope: !18, file: !1, line: 5, baseType: !21, size: 128) +!21 = !DICompositeType(tag: DW_TAG_array_type, baseType: !22, size: 128, elements: !23) +!22 = !DIBasicType(name: "unsigned int", size: 32, encoding: DW_ATE_unsigned) +!23 = !{!24} +!24 = !DISubrange(count: 4) +!25 = !DILocation(line: 0, scope: !7) +!26 = !DILocation(line: 4, column: 3, scope: !7) +!27 = !DILocation(line: 6, column: 5, scope: !7) +!28 = !DILocation(line: 7, column: 3, scope: !7) +!29 = !DILocation(line: 8, column: 3, scope: !7) +!30 = !DILocation(line: 10, column: 1, scope: !7) +!31 = !DILocation(line: 9, column: 3, scope: !7) +!32 = !DISubprogram(name: "foo", scope: !1, file: !1, line: 1, type: !33, flags: DIFlagPrototyped, spFlags: DISPFlagOptimized, retainedNodes: !2) +!33 = !DISubroutineType(types: !34) +!34 = !{null, !35} +!35 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !36, size: 64) +!36 = !DIDerivedType(tag: DW_TAG_const_type, baseType: null) diff --git a/llvm/test/CodeGen/SBF/BTF/local-var-readonly-2.ll b/llvm/test/CodeGen/SBF/BTF/local-var-readonly-2.ll new file mode 100644 index 0000000000000..ebccb3e7718b3 --- /dev/null +++ b/llvm/test/CodeGen/SBF/BTF/local-var-readonly-2.ll @@ -0,0 +1,96 @@ +; RUN: llc -sbf-enable-btf-emission -march=sbf -filetype=asm -o - %s | FileCheck -check-prefixes=CHECK %s +; +; Source: +; void foo(const void *); +; int test() { +; const struct { +; unsigned a[4]; +; char b; +; } val = { .a = {2, 3, 4, 5}, .b = 4 }; +; foo(&val); +; return 0; +; } +; Compilation flag: +; clang -target bpf -O2 -g -S -emit-llvm t.c + +%struct.anon = type { [4 x i32], i8 } + +@__const.test.val = private unnamed_addr constant %struct.anon { [4 x i32] [i32 2, i32 3, i32 4, i32 5], i8 4 }, align 4 + +; Function Attrs: nounwind +define dso_local i32 @test() local_unnamed_addr #0 !dbg !7 { +entry: + %val = alloca %struct.anon, align 4 + %0 = bitcast %struct.anon* %val to i8*, !dbg !23 + call void @llvm.lifetime.start.p0i8(i64 20, i8* nonnull %0) #4, !dbg !23 + call void @llvm.dbg.declare(metadata %struct.anon* %val, metadata !12, metadata !DIExpression()), !dbg !24 + call void @llvm.memcpy.p0i8.p0i8.i64(i8* nonnull align 4 dereferenceable(20) %0, i8* nonnull align 4 dereferenceable(20) bitcast (%struct.anon* @__const.test.val to i8*), i64 20, i1 false), !dbg !24 + call void @foo(i8* nonnull %0) #4, !dbg !25 + call void @llvm.lifetime.end.p0i8(i64 20, i8* nonnull %0) #4, !dbg !26 + ret i32 0, !dbg !27 +} + +; the init value of local variable "val" is stored in .rodata section +; CHECK: .long 42 # BTF_KIND_DATASEC +; CHECK-NEXT: .long 251658240 # 0xf000000 +; CHECK-NEXT: .long 0 + +; CHECK: .ascii ".rodata" # string offset=42 + +; Function Attrs: argmemonly nounwind willreturn +declare void @llvm.lifetime.start.p0i8(i64 immarg, i8* nocapture) #1 + +; Function Attrs: nounwind readnone speculatable willreturn +declare void @llvm.dbg.declare(metadata, metadata, metadata) #2 + +; Function Attrs: argmemonly nounwind willreturn +declare void @llvm.memcpy.p0i8.p0i8.i64(i8* noalias nocapture writeonly, i8* noalias nocapture readonly, i64, i1 immarg) #1 + +declare !dbg !28 dso_local void @foo(i8*) local_unnamed_addr #3 + +; Function Attrs: argmemonly nounwind willreturn +declare void @llvm.lifetime.end.p0i8(i64 immarg, i8* nocapture) #1 + +attributes #0 = { nounwind "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" } +attributes #1 = { argmemonly nounwind willreturn } +attributes #2 = { nounwind readnone speculatable willreturn } +attributes #3 = { "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" } +attributes #4 = { nounwind } + +!llvm.dbg.cu = !{!0} +!llvm.module.flags = !{!3, !4, !5} +!llvm.ident = !{!6} + +!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 11.0.0 (https://github.com/llvm/llvm-project.git 1e92cffe18a07c12042b57504dfa7fb709b833c8)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, splitDebugInlining: false, nameTableKind: None) +!1 = !DIFile(filename: "t.c", directory: "/tmp/home/yhs/tmp") +!2 = !{} +!3 = !{i32 7, !"Dwarf Version", i32 4} +!4 = !{i32 2, !"Debug Info Version", i32 3} +!5 = !{i32 1, !"wchar_size", i32 4} +!6 = !{!"clang version 11.0.0 (https://github.com/llvm/llvm-project.git 1e92cffe18a07c12042b57504dfa7fb709b833c8)"} +!7 = distinct !DISubprogram(name: "test", scope: !1, file: !1, line: 2, type: !8, scopeLine: 2, flags: DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !11) +!8 = !DISubroutineType(types: !9) +!9 = !{!10} +!10 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +!11 = !{!12} +!12 = !DILocalVariable(name: "val", scope: !7, file: !1, line: 6, type: !13) +!13 = !DIDerivedType(tag: DW_TAG_const_type, baseType: !14) +!14 = distinct !DICompositeType(tag: DW_TAG_structure_type, scope: !7, file: !1, line: 3, size: 160, elements: !15) +!15 = !{!16, !21} +!16 = !DIDerivedType(tag: DW_TAG_member, name: "a", scope: !14, file: !1, line: 4, baseType: !17, size: 128) +!17 = !DICompositeType(tag: DW_TAG_array_type, baseType: !18, size: 128, elements: !19) +!18 = !DIBasicType(name: "unsigned int", size: 32, encoding: DW_ATE_unsigned) +!19 = !{!20} +!20 = !DISubrange(count: 4) +!21 = !DIDerivedType(tag: DW_TAG_member, name: "b", scope: !14, file: !1, line: 5, baseType: !22, size: 8, offset: 128) +!22 = !DIBasicType(name: "char", size: 8, encoding: DW_ATE_signed_char) +!23 = !DILocation(line: 3, column: 3, scope: !7) +!24 = !DILocation(line: 6, column: 5, scope: !7) +!25 = !DILocation(line: 7, column: 3, scope: !7) +!26 = !DILocation(line: 9, column: 1, scope: !7) +!27 = !DILocation(line: 8, column: 3, scope: !7) +!28 = !DISubprogram(name: "foo", scope: !1, file: !1, line: 1, type: !29, flags: DIFlagPrototyped, spFlags: DISPFlagOptimized, retainedNodes: !2) +!29 = !DISubroutineType(types: !30) +!30 = !{null, !31} +!31 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !32, size: 64) +!32 = !DIDerivedType(tag: DW_TAG_const_type, baseType: null) diff --git a/llvm/test/CodeGen/SBF/BTF/local-var.ll b/llvm/test/CodeGen/SBF/BTF/local-var.ll new file mode 100644 index 0000000000000..a16469638fb2a --- /dev/null +++ b/llvm/test/CodeGen/SBF/BTF/local-var.ll @@ -0,0 +1,107 @@ +; RUN: llc -sbf-enable-btf-emission -march=sbf -filetype=asm -o - %s | FileCheck -check-prefixes=CHECK %s + +; Source code: +; int foo(char a) { volatile short b = 0; return b; } +; Compilation flag: +; clang -target bpf -O2 -g -S -emit-llvm test.c + +; Function Attrs: nounwind +define dso_local i32 @foo(i8 signext) local_unnamed_addr #0 !dbg !7 { + %2 = alloca i16, align 2 + call void @llvm.dbg.value(metadata i8 %0, metadata !13, metadata !DIExpression()), !dbg !17 + %3 = bitcast i16* %2 to i8*, !dbg !18 + call void @llvm.lifetime.start.p0i8(i64 2, i8* nonnull %3), !dbg !18 + call void @llvm.dbg.declare(metadata i16* %2, metadata !14, metadata !DIExpression()), !dbg !19 + store volatile i16 0, i16* %2, align 2, !dbg !19, !tbaa !20 + %4 = load volatile i16, i16* %2, align 2, !dbg !24, !tbaa !20 + %5 = sext i16 %4 to i32, !dbg !24 + call void @llvm.lifetime.end.p0i8(i64 2, i8* nonnull %3), !dbg !25 + ret i32 %5, !dbg !26 +} + +; CHECK: .section .BTF,"",@progbits +; CHECK-NEXT: .short 60319 # 0xeb9f +; CHECK-NEXT: .byte 1 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .long 24 +; CHECK-NEXT: .long 0 +; CHECK-NEXT: .long 64 +; CHECK-NEXT: .long 64 +; CHECK-NEXT: .long 59 +; CHECK-NEXT: .long 1 # BTF_KIND_INT(id = 1) +; CHECK-NEXT: .long 16777216 # 0x1000000 +; CHECK-NEXT: .long 1 +; CHECK-NEXT: .long 16777224 # 0x1000008 +; CHECK-NEXT: .long 0 # BTF_KIND_FUNC_PROTO(id = 2) +; CHECK-NEXT: .long 218103809 # 0xd000001 +; CHECK-NEXT: .long 3 +; CHECK-NEXT: .long 6 +; CHECK-NEXT: .long 1 +; CHECK-NEXT: .long 8 # BTF_KIND_INT(id = 3) +; CHECK-NEXT: .long 16777216 # 0x1000000 +; CHECK-NEXT: .long 4 +; CHECK-NEXT: .long 16777248 # 0x1000020 +; CHECK-NEXT: .long 12 # BTF_KIND_FUNC(id = 4) +; CHECK-NEXT: .long 201326593 # 0xc000001 +; CHECK-NEXT: .long 2 +; CHECK-NEXT: .byte 0 # string offset=0 +; CHECK-NEXT: .ascii "char" # string offset=1 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .byte 97 # string offset=6 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii "int" # string offset=8 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii "foo" # string offset=12 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii ".text" # string offset=16 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii "/home/yhs/work/tests/llvm/bug/test.c" # string offset=22 +; CHECK-NEXT: .byte 0 + +; Function Attrs: nounwind readnone speculatable +declare void @llvm.dbg.declare(metadata, metadata, metadata) #1 + +; Function Attrs: argmemonly nounwind +declare void @llvm.lifetime.start.p0i8(i64, i8* nocapture) #2 + +; Function Attrs: argmemonly nounwind +declare void @llvm.lifetime.end.p0i8(i64, i8* nocapture) #2 + +; Function Attrs: nounwind readnone speculatable +declare void @llvm.dbg.value(metadata, metadata, metadata) #1 + +attributes #0 = { nounwind "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "frame-pointer"="all" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" } +attributes #1 = { nounwind readnone speculatable } +attributes #2 = { argmemonly nounwind } + +!llvm.dbg.cu = !{!0} +!llvm.module.flags = !{!3, !4, !5} +!llvm.ident = !{!6} + +!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 8.0.20181009 ", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, nameTableKind: None) +!1 = !DIFile(filename: "test.c", directory: "/home/yhs/work/tests/llvm/bug") +!2 = !{} +!3 = !{i32 2, !"Dwarf Version", i32 4} +!4 = !{i32 2, !"Debug Info Version", i32 3} +!5 = !{i32 1, !"wchar_size", i32 4} +!6 = !{!"clang version 8.0.20181009 "} +!7 = distinct !DISubprogram(name: "foo", scope: !1, file: !1, line: 1, type: !8, isLocal: false, isDefinition: true, scopeLine: 1, flags: DIFlagPrototyped, isOptimized: true, unit: !0, retainedNodes: !12) +!8 = !DISubroutineType(types: !9) +!9 = !{!10, !11} +!10 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +!11 = !DIBasicType(name: "char", size: 8, encoding: DW_ATE_signed_char) +!12 = !{!13, !14} +!13 = !DILocalVariable(name: "a", arg: 1, scope: !7, file: !1, line: 1, type: !11) +!14 = !DILocalVariable(name: "b", scope: !7, file: !1, line: 1, type: !15) +!15 = !DIDerivedType(tag: DW_TAG_volatile_type, baseType: !16) +!16 = !DIBasicType(name: "short", size: 16, encoding: DW_ATE_signed) +!17 = !DILocation(line: 1, column: 14, scope: !7) +!18 = !DILocation(line: 1, column: 19, scope: !7) +!19 = !DILocation(line: 1, column: 34, scope: !7) +!20 = !{!21, !21, i64 0} +!21 = !{!"short", !22, i64 0} +!22 = !{!"omnipotent char", !23, i64 0} +!23 = !{!"Simple C/C++ TBAA"} +!24 = !DILocation(line: 1, column: 49, scope: !7) +!25 = !DILocation(line: 1, column: 52, scope: !7) +!26 = !DILocation(line: 1, column: 42, scope: !7) diff --git a/llvm/test/CodeGen/SBF/BTF/longlong.ll b/llvm/test/CodeGen/SBF/BTF/longlong.ll new file mode 100644 index 0000000000000..334b8bae53e60 --- /dev/null +++ b/llvm/test/CodeGen/SBF/BTF/longlong.ll @@ -0,0 +1,41 @@ +; RUN: llc -sbf-enable-btf-emission -march=sbf -filetype=asm -o - %s | FileCheck -check-prefixes=CHECK %s + +; Source code: +; long long a; +; Compilation flag: +; clang -target bpf -O2 -g -S -emit-llvm t.c + +@a = common dso_local local_unnamed_addr global i64 0, align 8, !dbg !0 + +!llvm.dbg.cu = !{!2} +!llvm.module.flags = !{!7, !8, !9} +!llvm.ident = !{!10} + +; CHECK: .section .BTF,"",@progbits +; CHECK-NEXT: .short 60319 # 0xeb9f +; CHECK-NEXT: .byte 1 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .long 24 +; CHECK-NEXT: .long 0 +; CHECK-NEXT: .long 16 +; CHECK-NEXT: .long 16 +; CHECK-NEXT: .long 15 +; CHECK-NEXT: .long 1 # BTF_KIND_INT(id = 1) +; CHECK-NEXT: .long 16777216 # 0x1000000 +; CHECK-NEXT: .long 8 +; CHECK-NEXT: .long 16777280 # 0x1000040 +; CHECK-NEXT: .byte 0 # string offset=0 +; CHECK-NEXT: .ascii "long long int" # string offset=1 +; CHECK-NEXT: .byte 0 + +!0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression()) +!1 = distinct !DIGlobalVariable(name: "a", scope: !2, file: !3, line: 1, type: !6, isLocal: false, isDefinition: true) +!2 = distinct !DICompileUnit(language: DW_LANG_C99, file: !3, producer: "clang version 8.0.0 (trunk 344789) (llvm/trunk 344782)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !4, globals: !5, nameTableKind: None) +!3 = !DIFile(filename: "t.c", directory: "/home/yhs/tmp") +!4 = !{} +!5 = !{!0} +!6 = !DIBasicType(name: "long long int", size: 64, encoding: DW_ATE_signed) +!7 = !{i32 2, !"Dwarf Version", i32 4} +!8 = !{i32 2, !"Debug Info Version", i32 3} +!9 = !{i32 1, !"wchar_size", i32 4} +!10 = !{!"clang version 8.0.0 (trunk 344789) (llvm/trunk 344782)"} diff --git a/llvm/test/CodeGen/SBF/BTF/map-def-2.ll b/llvm/test/CodeGen/SBF/BTF/map-def-2.ll new file mode 100644 index 0000000000000..487a4ef1c003c --- /dev/null +++ b/llvm/test/CodeGen/SBF/BTF/map-def-2.ll @@ -0,0 +1,89 @@ +; RUN: llc -sbf-enable-btf-emission -march=sbf -filetype=asm -o - %s | FileCheck -check-prefixes=CHECK %s +; +; Source code: +; struct key_type { +; int a1; +; }; +; typedef struct map_type { +; struct key_type *key; +; } _map_type; +; typedef _map_type __map_type; +; __map_type __attribute__((section(".maps"))) hash_map; +; Compilation flag: +; clang -target bpf -O2 -g -S -emit-llvm t2.c + +%struct.map_type = type { %struct.key_type* } +%struct.key_type = type { i32 } + +@hash_map = dso_local local_unnamed_addr global %struct.map_type zeroinitializer, section ".maps", align 8, !dbg !0 + +; CHECK: .long 0 # BTF_KIND_PTR(id = 1) +; CHECK-NEXT: .long 33554432 # 0x2000000 +; CHECK-NEXT: .long 2 +; CHECK-NEXT: .long 1 # BTF_KIND_STRUCT(id = 2) +; CHECK-NEXT: .long 67108865 # 0x4000001 +; CHECK-NEXT: .long 4 +; CHECK-NEXT: .long 10 +; CHECK-NEXT: .long 3 +; CHECK-NEXT: .long 0 # 0x0 +; CHECK-NEXT: .long 13 # BTF_KIND_INT(id = 3) +; CHECK-NEXT: .long 16777216 # 0x1000000 +; CHECK-NEXT: .long 4 +; CHECK-NEXT: .long 16777248 # 0x1000020 +; CHECK-NEXT: .long 17 # BTF_KIND_TYPEDEF(id = 4) +; CHECK-NEXT: .long 134217728 # 0x8000000 +; CHECK-NEXT: .long 5 +; CHECK-NEXT: .long 28 # BTF_KIND_TYPEDEF(id = 5) +; CHECK-NEXT: .long 134217728 # 0x8000000 +; CHECK-NEXT: .long 6 +; CHECK-NEXT: .long 38 # BTF_KIND_STRUCT(id = 6) +; CHECK-NEXT: .long 67108865 # 0x4000001 +; CHECK-NEXT: .long 8 +; CHECK-NEXT: .long 47 +; CHECK-NEXT: .long 1 +; CHECK-NEXT: .long 0 # 0x0 +; CHECK-NEXT: .long 51 # BTF_KIND_VAR(id = 7) +; CHECK-NEXT: .long 234881024 # 0xe000000 +; CHECK-NEXT: .long 4 +; CHECK-NEXT: .long 1 +; CHECK-NEXT: .long 60 # BTF_KIND_DATASEC(id = 8) +; CHECK-NEXT: .long 251658241 # 0xf000001 +; CHECK-NEXT: .long 0 +; CHECK-NEXT: .long 7 +; CHECK-NEXT: .long hash_map +; CHECK-NEXT: .long 8 + +; CHECK: .ascii "key_type" # string offset=1 +; CHECK: .ascii "a1" # string offset=10 +; CHECK: .ascii "int" # string offset=13 +; CHECK: .ascii "__map_type" # string offset=17 +; CHECK: .ascii "_map_type" # string offset=28 +; CHECK: .ascii "map_type" # string offset=38 +; CHECK: .ascii "key" # string offset=47 +; CHECK: .ascii "hash_map" # string offset=51 +; CHECK: .ascii ".maps" # string offset=60 + +!llvm.dbg.cu = !{!2} +!llvm.module.flags = !{!16, !17, !18} +!llvm.ident = !{!19} + +!0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression()) +!1 = distinct !DIGlobalVariable(name: "hash_map", scope: !2, file: !3, line: 8, type: !6, isLocal: false, isDefinition: true) +!2 = distinct !DICompileUnit(language: DW_LANG_C99, file: !3, producer: "clang version 11.0.0 (https://github.com/llvm/llvm-project.git b8409c03ed90807f3d49c7d98dceea98cf461f7a)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !4, globals: !5, splitDebugInlining: false, nameTableKind: None) +!3 = !DIFile(filename: "t2.c", directory: "/tmp/home/yhs/tmp1") +!4 = !{} +!5 = !{!0} +!6 = !DIDerivedType(tag: DW_TAG_typedef, name: "__map_type", file: !3, line: 7, baseType: !7) +!7 = !DIDerivedType(tag: DW_TAG_typedef, name: "_map_type", file: !3, line: 6, baseType: !8) +!8 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "map_type", file: !3, line: 4, size: 64, elements: !9) +!9 = !{!10} +!10 = !DIDerivedType(tag: DW_TAG_member, name: "key", scope: !8, file: !3, line: 5, baseType: !11, size: 64) +!11 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !12, size: 64) +!12 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "key_type", file: !3, line: 1, size: 32, elements: !13) +!13 = !{!14} +!14 = !DIDerivedType(tag: DW_TAG_member, name: "a1", scope: !12, file: !3, line: 2, baseType: !15, size: 32) +!15 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +!16 = !{i32 7, !"Dwarf Version", i32 4} +!17 = !{i32 2, !"Debug Info Version", i32 3} +!18 = !{i32 1, !"wchar_size", i32 4} +!19 = !{!"clang version 11.0.0 (https://github.com/llvm/llvm-project.git b8409c03ed90807f3d49c7d98dceea98cf461f7a)"} diff --git a/llvm/test/CodeGen/SBF/BTF/map-def-3.ll b/llvm/test/CodeGen/SBF/BTF/map-def-3.ll new file mode 100644 index 0000000000000..674a8b91fd38a --- /dev/null +++ b/llvm/test/CodeGen/SBF/BTF/map-def-3.ll @@ -0,0 +1,64 @@ +; RUN: llc -sbf-enable-btf-emission -march=sbf -filetype=asm -o - %s | FileCheck -check-prefixes=CHECK %s +; +; Source code: +; struct key_type { +; int a1; +; }; +; const struct key_type __attribute__((section(".maps"))) hash_map; +; Compilation flag: +; clang -target bpf -O2 -g -S -emit-llvm t3.c + +%struct.key_type = type { i32 } + +@hash_map = dso_local local_unnamed_addr constant %struct.key_type zeroinitializer, section ".maps", align 4, !dbg !0 + +; CHECK: .long 1 # BTF_KIND_INT(id = 1) +; CHECK-NEXT: .long 16777216 # 0x1000000 +; CHECK-NEXT: .long 4 +; CHECK-NEXT: .long 16777248 # 0x1000020 +; CHECK-NEXT: .long 0 # BTF_KIND_CONST(id = 2) +; CHECK-NEXT: .long 167772160 # 0xa000000 +; CHECK-NEXT: .long 3 +; CHECK-NEXT: .long 5 # BTF_KIND_STRUCT(id = 3) +; CHECK-NEXT: .long 67108865 # 0x4000001 +; CHECK-NEXT: .long 4 +; CHECK-NEXT: .long 14 +; CHECK-NEXT: .long 1 +; CHECK-NEXT: .long 0 # 0x0 +; CHECK-NEXT: .long 17 # BTF_KIND_VAR(id = 4) +; CHECK-NEXT: .long 234881024 # 0xe000000 +; CHECK-NEXT: .long 2 +; CHECK-NEXT: .long 1 +; CHECK-NEXT: .long 26 # BTF_KIND_DATASEC(id = 5) +; CHECK-NEXT: .long 251658241 # 0xf000001 +; CHECK-NEXT: .long 0 +; CHECK-NEXT: .long 4 +; CHECK-NEXT: .long hash_map +; CHECK-NEXT: .long 4 + +; CHECK: .ascii "int" # string offset=1 +; CHECK: .ascii "key_type" # string offset=5 +; CHECK: .ascii "a1" # string offset=14 +; CHECK: .ascii "hash_map" # string offset=17 +; CHECK: .ascii ".maps" # string offset=26 + + +!llvm.dbg.cu = !{!2} +!llvm.module.flags = !{!11, !12, !13} +!llvm.ident = !{!14} + +!0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression()) +!1 = distinct !DIGlobalVariable(name: "hash_map", scope: !2, file: !3, line: 4, type: !6, isLocal: false, isDefinition: true) +!2 = distinct !DICompileUnit(language: DW_LANG_C99, file: !3, producer: "clang version 11.0.0 (https://github.com/llvm/llvm-project.git 5bd074629f00d4798674b411cf00216f38016483)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !4, globals: !5, splitDebugInlining: false, nameTableKind: None) +!3 = !DIFile(filename: "t3.c", directory: "/tmp/home/yhs/tmp1") +!4 = !{} +!5 = !{!0} +!6 = !DIDerivedType(tag: DW_TAG_const_type, baseType: !7) +!7 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "key_type", file: !3, line: 1, size: 32, elements: !8) +!8 = !{!9} +!9 = !DIDerivedType(tag: DW_TAG_member, name: "a1", scope: !7, file: !3, line: 2, baseType: !10, size: 32) +!10 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +!11 = !{i32 7, !"Dwarf Version", i32 4} +!12 = !{i32 2, !"Debug Info Version", i32 3} +!13 = !{i32 1, !"wchar_size", i32 4} +!14 = !{!"clang version 11.0.0 (https://github.com/llvm/llvm-project.git 5bd074629f00d4798674b411cf00216f38016483)"} diff --git a/llvm/test/CodeGen/SBF/BTF/map-def.ll b/llvm/test/CodeGen/SBF/BTF/map-def.ll new file mode 100644 index 0000000000000..1d6514c0999fe --- /dev/null +++ b/llvm/test/CodeGen/SBF/BTF/map-def.ll @@ -0,0 +1,119 @@ +; RUN: llc -sbf-enable-btf-emission -march=sbf -filetype=asm -o - %s | FileCheck -check-prefixes=CHECK %s + +; Source code: +; struct key_type { +; int a; +; int b; +; }; +; struct map_type { +; struct key_type *key; +; unsigned *value; +; }; +; struct map_type __attribute__((section(".maps"))) hash_map; +; Compilation flag: +; clang -target bpf -O2 -g -S -emit-llvm t.c + +%struct.map_type = type { %struct.key_type*, i32* } +%struct.key_type = type { i32, i32 } + +@hash_map = dso_local local_unnamed_addr global %struct.map_type zeroinitializer, section ".maps", align 8, !dbg !0 + +; CHECK: .section .BTF,"",@progbits +; CHECK-NEXT: .short 60319 # 0xeb9f +; CHECK-NEXT: .byte 1 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .long 24 +; CHECK-NEXT: .long 0 +; CHECK-NEXT: .long 168 +; CHECK-NEXT: .long 168 +; CHECK-NEXT: .long 65 +; CHECK-NEXT: .long 0 # BTF_KIND_PTR(id = 1) +; CHECK-NEXT: .long 33554432 # 0x2000000 +; CHECK-NEXT: .long 2 +; CHECK-NEXT: .long 1 # BTF_KIND_STRUCT(id = 2) +; CHECK-NEXT: .long 67108866 # 0x4000002 +; CHECK-NEXT: .long 8 +; CHECK-NEXT: .long 10 +; CHECK-NEXT: .long 3 +; CHECK-NEXT: .long 0 # 0x0 +; CHECK-NEXT: .long 12 +; CHECK-NEXT: .long 3 +; CHECK-NEXT: .long 32 # 0x20 +; CHECK-NEXT: .long 14 # BTF_KIND_INT(id = 3) +; CHECK-NEXT: .long 16777216 # 0x1000000 +; CHECK-NEXT: .long 4 +; CHECK-NEXT: .long 16777248 # 0x1000020 +; CHECK-NEXT: .long 0 # BTF_KIND_PTR(id = 4) +; CHECK-NEXT: .long 33554432 # 0x2000000 +; CHECK-NEXT: .long 5 +; CHECK-NEXT: .long 18 # BTF_KIND_INT(id = 5) +; CHECK-NEXT: .long 16777216 # 0x1000000 +; CHECK-NEXT: .long 4 +; CHECK-NEXT: .long 32 # 0x20 +; CHECK-NEXT: .long 31 # BTF_KIND_STRUCT(id = 6) +; CHECK-NEXT: .long 67108866 # 0x4000002 +; CHECK-NEXT: .long 16 +; CHECK-NEXT: .long 40 +; CHECK-NEXT: .long 1 +; CHECK-NEXT: .long 0 # 0x0 +; CHECK-NEXT: .long 44 +; CHECK-NEXT: .long 4 +; CHECK-NEXT: .long 64 # 0x40 +; CHECK-NEXT: .long 50 # BTF_KIND_VAR(id = 7) +; CHECK-NEXT: .long 234881024 # 0xe000000 +; CHECK-NEXT: .long 6 +; CHECK-NEXT: .long 1 +; CHECK-NEXT: .long 59 # BTF_KIND_DATASEC(id = 8) +; CHECK-NEXT: .long 251658241 # 0xf000001 +; CHECK-NEXT: .long 0 +; CHECK-NEXT: .long 7 +; CHECK-NEXT: .long hash_map +; CHECK-NEXT: .long 16 +; CHECK-NEXT: .byte 0 # string offset=0 +; CHECK-NEXT: .ascii "key_type" # string offset=1 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .byte 97 # string offset=10 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .byte 98 # string offset=12 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii "int" # string offset=14 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii "unsigned int" # string offset=18 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii "map_type" # string offset=31 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii "key" # string offset=40 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii "value" # string offset=44 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii "hash_map" # string offset=50 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii ".maps" # string offset=59 +; CHECK-NEXT: .byte 0 + +!llvm.dbg.cu = !{!2} +!llvm.module.flags = !{!18, !19, !20} +!llvm.ident = !{!21} + +!0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression()) +!1 = distinct !DIGlobalVariable(name: "hash_map", scope: !2, file: !3, line: 9, type: !6, isLocal: false, isDefinition: true) +!2 = distinct !DICompileUnit(language: DW_LANG_C99, file: !3, producer: "clang version 9.0.0 (trunk 364157) (llvm/trunk 364156)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !4, globals: !5, nameTableKind: None) +!3 = !DIFile(filename: "t.c", directory: "/tmp/home/yhs/work/tests/llvm") +!4 = !{} +!5 = !{!0} +!6 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "map_type", file: !3, line: 5, size: 128, elements: !7) +!7 = !{!8, !15} +!8 = !DIDerivedType(tag: DW_TAG_member, name: "key", scope: !6, file: !3, line: 6, baseType: !9, size: 64) +!9 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !10, size: 64) +!10 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "key_type", file: !3, line: 1, size: 64, elements: !11) +!11 = !{!12, !14} +!12 = !DIDerivedType(tag: DW_TAG_member, name: "a", scope: !10, file: !3, line: 2, baseType: !13, size: 32) +!13 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +!14 = !DIDerivedType(tag: DW_TAG_member, name: "b", scope: !10, file: !3, line: 3, baseType: !13, size: 32, offset: 32) +!15 = !DIDerivedType(tag: DW_TAG_member, name: "value", scope: !6, file: !3, line: 7, baseType: !16, size: 64, offset: 64) +!16 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !17, size: 64) +!17 = !DIBasicType(name: "unsigned int", size: 32, encoding: DW_ATE_unsigned) +!18 = !{i32 2, !"Dwarf Version", i32 4} +!19 = !{i32 2, !"Debug Info Version", i32 3} +!20 = !{i32 1, !"wchar_size", i32 4} +!21 = !{!"clang version 9.0.0 (trunk 364157) (llvm/trunk 364156)"} diff --git a/llvm/test/CodeGen/SBF/BTF/pruning-const.ll b/llvm/test/CodeGen/SBF/BTF/pruning-const.ll new file mode 100644 index 0000000000000..7ebe980bdd7dd --- /dev/null +++ b/llvm/test/CodeGen/SBF/BTF/pruning-const.ll @@ -0,0 +1,119 @@ +; RUN: llc -sbf-enable-btf-emission -march=sbf -filetype=asm -o - %s | FileCheck -check-prefixes=CHECK %s +; Source: +; struct tt; +; struct s1 { const struct tt *mp; }; +; int test1(struct s1 *arg) +; { +; return 0; +; } +; +; struct tt { int m1; int m2; }; +; struct s2 { const struct tt m3; }; +; int test2(struct s2 *arg) +; { +; return arg->m3.m1; +; } +; Compilation flags: +; clang -target bpf -O2 -g -S -emit-llvm t.c + +%struct.s1 = type { %struct.tt* } +%struct.tt = type { i32, i32 } +%struct.s2 = type { %struct.tt } + +; Function Attrs: norecurse nounwind readnone +define dso_local i32 @test1(%struct.s1* nocapture readnone %arg) local_unnamed_addr #0 !dbg !7 { +entry: + call void @llvm.dbg.value(metadata %struct.s1* %arg, metadata !22, metadata !DIExpression()), !dbg !23 + ret i32 0, !dbg !24 +} + +; Function Attrs: norecurse nounwind readonly +define dso_local i32 @test2(%struct.s2* nocapture readonly %arg) local_unnamed_addr #1 !dbg !25 { +entry: + call void @llvm.dbg.value(metadata %struct.s2* %arg, metadata !33, metadata !DIExpression()), !dbg !34 + %m1 = getelementptr inbounds %struct.s2, %struct.s2* %arg, i64 0, i32 0, i32 0, !dbg !35 + %0 = load i32, i32* %m1, align 4, !dbg !35, !tbaa !36 + ret i32 %0, !dbg !42 +} + +; CHECK: .long 0 # BTF_KIND_CONST(id = 4) +; CHECK-NEXT: .long 167772160 # 0xa000000 +; CHECK-NEXT: .long 10 + +; CHECK: .long 60 # BTF_KIND_STRUCT(id = 9) +; CHECK-NEXT: .long 67108865 # 0x4000001 +; CHECK-NEXT: .long 8 +; CHECK-NEXT: .long 63 +; CHECK-NEXT: .long 4 +; CHECK-NEXT: .long 0 # 0x0 + +; CHECK: .long 66 # BTF_KIND_STRUCT(id = 10) +; CHECK-NEXT: .long 67108866 # 0x4000002 +; CHECK-NEXT: .long 8 +; CHECK-NEXT: .long 69 +; CHECK-NEXT: .long 6 +; CHECK-NEXT: .long 0 # 0x0 +; CHECK-NEXT: .long 72 +; CHECK-NEXT: .long 6 +; CHECK-NEXT: .long 32 # 0x20 + +; CHECK: .ascii "s2" # string offset=60 +; CHECK: .ascii "m3" # string offset=63 +; CHECK: .ascii "tt" # string offset=66 +; CHECK: .ascii "m1" # string offset=69 +; CHECK: .ascii "m2" # string offset=72 + +; Function Attrs: nounwind readnone speculatable willreturn +declare void @llvm.dbg.value(metadata, metadata, metadata) #2 + +attributes #0 = { norecurse nounwind readnone "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" } +attributes #1 = { norecurse nounwind readonly "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" } +attributes #2 = { nounwind readnone speculatable willreturn } + +!llvm.dbg.cu = !{!0} +!llvm.module.flags = !{!3, !4, !5} +!llvm.ident = !{!6} + +!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 11.0.0 (https://github.com/llvm/llvm-project.git 7cfd267c518aba226b34b7fbfe8db70000b22053)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, splitDebugInlining: false, nameTableKind: None) +!1 = !DIFile(filename: "t.c", directory: "/tmp/home/yhs/work/tests/btf") +!2 = !{} +!3 = !{i32 7, !"Dwarf Version", i32 4} +!4 = !{i32 2, !"Debug Info Version", i32 3} +!5 = !{i32 1, !"wchar_size", i32 4} +!6 = !{!"clang version 11.0.0 (https://github.com/llvm/llvm-project.git 7cfd267c518aba226b34b7fbfe8db70000b22053)"} +!7 = distinct !DISubprogram(name: "test1", scope: !1, file: !1, line: 3, type: !8, scopeLine: 4, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !21) +!8 = !DISubroutineType(types: !9) +!9 = !{!10, !11} +!10 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +!11 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !12, size: 64) +!12 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "s1", file: !1, line: 2, size: 64, elements: !13) +!13 = !{!14} +!14 = !DIDerivedType(tag: DW_TAG_member, name: "mp", scope: !12, file: !1, line: 2, baseType: !15, size: 64) +!15 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !16, size: 64) +!16 = !DIDerivedType(tag: DW_TAG_const_type, baseType: !17) +!17 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "tt", file: !1, line: 8, size: 64, elements: !18) +!18 = !{!19, !20} +!19 = !DIDerivedType(tag: DW_TAG_member, name: "m1", scope: !17, file: !1, line: 8, baseType: !10, size: 32) +!20 = !DIDerivedType(tag: DW_TAG_member, name: "m2", scope: !17, file: !1, line: 8, baseType: !10, size: 32, offset: 32) +!21 = !{!22} +!22 = !DILocalVariable(name: "arg", arg: 1, scope: !7, file: !1, line: 3, type: !11) +!23 = !DILocation(line: 0, scope: !7) +!24 = !DILocation(line: 5, column: 3, scope: !7) +!25 = distinct !DISubprogram(name: "test2", scope: !1, file: !1, line: 10, type: !26, scopeLine: 11, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !32) +!26 = !DISubroutineType(types: !27) +!27 = !{!10, !28} +!28 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !29, size: 64) +!29 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "s2", file: !1, line: 9, size: 64, elements: !30) +!30 = !{!31} +!31 = !DIDerivedType(tag: DW_TAG_member, name: "m3", scope: !29, file: !1, line: 9, baseType: !16, size: 64) +!32 = !{!33} +!33 = !DILocalVariable(name: "arg", arg: 1, scope: !25, file: !1, line: 10, type: !28) +!34 = !DILocation(line: 0, scope: !25) +!35 = !DILocation(line: 12, column: 18, scope: !25) +!36 = !{!37, !39, i64 0} +!37 = !{!"s2", !38, i64 0} +!38 = !{!"tt", !39, i64 0, !39, i64 4} +!39 = !{!"int", !40, i64 0} +!40 = !{!"omnipotent char", !41, i64 0} +!41 = !{!"Simple C/C++ TBAA"} +!42 = !DILocation(line: 12, column: 3, scope: !25) diff --git a/llvm/test/CodeGen/SBF/BTF/pruning-multi-derived-type.ll b/llvm/test/CodeGen/SBF/BTF/pruning-multi-derived-type.ll new file mode 100644 index 0000000000000..1011341a70610 --- /dev/null +++ b/llvm/test/CodeGen/SBF/BTF/pruning-multi-derived-type.ll @@ -0,0 +1,86 @@ +; RUN: llc -sbf-enable-btf-emission -march=sbf -filetype=asm -o - %s | FileCheck -check-prefixes=CHECK %s +; Source: +; struct t1 { +; int a; +; }; +; struct t2 { +; const struct t1 * const a; +; }; +; int foo(struct t2 *arg) { return 0; } +; int bar(const struct t1 * const arg) { return 0; } +; Compilation flags: +; clang -target bpf -O2 -g -S -emit-llvm t.c + +%struct.t2 = type { %struct.t1* } +%struct.t1 = type { i32 } + +; Function Attrs: mustprogress nofree norecurse nosync nounwind readnone willreturn +define dso_local i32 @foo(%struct.t2* nocapture noundef readnone %arg) local_unnamed_addr #0 !dbg !7 { +entry: + call void @llvm.dbg.value(metadata %struct.t2* %arg, metadata !22, metadata !DIExpression()), !dbg !23 + ret i32 0, !dbg !24 +} + +; Function Attrs: mustprogress nofree norecurse nosync nounwind readnone willreturn +define dso_local i32 @bar(%struct.t1* nocapture noundef readnone %arg) local_unnamed_addr #0 !dbg !25 { +entry: + call void @llvm.dbg.value(metadata %struct.t1* %arg, metadata !29, metadata !DIExpression()), !dbg !30 + ret i32 0, !dbg !31 +} + +; CHECK: .long 10 # BTF_KIND_INT(id = 7) +; CHECK-NEXT: .long 16777216 # 0x1000000 +; CHECK-NEXT: .long 4 +; CHECK-NEXT: .long 16777248 # 0x1000020 + +; CHECK: .long 69 # BTF_KIND_STRUCT(id = 9) +; CHECK-NEXT: .long 67108865 # 0x4000001 +; CHECK-NEXT: .long 4 +; CHECK-NEXT: .long 4 +; CHECK-NEXT: .long 7 + +; CHECK: .byte 97 # string offset=4 +; CHECK: .ascii "t1" # string offset=69 + +; Function Attrs: nofree nosync nounwind readnone speculatable willreturn +declare void @llvm.dbg.value(metadata, metadata, metadata) #1 + +attributes #0 = { mustprogress nofree norecurse nosync nounwind readnone willreturn "frame-pointer"="all" "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" } +attributes #1 = { nofree nosync nounwind readnone speculatable willreturn } + +!llvm.dbg.cu = !{!0} +!llvm.module.flags = !{!2, !3, !4, !5} +!llvm.ident = !{!6} + +!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 15.0.0 (https://github.com/llvm/llvm-project.git c34c8afcb85ae9142d0f783bb899c464e8bd2356)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, splitDebugInlining: false, nameTableKind: None) +!1 = !DIFile(filename: "test.c", directory: "/tmp/home/yhs/work/tests/llvm/btf_ptr", checksumkind: CSK_MD5, checksum: "d43a0541e830263021772349589e47a5") +!2 = !{i32 7, !"Dwarf Version", i32 5} +!3 = !{i32 2, !"Debug Info Version", i32 3} +!4 = !{i32 1, !"wchar_size", i32 4} +!5 = !{i32 7, !"frame-pointer", i32 2} +!6 = !{!"clang version 15.0.0 (https://github.com/llvm/llvm-project.git c34c8afcb85ae9142d0f783bb899c464e8bd2356)"} +!7 = distinct !DISubprogram(name: "foo", scope: !1, file: !1, line: 7, type: !8, scopeLine: 7, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !21) +!8 = !DISubroutineType(types: !9) +!9 = !{!10, !11} +!10 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +!11 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !12, size: 64) +!12 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "t2", file: !1, line: 4, size: 64, elements: !13) +!13 = !{!14} +!14 = !DIDerivedType(tag: DW_TAG_member, name: "a", scope: !12, file: !1, line: 5, baseType: !15, size: 64) +!15 = !DIDerivedType(tag: DW_TAG_const_type, baseType: !16) +!16 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !17, size: 64) +!17 = !DIDerivedType(tag: DW_TAG_const_type, baseType: !18) +!18 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "t1", file: !1, line: 1, size: 32, elements: !19) +!19 = !{!20} +!20 = !DIDerivedType(tag: DW_TAG_member, name: "a", scope: !18, file: !1, line: 2, baseType: !10, size: 32) +!21 = !{!22} +!22 = !DILocalVariable(name: "arg", arg: 1, scope: !7, file: !1, line: 7, type: !11) +!23 = !DILocation(line: 0, scope: !7) +!24 = !DILocation(line: 7, column: 27, scope: !7) +!25 = distinct !DISubprogram(name: "bar", scope: !1, file: !1, line: 8, type: !26, scopeLine: 8, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !28) +!26 = !DISubroutineType(types: !27) +!27 = !{!10, !15} +!28 = !{!29} +!29 = !DILocalVariable(name: "arg", arg: 1, scope: !25, file: !1, line: 8, type: !15) +!30 = !DILocation(line: 0, scope: !25) +!31 = !DILocation(line: 8, column: 40, scope: !25) diff --git a/llvm/test/CodeGen/SBF/BTF/pruning-typedef.ll b/llvm/test/CodeGen/SBF/BTF/pruning-typedef.ll new file mode 100644 index 0000000000000..5dd38e6bbeed3 --- /dev/null +++ b/llvm/test/CodeGen/SBF/BTF/pruning-typedef.ll @@ -0,0 +1,127 @@ +; RUN: llc -sbf-enable-btf-emission -march=sbf -filetype=asm -o - %s | FileCheck -check-prefixes=CHECK %s +; Source: +; struct tt; +; typedef struct tt _tt; +; typedef _tt __tt; +; struct s1 { __tt *mp; }; +; int test1(struct s1 *arg) +; { +; return 0; +; } +; +; struct tt { int m1; int m2; }; +; struct s2 { __tt m3; }; +; int test2(struct s2 *arg) +; { +; return arg->m3.m1; +; } +; Compilation flags: +; clang -target bpf -O2 -g -S -emit-llvm t.c + +%struct.s1 = type { %struct.tt* } +%struct.tt = type { i32, i32 } +%struct.s2 = type { %struct.tt } + +; Function Attrs: norecurse nounwind readnone +define dso_local i32 @test1(%struct.s1* nocapture readnone %arg) local_unnamed_addr #0 !dbg !7 { +entry: + call void @llvm.dbg.value(metadata %struct.s1* %arg, metadata !23, metadata !DIExpression()), !dbg !24 + ret i32 0, !dbg !25 +} + +; Function Attrs: norecurse nounwind readonly +define dso_local i32 @test2(%struct.s2* nocapture readonly %arg) local_unnamed_addr #1 !dbg !26 { +entry: + call void @llvm.dbg.value(metadata %struct.s2* %arg, metadata !34, metadata !DIExpression()), !dbg !35 + %m1 = getelementptr inbounds %struct.s2, %struct.s2* %arg, i64 0, i32 0, i32 0, !dbg !36 + %0 = load i32, i32* %m1, align 4, !dbg !36, !tbaa !37 + ret i32 %0, !dbg !43 +} + +; CHECK: .long 7 # BTF_KIND_TYPEDEF(id = 4) +; CHECK-NEXT: .long 134217728 # 0x8000000 +; CHECK-NEXT: .long 5 +; CHECK-NEXT: .long 12 # BTF_KIND_TYPEDEF(id = 5) +; CHECK-NEXT: .long 134217728 # 0x8000000 +; CHECK-NEXT: .long 11 + +; CHECK: .long 69 # BTF_KIND_STRUCT(id = 10) +; CHECK-NEXT: .long 67108865 # 0x4000001 +; CHECK-NEXT: .long 8 +; CHECK-NEXT: .long 72 +; CHECK-NEXT: .long 4 +; CHECK-NEXT: .long 0 # 0x0 + +; CHECK: .long 75 # BTF_KIND_STRUCT(id = 11) +; CHECK-NEXT: .long 67108866 # 0x4000002 +; CHECK-NEXT: .long 8 +; CHECK-NEXT: .long 78 +; CHECK-NEXT: .long 7 +; CHECK-NEXT: .long 0 # 0x0 +; CHECK-NEXT: .long 81 +; CHECK-NEXT: .long 7 +; CHECK-NEXT: .long 32 # 0x20 + +; CHECK: .ascii "__tt" # string offset=7 +; CHECK: .ascii "_tt" # string offset=12 +; CHECK: .ascii "s2" # string offset=69 +; CHECK: .ascii "m3" # string offset=72 +; CHECK: .ascii "tt" # string offset=75 +; CHECK: .ascii "m1" # string offset=78 +; CHECK: .ascii "m2" # string offset=81 + +; Function Attrs: nounwind readnone speculatable willreturn +declare void @llvm.dbg.value(metadata, metadata, metadata) #2 + +attributes #0 = { norecurse nounwind readnone "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" } +attributes #1 = { norecurse nounwind readonly "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" } +attributes #2 = { nounwind readnone speculatable willreturn } + +!llvm.dbg.cu = !{!0} +!llvm.module.flags = !{!3, !4, !5} +!llvm.ident = !{!6} + +!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 11.0.0 (https://github.com/llvm/llvm-project.git 7cfd267c518aba226b34b7fbfe8db70000b22053)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, splitDebugInlining: false, nameTableKind: None) +!1 = !DIFile(filename: "t.c", directory: "/tmp/home/yhs/work/tests/btf") +!2 = !{} +!3 = !{i32 7, !"Dwarf Version", i32 4} +!4 = !{i32 2, !"Debug Info Version", i32 3} +!5 = !{i32 1, !"wchar_size", i32 4} +!6 = !{!"clang version 11.0.0 (https://github.com/llvm/llvm-project.git 7cfd267c518aba226b34b7fbfe8db70000b22053)"} +!7 = distinct !DISubprogram(name: "test1", scope: !1, file: !1, line: 5, type: !8, scopeLine: 6, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !22) +!8 = !DISubroutineType(types: !9) +!9 = !{!10, !11} +!10 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +!11 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !12, size: 64) +!12 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "s1", file: !1, line: 4, size: 64, elements: !13) +!13 = !{!14} +!14 = !DIDerivedType(tag: DW_TAG_member, name: "mp", scope: !12, file: !1, line: 4, baseType: !15, size: 64) +!15 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !16, size: 64) +!16 = !DIDerivedType(tag: DW_TAG_typedef, name: "__tt", file: !1, line: 3, baseType: !17) +!17 = !DIDerivedType(tag: DW_TAG_typedef, name: "_tt", file: !1, line: 2, baseType: !18) +!18 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "tt", file: !1, line: 10, size: 64, elements: !19) +!19 = !{!20, !21} +!20 = !DIDerivedType(tag: DW_TAG_member, name: "m1", scope: !18, file: !1, line: 10, baseType: !10, size: 32) +!21 = !DIDerivedType(tag: DW_TAG_member, name: "m2", scope: !18, file: !1, line: 10, baseType: !10, size: 32, offset: 32) +!22 = !{!23} +!23 = !DILocalVariable(name: "arg", arg: 1, scope: !7, file: !1, line: 5, type: !11) +!24 = !DILocation(line: 0, scope: !7) +!25 = !DILocation(line: 7, column: 3, scope: !7) +!26 = distinct !DISubprogram(name: "test2", scope: !1, file: !1, line: 12, type: !27, scopeLine: 13, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !33) +!27 = !DISubroutineType(types: !28) +!28 = !{!10, !29} +!29 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !30, size: 64) +!30 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "s2", file: !1, line: 11, size: 64, elements: !31) +!31 = !{!32} +!32 = !DIDerivedType(tag: DW_TAG_member, name: "m3", scope: !30, file: !1, line: 11, baseType: !16, size: 64) +!33 = !{!34} +!34 = !DILocalVariable(name: "arg", arg: 1, scope: !26, file: !1, line: 12, type: !29) +!35 = !DILocation(line: 0, scope: !26) +!36 = !DILocation(line: 14, column: 18, scope: !26) +!37 = !{!38, !40, i64 0} +!38 = !{!"s2", !39, i64 0} +!39 = !{!"tt", !40, i64 0, !40, i64 4} +!40 = !{!"int", !41, i64 0} +!41 = !{!"omnipotent char", !42, i64 0} +!42 = !{!"Simple C/C++ TBAA"} +!43 = !DILocation(line: 14, column: 3, scope: !26) diff --git a/llvm/test/CodeGen/SBF/BTF/ptr-const-void.ll b/llvm/test/CodeGen/SBF/BTF/ptr-const-void.ll new file mode 100644 index 0000000000000..50e2a6754a875 --- /dev/null +++ b/llvm/test/CodeGen/SBF/BTF/ptr-const-void.ll @@ -0,0 +1,42 @@ +; RUN: llc -sbf-enable-btf-emission -march=sbf -filetype=asm -o - %s | FileCheck -check-prefixes=CHECK %s + +; Source code: +; const void *a; +; Compilation flag: +; clang -target bpf -O2 -g -S -emit-llvm t.c + +@p = common dso_local local_unnamed_addr global i8* null, align 8, !dbg !0 + +!llvm.dbg.cu = !{!2} +!llvm.module.flags = !{!8, !9, !10} +!llvm.ident = !{!11} + +; CHECK: .section .BTF,"",@progbits +; CHECK-NEXT: .short 60319 # 0xeb9f +; CHECK-NEXT: .byte 1 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .long 24 +; CHECK-NEXT: .long 0 +; CHECK-NEXT: .long 24 +; CHECK-NEXT: .long 24 +; CHECK-NEXT: .long 1 +; CHECK-NEXT: .long 0 # BTF_KIND_PTR(id = 1) +; CHECK-NEXT: .long 33554432 # 0x2000000 +; CHECK-NEXT: .long 2 +; CHECK-NEXT: .long 0 # BTF_KIND_CONST(id = 2) +; CHECK-NEXT: .long 167772160 # 0xa000000 +; CHECK-NEXT: .long 0 +; CHECK-NEXT: .byte 0 # string offset=0 + +!0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression()) +!1 = distinct !DIGlobalVariable(name: "p", scope: !2, file: !3, line: 1, type: !6, isLocal: false, isDefinition: true) +!2 = distinct !DICompileUnit(language: DW_LANG_C99, file: !3, producer: "clang version 8.0.0 (trunk 344789) (llvm/trunk 344782)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !4, globals: !5, nameTableKind: None) +!3 = !DIFile(filename: "t.c", directory: "/home/yhs/tmp") +!4 = !{} +!5 = !{!0} +!6 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !7, size: 64) +!7 = !DIDerivedType(tag: DW_TAG_const_type, baseType: null) +!8 = !{i32 2, !"Dwarf Version", i32 4} +!9 = !{i32 2, !"Debug Info Version", i32 3} +!10 = !{i32 1, !"wchar_size", i32 4} +!11 = !{!"clang version 8.0.0 (trunk 344789) (llvm/trunk 344782)"} diff --git a/llvm/test/CodeGen/SBF/BTF/ptr-func-1.ll b/llvm/test/CodeGen/SBF/BTF/ptr-func-1.ll new file mode 100644 index 0000000000000..ecf63ed389060 --- /dev/null +++ b/llvm/test/CodeGen/SBF/BTF/ptr-func-1.ll @@ -0,0 +1,43 @@ +; RUN: llc -sbf-enable-btf-emission -march=sbf -filetype=asm -o - %s | FileCheck -check-prefixes=CHECK %s + +; Source code: +; void (*a)(void); +; Compilation flag: +; clang -target bpf -O2 -g -S -emit-llvm t.c + +@a = common dso_local local_unnamed_addr global void ()* null, align 8, !dbg !0 + +!llvm.dbg.cu = !{!2} +!llvm.module.flags = !{!9, !10, !11} +!llvm.ident = !{!12} + +; CHECK: .section .BTF,"",@progbits +; CHECK-NEXT: .short 60319 # 0xeb9f +; CHECK-NEXT: .byte 1 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .long 24 +; CHECK-NEXT: .long 0 +; CHECK-NEXT: .long 24 +; CHECK-NEXT: .long 24 +; CHECK-NEXT: .long 1 +; CHECK-NEXT: .long 0 # BTF_KIND_PTR(id = 1) +; CHECK-NEXT: .long 33554432 # 0x2000000 +; CHECK-NEXT: .long 2 +; CHECK-NEXT: .long 0 # BTF_KIND_FUNC_PROTO(id = 2) +; CHECK-NEXT: .long 218103808 # 0xd000000 +; CHECK-NEXT: .long 0 +; CHECK-NEXT: .byte 0 # string offset=0 + +!0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression()) +!1 = distinct !DIGlobalVariable(name: "a", scope: !2, file: !3, line: 1, type: !6, isLocal: false, isDefinition: true) +!2 = distinct !DICompileUnit(language: DW_LANG_C99, file: !3, producer: "clang version 8.0.0 (trunk 344789) (llvm/trunk 344782)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !4, globals: !5, nameTableKind: None) +!3 = !DIFile(filename: "t.c", directory: "/home/yhs/tmp") +!4 = !{} +!5 = !{!0} +!6 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !7, size: 64) +!7 = !DISubroutineType(types: !8) +!8 = !{null} +!9 = !{i32 2, !"Dwarf Version", i32 4} +!10 = !{i32 2, !"Debug Info Version", i32 3} +!11 = !{i32 1, !"wchar_size", i32 4} +!12 = !{!"clang version 8.0.0 (trunk 344789) (llvm/trunk 344782)"} diff --git a/llvm/test/CodeGen/SBF/BTF/ptr-func-2.ll b/llvm/test/CodeGen/SBF/BTF/ptr-func-2.ll new file mode 100644 index 0000000000000..9cbb49dce2dc7 --- /dev/null +++ b/llvm/test/CodeGen/SBF/BTF/ptr-func-2.ll @@ -0,0 +1,61 @@ +; RUN: llc -sbf-enable-btf-emission -march=sbf -filetype=asm -o - %s | FileCheck -check-prefixes=CHECK %s + +; Source code: +; int (*a)(int a, char b); +; Compilation flag: +; clang -target bpf -O2 -g -S -emit-llvm t.c + +@a = common dso_local local_unnamed_addr global i32 (i32, i8)* null, align 8, !dbg !0 + +!llvm.dbg.cu = !{!2} +!llvm.module.flags = !{!11, !12, !13} +!llvm.ident = !{!14} + +; CHECK: .section .BTF,"",@progbits +; CHECK-NEXT: .short 60319 # 0xeb9f +; CHECK-NEXT: .byte 1 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .long 24 +; CHECK-NEXT: .long 0 +; CHECK-NEXT: .long 72 +; CHECK-NEXT: .long 72 +; CHECK-NEXT: .long 10 +; CHECK-NEXT: .long 0 # BTF_KIND_PTR(id = 1) +; CHECK-NEXT: .long 33554432 # 0x2000000 +; CHECK-NEXT: .long 2 +; CHECK-NEXT: .long 0 # BTF_KIND_FUNC_PROTO(id = 2) +; CHECK-NEXT: .long 218103810 # 0xd000002 +; CHECK-NEXT: .long 3 +; CHECK-NEXT: .long 0 +; CHECK-NEXT: .long 3 +; CHECK-NEXT: .long 0 +; CHECK-NEXT: .long 4 +; CHECK-NEXT: .long 1 # BTF_KIND_INT(id = 3) +; CHECK-NEXT: .long 16777216 # 0x1000000 +; CHECK-NEXT: .long 4 +; CHECK-NEXT: .long 16777248 # 0x1000020 +; CHECK-NEXT: .long 5 # BTF_KIND_INT(id = 4) +; CHECK-NEXT: .long 16777216 # 0x1000000 +; CHECK-NEXT: .long 1 +; CHECK-NEXT: .long 16777224 # 0x1000008 +; CHECK-NEXT: .byte 0 # string offset=0 +; CHECK-NEXT: .ascii "int" # string offset=1 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii "char" # string offset=5 +; CHECK-NEXT: .byte 0 + +!0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression()) +!1 = distinct !DIGlobalVariable(name: "a", scope: !2, file: !3, line: 1, type: !6, isLocal: false, isDefinition: true) +!2 = distinct !DICompileUnit(language: DW_LANG_C99, file: !3, producer: "clang version 8.0.0 (trunk 344789) (llvm/trunk 344782)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !4, globals: !5, nameTableKind: None) +!3 = !DIFile(filename: "t.c", directory: "/home/yhs/tmp") +!4 = !{} +!5 = !{!0} +!6 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !7, size: 64) +!7 = !DISubroutineType(types: !8) +!8 = !{!9, !9, !10} +!9 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +!10 = !DIBasicType(name: "char", size: 8, encoding: DW_ATE_signed_char) +!11 = !{i32 2, !"Dwarf Version", i32 4} +!12 = !{i32 2, !"Debug Info Version", i32 3} +!13 = !{i32 1, !"wchar_size", i32 4} +!14 = !{!"clang version 8.0.0 (trunk 344789) (llvm/trunk 344782)"} diff --git a/llvm/test/CodeGen/SBF/BTF/ptr-func-3.ll b/llvm/test/CodeGen/SBF/BTF/ptr-func-3.ll new file mode 100644 index 0000000000000..37d78353ee979 --- /dev/null +++ b/llvm/test/CodeGen/SBF/BTF/ptr-func-3.ll @@ -0,0 +1,61 @@ +; RUN: llc -sbf-enable-btf-emission -march=sbf -filetype=asm -o - %s | FileCheck -check-prefixes=CHECK %s + +; Source code: +; typedef int __int; +; __int (*a)(__int a, __int b); +; Compilation flag: +; clang -target bpf -O2 -g -S -emit-llvm t.c + +@a = common dso_local local_unnamed_addr global i32 (i32, i32)* null, align 8, !dbg !0 + +!llvm.dbg.cu = !{!2} +!llvm.module.flags = !{!11, !12, !13} +!llvm.ident = !{!14} + +; CHECK: .section .BTF,"",@progbits +; CHECK-NEXT: .short 60319 # 0xeb9f +; CHECK-NEXT: .byte 1 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .long 24 +; CHECK-NEXT: .long 0 +; CHECK-NEXT: .long 68 +; CHECK-NEXT: .long 68 +; CHECK-NEXT: .long 11 +; CHECK-NEXT: .long 0 # BTF_KIND_PTR(id = 1) +; CHECK-NEXT: .long 33554432 # 0x2000000 +; CHECK-NEXT: .long 2 +; CHECK-NEXT: .long 0 # BTF_KIND_FUNC_PROTO(id = 2) +; CHECK-NEXT: .long 218103810 # 0xd000002 +; CHECK-NEXT: .long 3 +; CHECK-NEXT: .long 0 +; CHECK-NEXT: .long 3 +; CHECK-NEXT: .long 0 +; CHECK-NEXT: .long 3 +; CHECK-NEXT: .long 1 # BTF_KIND_TYPEDEF(id = 3) +; CHECK-NEXT: .long 134217728 # 0x8000000 +; CHECK-NEXT: .long 4 +; CHECK-NEXT: .long 7 # BTF_KIND_INT(id = 4) +; CHECK-NEXT: .long 16777216 # 0x1000000 +; CHECK-NEXT: .long 4 +; CHECK-NEXT: .long 16777248 # 0x1000020 +; CHECK-NEXT: .byte 0 # string offset=0 +; CHECK-NEXT: .ascii "__int" # string offset=1 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii "int" # string offset=7 +; CHECK-NEXT: .byte 0 + +!0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression()) +!1 = distinct !DIGlobalVariable(name: "a", scope: !2, file: !3, line: 2, type: !6, isLocal: false, isDefinition: true) +!2 = distinct !DICompileUnit(language: DW_LANG_C99, file: !3, producer: "clang version 8.0.0 (trunk 344789) (llvm/trunk 344782)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !4, globals: !5, nameTableKind: None) +!3 = !DIFile(filename: "t.c", directory: "/home/yhs/tmp") +!4 = !{} +!5 = !{!0} +!6 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !7, size: 64) +!7 = !DISubroutineType(types: !8) +!8 = !{!9, !9, !9} +!9 = !DIDerivedType(tag: DW_TAG_typedef, name: "__int", file: !3, line: 1, baseType: !10) +!10 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +!11 = !{i32 2, !"Dwarf Version", i32 4} +!12 = !{i32 2, !"Debug Info Version", i32 3} +!13 = !{i32 1, !"wchar_size", i32 4} +!14 = !{!"clang version 8.0.0 (trunk 344789) (llvm/trunk 344782)"} diff --git a/llvm/test/CodeGen/SBF/BTF/ptr-int.ll b/llvm/test/CodeGen/SBF/BTF/ptr-int.ll new file mode 100644 index 0000000000000..c2cc70451161a --- /dev/null +++ b/llvm/test/CodeGen/SBF/BTF/ptr-int.ll @@ -0,0 +1,45 @@ +; RUN: llc -sbf-enable-btf-emission -march=sbf -filetype=asm -o - %s | FileCheck -check-prefixes=CHECK %s + +; Source code: +; int *a; +; Compilation flag: +; clang -target bpf -O2 -g -S -emit-llvm t.c + +@a = common dso_local local_unnamed_addr global i32* null, align 8, !dbg !0 + +!llvm.dbg.cu = !{!2} +!llvm.module.flags = !{!8, !9, !10} +!llvm.ident = !{!11} + +; CHECK: .section .BTF,"",@progbits +; CHECK-NEXT: .short 60319 # 0xeb9f +; CHECK-NEXT: .byte 1 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .long 24 +; CHECK-NEXT: .long 0 +; CHECK-NEXT: .long 28 +; CHECK-NEXT: .long 28 +; CHECK-NEXT: .long 5 +; CHECK-NEXT: .long 0 # BTF_KIND_PTR(id = 1) +; CHECK-NEXT: .long 33554432 # 0x2000000 +; CHECK-NEXT: .long 2 +; CHECK-NEXT: .long 1 # BTF_KIND_INT(id = 2) +; CHECK-NEXT: .long 16777216 # 0x1000000 +; CHECK-NEXT: .long 4 +; CHECK-NEXT: .long 16777248 # 0x1000020 +; CHECK-NEXT: .byte 0 # string offset=0 +; CHECK-NEXT: .ascii "int" # string offset=1 +; CHECK-NEXT: .byte 0 + +!0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression()) +!1 = distinct !DIGlobalVariable(name: "a", scope: !2, file: !3, line: 1, type: !6, isLocal: false, isDefinition: true) +!2 = distinct !DICompileUnit(language: DW_LANG_C99, file: !3, producer: "clang version 8.0.0 (trunk 344789) (llvm/trunk 344782)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !4, globals: !5, nameTableKind: None) +!3 = !DIFile(filename: "t.c", directory: "/home/yhs/tmp") +!4 = !{} +!5 = !{!0} +!6 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !7, size: 64) +!7 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +!8 = !{i32 2, !"Dwarf Version", i32 4} +!9 = !{i32 2, !"Debug Info Version", i32 3} +!10 = !{i32 1, !"wchar_size", i32 4} +!11 = !{!"clang version 8.0.0 (trunk 344789) (llvm/trunk 344782)"} diff --git a/llvm/test/CodeGen/SBF/BTF/ptr-prune-type.ll b/llvm/test/CodeGen/SBF/BTF/ptr-prune-type.ll new file mode 100644 index 0000000000000..aad49284a76ae --- /dev/null +++ b/llvm/test/CodeGen/SBF/BTF/ptr-prune-type.ll @@ -0,0 +1,83 @@ +; RUN: llc -sbf-enable-btf-emission -march=sbf -filetype=asm -o - %s | FileCheck -check-prefixes=CHECK %s + +; Source code: +; struct t { +; int a; +; }; +; struct t2 { +; struct t *f1; +; }; +; struct t2 __attribute__((section("prune_types"))) g; +; Compilation flag: +; clang -target bpf -O2 -g -S -emit-llvm t.c + +%struct.t2 = type { %struct.t* } +%struct.t = type { i32 } + +@g = dso_local local_unnamed_addr global %struct.t2 zeroinitializer, section "prune_types", align 8, !dbg !0 + +; CHECK: .section .BTF,"",@progbits +; CHECK-NEXT: .short 60319 # 0xeb9f +; CHECK-NEXT: .byte 1 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .long 24 +; CHECK-NEXT: .long 0 +; CHECK-NEXT: .long 88 +; CHECK-NEXT: .long 88 +; CHECK-NEXT: .long 23 +; CHECK-NEXT: .long 1 # BTF_KIND_STRUCT(id = 1) +; CHECK-NEXT: .long 67108865 # 0x4000001 +; CHECK-NEXT: .long 8 +; CHECK-NEXT: .long 4 +; CHECK-NEXT: .long 2 +; CHECK-NEXT: .long 0 # 0x0 +; CHECK-NEXT: .long 0 # BTF_KIND_PTR(id = 2) +; CHECK-NEXT: .long 33554432 # 0x2000000 +; CHECK-NEXT: .long 5 +; CHECK-NEXT: .long 7 # BTF_KIND_VAR(id = 3) +; CHECK-NEXT: .long 234881024 # 0xe000000 +; CHECK-NEXT: .long 1 +; CHECK-NEXT: .long 1 +; CHECK-NEXT: .long 9 # BTF_KIND_DATASEC(id = 4) +; CHECK-NEXT: .long 251658241 # 0xf000001 +; CHECK-NEXT: .long 0 +; CHECK-NEXT: .long 3 +; CHECK-NEXT: .long g +; CHECK-NEXT: .long 8 +; CHECK-NEXT: .long 21 # BTF_KIND_FWD(id = 5) +; CHECK-NEXT: .long 117440512 # 0x7000000 +; CHECK-NEXT: .long 0 +; CHECK-NEXT: .byte 0 # string offset=0 +; CHECK-NEXT: .ascii "t2" # string offset=1 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii "f1" # string offset=4 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .byte 103 # string offset=7 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii "prune_types" # string offset=9 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .byte 116 # string offset=21 +; CHECK-NEXT: .byte 0 + +!llvm.dbg.cu = !{!2} +!llvm.module.flags = !{!14, !15, !16} +!llvm.ident = !{!17} + +!0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression()) +!1 = distinct !DIGlobalVariable(name: "g", scope: !2, file: !3, line: 7, type: !6, isLocal: false, isDefinition: true) +!2 = distinct !DICompileUnit(language: DW_LANG_C99, file: !3, producer: "clang version 9.0.0 (trunk 364157) (llvm/trunk 364156)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !4, globals: !5, nameTableKind: None) +!3 = !DIFile(filename: "t.c", directory: "/tmp/home/yhs/work/tests/llvm") +!4 = !{} +!5 = !{!0} +!6 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "t2", file: !3, line: 4, size: 64, elements: !7) +!7 = !{!8} +!8 = !DIDerivedType(tag: DW_TAG_member, name: "f1", scope: !6, file: !3, line: 5, baseType: !9, size: 64) +!9 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !10, size: 64) +!10 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "t", file: !3, line: 1, size: 32, elements: !11) +!11 = !{!12} +!12 = !DIDerivedType(tag: DW_TAG_member, name: "a", scope: !10, file: !3, line: 2, baseType: !13, size: 32) +!13 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +!14 = !{i32 2, !"Dwarf Version", i32 4} +!15 = !{i32 2, !"Debug Info Version", i32 3} +!16 = !{i32 1, !"wchar_size", i32 4} +!17 = !{!"clang version 9.0.0 (trunk 364157) (llvm/trunk 364156)"} diff --git a/llvm/test/CodeGen/SBF/BTF/ptr-void.ll b/llvm/test/CodeGen/SBF/BTF/ptr-void.ll new file mode 100644 index 0000000000000..557b44cc9c6cb --- /dev/null +++ b/llvm/test/CodeGen/SBF/BTF/ptr-void.ll @@ -0,0 +1,38 @@ +; RUN: llc -sbf-enable-btf-emission -march=sbf -filetype=asm -o - %s | FileCheck -check-prefixes=CHECK %s + +; Source code: +; void *a; +; Compilation flag: +; clang -target bpf -O2 -g -S -emit-llvm t.c + +@a = common dso_local local_unnamed_addr global i8* null, align 8, !dbg !0 + +!llvm.dbg.cu = !{!2} +!llvm.module.flags = !{!7, !8, !9} +!llvm.ident = !{!10} + +; CHECK: .section .BTF,"",@progbits +; CHECK-NEXT: .short 60319 # 0xeb9f +; CHECK-NEXT: .byte 1 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .long 24 +; CHECK-NEXT: .long 0 +; CHECK-NEXT: .long 12 +; CHECK-NEXT: .long 12 +; CHECK-NEXT: .long 1 +; CHECK-NEXT: .long 0 # BTF_KIND_PTR(id = 1) +; CHECK-NEXT: .long 33554432 # 0x2000000 +; CHECK-NEXT: .long 0 +; CHECK-NEXT: .byte 0 # string offset=0 + +!0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression()) +!1 = distinct !DIGlobalVariable(name: "a", scope: !2, file: !3, line: 1, type: !6, isLocal: false, isDefinition: true) +!2 = distinct !DICompileUnit(language: DW_LANG_C99, file: !3, producer: "clang version 8.0.0 (trunk 345296) (llvm/trunk 345297)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !4, globals: !5, nameTableKind: None) +!3 = !DIFile(filename: "t.c", directory: "/home/yhs/tmp") +!4 = !{} +!5 = !{!0} +!6 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: null, size: 64) +!7 = !{i32 2, !"Dwarf Version", i32 4} +!8 = !{i32 2, !"Debug Info Version", i32 3} +!9 = !{i32 1, !"wchar_size", i32 4} +!10 = !{!"clang version 8.0.0 (trunk 345296) (llvm/trunk 345297)"} diff --git a/llvm/test/CodeGen/SBF/BTF/ptr-volatile-const-void.ll b/llvm/test/CodeGen/SBF/BTF/ptr-volatile-const-void.ll new file mode 100644 index 0000000000000..881c10669a1e4 --- /dev/null +++ b/llvm/test/CodeGen/SBF/BTF/ptr-volatile-const-void.ll @@ -0,0 +1,46 @@ +; RUN: llc -sbf-enable-btf-emission -march=sbf -filetype=asm -o - %s | FileCheck -check-prefixes=CHECK %s + +; Source code: +; volatile const void *p; +; Compilation flag: +; clang -target bpf -O2 -g -S -emit-llvm t.c + +@p = common dso_local local_unnamed_addr global i8* null, align 8, !dbg !0 + +!llvm.dbg.cu = !{!2} +!llvm.module.flags = !{!9, !10, !11} +!llvm.ident = !{!12} + +; CHECK: .section .BTF,"",@progbits +; CHECK-NEXT: .short 60319 # 0xeb9f +; CHECK-NEXT: .byte 1 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .long 24 +; CHECK-NEXT: .long 0 +; CHECK-NEXT: .long 36 +; CHECK-NEXT: .long 36 +; CHECK-NEXT: .long 1 +; CHECK-NEXT: .long 0 # BTF_KIND_PTR(id = 1) +; CHECK-NEXT: .long 33554432 # 0x2000000 +; CHECK-NEXT: .long 2 +; CHECK-NEXT: .long 0 # BTF_KIND_CONST(id = 2) +; CHECK-NEXT: .long 167772160 # 0xa000000 +; CHECK-NEXT: .long 3 +; CHECK-NEXT: .long 0 # BTF_KIND_VOLATILE(id = 3) +; CHECK-NEXT: .long 150994944 # 0x9000000 +; CHECK-NEXT: .long 0 +; CHECK-NEXT: .byte 0 # string offset=0 + +!0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression()) +!1 = distinct !DIGlobalVariable(name: "p", scope: !2, file: !3, line: 1, type: !6, isLocal: false, isDefinition: true) +!2 = distinct !DICompileUnit(language: DW_LANG_C99, file: !3, producer: "clang version 8.0.0 (trunk 344789) (llvm/trunk 344782)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !4, globals: !5, nameTableKind: None) +!3 = !DIFile(filename: "t.c", directory: "/home/yhs/tmp") +!4 = !{} +!5 = !{!0} +!6 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !7, size: 64) +!7 = !DIDerivedType(tag: DW_TAG_const_type, baseType: !8) +!8 = !DIDerivedType(tag: DW_TAG_volatile_type, baseType: null) +!9 = !{i32 2, !"Dwarf Version", i32 4} +!10 = !{i32 2, !"Debug Info Version", i32 3} +!11 = !{i32 1, !"wchar_size", i32 4} +!12 = !{!"clang version 8.0.0 (trunk 344789) (llvm/trunk 344782)"} diff --git a/llvm/test/CodeGen/SBF/BTF/ptr-volatile-void.ll b/llvm/test/CodeGen/SBF/BTF/ptr-volatile-void.ll new file mode 100644 index 0000000000000..21cf61309bb76 --- /dev/null +++ b/llvm/test/CodeGen/SBF/BTF/ptr-volatile-void.ll @@ -0,0 +1,42 @@ +; RUN: llc -sbf-enable-btf-emission -march=sbf -filetype=asm -o - %s | FileCheck -check-prefixes=CHECK %s + +; Source code: +; volatile void *a; +; Compilation flag: +; clang -target bpf -O2 -g -S -emit-llvm t.c + +@p = common dso_local local_unnamed_addr global i8* null, align 8, !dbg !0 + +!llvm.dbg.cu = !{!2} +!llvm.module.flags = !{!8, !9, !10} +!llvm.ident = !{!11} + +; CHECK: .section .BTF,"",@progbits +; CHECK-NEXT: .short 60319 # 0xeb9f +; CHECK-NEXT: .byte 1 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .long 24 +; CHECK-NEXT: .long 0 +; CHECK-NEXT: .long 24 +; CHECK-NEXT: .long 24 +; CHECK-NEXT: .long 1 +; CHECK-NEXT: .long 0 # BTF_KIND_PTR(id = 1) +; CHECK-NEXT: .long 33554432 # 0x2000000 +; CHECK-NEXT: .long 2 +; CHECK-NEXT: .long 0 # BTF_KIND_VOLATILE(id = 2) +; CHECK-NEXT: .long 150994944 # 0x9000000 +; CHECK-NEXT: .long 0 +; CHECK-NEXT: .byte 0 # string offset=0 + +!0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression()) +!1 = distinct !DIGlobalVariable(name: "p", scope: !2, file: !3, line: 1, type: !6, isLocal: false, isDefinition: true) +!2 = distinct !DICompileUnit(language: DW_LANG_C99, file: !3, producer: "clang version 8.0.0 (trunk 344789) (llvm/trunk 344782)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !4, globals: !5, nameTableKind: None) +!3 = !DIFile(filename: "t.c", directory: "/home/yhs/tmp") +!4 = !{} +!5 = !{!0} +!6 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !7, size: 64) +!7 = !DIDerivedType(tag: DW_TAG_volatile_type, baseType: null) +!8 = !{i32 2, !"Dwarf Version", i32 4} +!9 = !{i32 2, !"Debug Info Version", i32 3} +!10 = !{i32 1, !"wchar_size", i32 4} +!11 = !{!"clang version 8.0.0 (trunk 344789) (llvm/trunk 344782)"} diff --git a/llvm/test/CodeGen/SBF/BTF/restrict-ptr.ll b/llvm/test/CodeGen/SBF/BTF/restrict-ptr.ll new file mode 100644 index 0000000000000..c5350f302ca2a --- /dev/null +++ b/llvm/test/CodeGen/SBF/BTF/restrict-ptr.ll @@ -0,0 +1,49 @@ +; RUN: llc -sbf-enable-btf-emission -march=sbf -filetype=asm -o - %s | FileCheck -check-prefixes=CHECK %s + +; Source code: +; int * restrict p; +; Compilation flag: +; clang -target bpf -O2 -g -S -emit-llvm t.c + +@p = common dso_local local_unnamed_addr global i32* null, align 8, !dbg !0 + +!llvm.dbg.cu = !{!2} +!llvm.module.flags = !{!9, !10, !11} +!llvm.ident = !{!12} + +; CHECK: .section .BTF,"",@progbits +; CHECK-NEXT: .short 60319 # 0xeb9f +; CHECK-NEXT: .byte 1 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .long 24 +; CHECK-NEXT: .long 0 +; CHECK-NEXT: .long 40 +; CHECK-NEXT: .long 40 +; CHECK-NEXT: .long 5 +; CHECK-NEXT: .long 0 # BTF_KIND_RESTRICT(id = 1) +; CHECK-NEXT: .long 184549376 # 0xb000000 +; CHECK-NEXT: .long 2 +; CHECK-NEXT: .long 0 # BTF_KIND_PTR(id = 2) +; CHECK-NEXT: .long 33554432 # 0x2000000 +; CHECK-NEXT: .long 3 +; CHECK-NEXT: .long 1 # BTF_KIND_INT(id = 3) +; CHECK-NEXT: .long 16777216 # 0x1000000 +; CHECK-NEXT: .long 4 +; CHECK-NEXT: .long 16777248 # 0x1000020 +; CHECK-NEXT: .byte 0 # string offset=0 +; CHECK-NEXT: .ascii "int" # string offset=1 +; CHECK-NEXT: .byte 0 + +!0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression()) +!1 = distinct !DIGlobalVariable(name: "p", scope: !2, file: !3, line: 1, type: !6, isLocal: false, isDefinition: true) +!2 = distinct !DICompileUnit(language: DW_LANG_C99, file: !3, producer: "clang version 8.0.0 (trunk 344789) (llvm/trunk 344782)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !4, globals: !5, nameTableKind: None) +!3 = !DIFile(filename: "t.c", directory: "/home/yhs/tmp") +!4 = !{} +!5 = !{!0} +!6 = !DIDerivedType(tag: DW_TAG_restrict_type, baseType: !7) +!7 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !8, size: 64) +!8 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +!9 = !{i32 2, !"Dwarf Version", i32 4} +!10 = !{i32 2, !"Debug Info Version", i32 3} +!11 = !{i32 1, !"wchar_size", i32 4} +!12 = !{!"clang version 8.0.0 (trunk 344789) (llvm/trunk 344782)"} diff --git a/llvm/test/CodeGen/SBF/BTF/short.ll b/llvm/test/CodeGen/SBF/BTF/short.ll new file mode 100644 index 0000000000000..302739ce4c89c --- /dev/null +++ b/llvm/test/CodeGen/SBF/BTF/short.ll @@ -0,0 +1,42 @@ +; RUN: llc -sbf-enable-btf-emission -march=sbf -filetype=asm -o - %s | FileCheck -check-prefixes=CHECK %s + +; Source code: +; short a; +; Compilation flag: +; clang -target bpf -O2 -g -S -emit-llvm t.c + + +@a = common dso_local local_unnamed_addr global i16 0, align 2, !dbg !0 + +!llvm.dbg.cu = !{!2} +!llvm.module.flags = !{!7, !8, !9} +!llvm.ident = !{!10} + +; CHECK: .section .BTF,"",@progbits +; CHECK-NEXT: .short 60319 # 0xeb9f +; CHECK-NEXT: .byte 1 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .long 24 +; CHECK-NEXT: .long 0 +; CHECK-NEXT: .long 16 +; CHECK-NEXT: .long 16 +; CHECK-NEXT: .long 7 +; CHECK-NEXT: .long 1 # BTF_KIND_INT(id = 1) +; CHECK-NEXT: .long 16777216 # 0x1000000 +; CHECK-NEXT: .long 2 +; CHECK-NEXT: .long 16777232 # 0x1000010 +; CHECK-NEXT: .byte 0 # string offset=0 +; CHECK-NEXT: .ascii "short" # string offset=1 +; CHECK-NEXT: .byte 0 + +!0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression()) +!1 = distinct !DIGlobalVariable(name: "a", scope: !2, file: !3, line: 1, type: !6, isLocal: false, isDefinition: true) +!2 = distinct !DICompileUnit(language: DW_LANG_C99, file: !3, producer: "clang version 8.0.0 (trunk 344789) (llvm/trunk 344782)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !4, globals: !5, nameTableKind: None) +!3 = !DIFile(filename: "t.c", directory: "/home/yhs/tmp") +!4 = !{} +!5 = !{!0} +!6 = !DIBasicType(name: "short", size: 16, encoding: DW_ATE_signed) +!7 = !{i32 2, !"Dwarf Version", i32 4} +!8 = !{i32 2, !"Debug Info Version", i32 3} +!9 = !{i32 1, !"wchar_size", i32 4} +!10 = !{!"clang version 8.0.0 (trunk 344789) (llvm/trunk 344782)"} diff --git a/llvm/test/CodeGen/SBF/BTF/static-func.ll b/llvm/test/CodeGen/SBF/BTF/static-func.ll new file mode 100644 index 0000000000000..074b88a807677 --- /dev/null +++ b/llvm/test/CodeGen/SBF/BTF/static-func.ll @@ -0,0 +1,95 @@ +; RUN: llc -sbf-enable-btf-emission -march=sbf -filetype=asm -o - %s | FileCheck -check-prefixes=CHECK %s +; +; Source code: +; extern int foo(void); +; static __attribute__((noinline)) int test1() { return foo(); } +; int test2() { return test1(); } +; Compilation flag: +; clang -target bpf -O2 -g -S -emit-llvm test.c + +; Function Attrs: nounwind +define dso_local i32 @test2() local_unnamed_addr #0 !dbg !12 { +entry: + %call = tail call fastcc i32 @test1(), !dbg !13 + ret i32 %call, !dbg !14 +} +; Function Attrs: noinline nounwind +define internal fastcc i32 @test1() unnamed_addr #1 !dbg !15 { +entry: + %call = tail call i32 @foo() #3, !dbg !16 + ret i32 %call, !dbg !17 +} +declare !dbg !4 dso_local i32 @foo() local_unnamed_addr #2 + +; CHECK: .section .BTF,"",@progbits +; CHECK-NEXT: .short 60319 # 0xeb9f +; CHECK-NEXT: .byte 1 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .long 24 +; CHECK-NEXT: .long 0 +; CHECK-NEXT: .long 88 +; CHECK-NEXT: .long 88 +; CHECK-NEXT: .long 64 +; CHECK-NEXT: .long 0 # BTF_KIND_FUNC_PROTO(id = 1) +; CHECK-NEXT: .long 218103808 # 0xd000000 +; CHECK-NEXT: .long 2 +; CHECK-NEXT: .long 1 # BTF_KIND_INT(id = 2) +; CHECK-NEXT: .long 16777216 # 0x1000000 +; CHECK-NEXT: .long 4 +; CHECK-NEXT: .long 16777248 # 0x1000020 +; CHECK-NEXT: .long 5 # BTF_KIND_FUNC(id = 3) +; CHECK-NEXT: .long 201326593 # 0xc000001 +; CHECK-NEXT: .long 1 +; CHECK-NEXT: .long 0 # BTF_KIND_FUNC_PROTO(id = 4) +; CHECK-NEXT: .long 218103808 # 0xd000000 +; CHECK-NEXT: .long 2 +; CHECK-NEXT: .long 54 # BTF_KIND_FUNC(id = 5) +; CHECK-NEXT: .long 201326592 # 0xc000000 +; CHECK-NEXT: .long 4 +; CHECK-NEXT: .long 0 # BTF_KIND_FUNC_PROTO(id = 6) +; CHECK-NEXT: .long 218103808 # 0xd000000 +; CHECK-NEXT: .long 2 +; CHECK-NEXT: .long 60 # BTF_KIND_FUNC(id = 7) +; CHECK-NEXT: .long 201326594 # 0xc000002 +; CHECK-NEXT: .long 6 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii "int" # string offset=1 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii "test2" # string offset=5 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii ".text" # string offset=11 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii "/tmp/home/yhs/work/tests/bugs/test.c" # string offset=17 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii "test1" # string offset=54 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii "foo" # string offset=60 +; CHECK-NEXT: .byte 0 + +attributes #0 = { nounwind "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" } +attributes #1 = { noinline nounwind "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" } +attributes #2 = { "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" } +attributes #3 = { nounwind } + +!llvm.dbg.cu = !{!0} +!llvm.module.flags = !{!8, !9, !10} +!llvm.ident = !{!11} + +!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 10.0.0 (https://github.com/llvm/llvm-project.git 000f95c4157aee07bd4ffc3f59ffdb6c7ecae4af)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, retainedTypes: !3, splitDebugInlining: false, nameTableKind: None) +!1 = !DIFile(filename: "test.c", directory: "/tmp/home/yhs/work/tests/bugs") +!2 = !{} +!3 = !{!4} +!4 = !DISubprogram(name: "foo", scope: !1, file: !1, line: 1, type: !5, flags: DIFlagPrototyped, spFlags: DISPFlagOptimized, retainedNodes: !2) +!5 = !DISubroutineType(types: !6) +!6 = !{!7} +!7 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +!8 = !{i32 7, !"Dwarf Version", i32 4} +!9 = !{i32 2, !"Debug Info Version", i32 3} +!10 = !{i32 1, !"wchar_size", i32 4} +!11 = !{!"clang version 10.0.0 (https://github.com/llvm/llvm-project.git 000f95c4157aee07bd4ffc3f59ffdb6c7ecae4af)"} +!12 = distinct !DISubprogram(name: "test2", scope: !1, file: !1, line: 3, type: !5, scopeLine: 3, flags: DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !2) +!13 = !DILocation(line: 3, column: 22, scope: !12) +!14 = !DILocation(line: 3, column: 15, scope: !12) +!15 = distinct !DISubprogram(name: "test1", scope: !1, file: !1, line: 2, type: !5, scopeLine: 2, flags: DIFlagAllCallsDescribed, spFlags: DISPFlagLocalToUnit | DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !2) +!16 = !DILocation(line: 2, column: 55, scope: !15) +!17 = !DILocation(line: 2, column: 48, scope: !15) diff --git a/llvm/test/CodeGen/SBF/BTF/static-var-derived-type.ll b/llvm/test/CodeGen/SBF/BTF/static-var-derived-type.ll new file mode 100644 index 0000000000000..0785d72cfcc0f --- /dev/null +++ b/llvm/test/CodeGen/SBF/BTF/static-var-derived-type.ll @@ -0,0 +1,189 @@ +; RUN: llc -sbf-enable-btf-emission -march=sbf -filetype=asm -o - %s | FileCheck -check-prefixes=CHECK %s + +; Source code: +; typedef int * int_ptr; +; static int * volatile v1; +; static const int * volatile v2; +; static volatile int_ptr v3 = 0; +; static volatile const int_ptr v4 = 0; +; long foo() { return (long)(v1 - v2 + v3 - v4); } +; Compilation flag: +; clang -target bpf -O2 -g -S -emit-llvm test.c + +@v1 = internal global i32* null, align 8, !dbg !0 +@v2 = internal global i32* null, align 8, !dbg !8 +@v3 = internal global i32* null, align 8, !dbg !14 +@v4 = internal constant i32* null, align 8, !dbg !19 + +; Function Attrs: norecurse nounwind +define dso_local i64 @foo() local_unnamed_addr #0 !dbg !27 { + %1 = load volatile i32*, i32** @v1, align 8, !dbg !29, !tbaa !30 + %2 = load volatile i32*, i32** @v2, align 8, !dbg !34, !tbaa !30 + %3 = ptrtoint i32* %1 to i64, !dbg !35 + %4 = ptrtoint i32* %2 to i64, !dbg !35 + %5 = sub i64 %3, %4, !dbg !35 + %6 = ashr exact i64 %5, 2, !dbg !35 + %7 = load volatile i32*, i32** @v3, align 8, !dbg !36, !tbaa !30 + %8 = getelementptr inbounds i32, i32* %7, i64 %6, !dbg !37 + %9 = load volatile i32*, i32** @v4, align 8, !dbg !38, !tbaa !30 + %10 = ptrtoint i32* %8 to i64, !dbg !39 + %11 = ptrtoint i32* %9 to i64, !dbg !39 + %12 = sub i64 %10, %11, !dbg !39 + %13 = ashr exact i64 %12, 2, !dbg !39 + ret i64 %13, !dbg !40 +} + +; CHECK: .section .BTF,"",@progbits +; CHECK-NEXT: .short 60319 # 0xeb9f +; CHECK-NEXT: .byte 1 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .long 24 +; CHECK-NEXT: .long 0 +; CHECK-NEXT: .long 288 +; CHECK-NEXT: .long 288 +; CHECK-NEXT: .long 95 +; CHECK-NEXT: .long 0 # BTF_KIND_FUNC_PROTO(id = 1) +; CHECK-NEXT: .long 218103808 # 0xd000000 +; CHECK-NEXT: .long 2 +; CHECK-NEXT: .long 1 # BTF_KIND_INT(id = 2) +; CHECK-NEXT: .long 16777216 # 0x1000000 +; CHECK-NEXT: .long 8 +; CHECK-NEXT: .long 16777280 # 0x1000040 +; CHECK-NEXT: .long 10 # BTF_KIND_FUNC(id = 3) +; CHECK-NEXT: .long 201326593 # 0xc000001 +; CHECK-NEXT: .long 1 +; CHECK-NEXT: .long 0 # BTF_KIND_VOLATILE(id = 4) +; CHECK-NEXT: .long 150994944 # 0x9000000 +; CHECK-NEXT: .long 5 +; CHECK-NEXT: .long 0 # BTF_KIND_PTR(id = 5) +; CHECK-NEXT: .long 33554432 # 0x2000000 +; CHECK-NEXT: .long 6 +; CHECK-NEXT: .long 58 # BTF_KIND_INT(id = 6) +; CHECK-NEXT: .long 16777216 # 0x1000000 +; CHECK-NEXT: .long 4 +; CHECK-NEXT: .long 16777248 # 0x1000020 +; CHECK-NEXT: .long 62 # BTF_KIND_VAR(id = 7) +; CHECK-NEXT: .long 234881024 # 0xe000000 +; CHECK-NEXT: .long 4 +; CHECK-NEXT: .long 0 +; CHECK-NEXT: .long 0 # BTF_KIND_VOLATILE(id = 8) +; CHECK-NEXT: .long 150994944 # 0x9000000 +; CHECK-NEXT: .long 9 +; CHECK-NEXT: .long 0 # BTF_KIND_PTR(id = 9) +; CHECK-NEXT: .long 33554432 # 0x2000000 +; CHECK-NEXT: .long 10 +; CHECK-NEXT: .long 0 # BTF_KIND_CONST(id = 10) +; CHECK-NEXT: .long 167772160 # 0xa000000 +; CHECK-NEXT: .long 6 +; CHECK-NEXT: .long 65 # BTF_KIND_VAR(id = 11) +; CHECK-NEXT: .long 234881024 # 0xe000000 +; CHECK-NEXT: .long 8 +; CHECK-NEXT: .long 0 +; CHECK-NEXT: .long 0 # BTF_KIND_VOLATILE(id = 12) +; CHECK-NEXT: .long 150994944 # 0x9000000 +; CHECK-NEXT: .long 13 +; CHECK-NEXT: .long 68 # BTF_KIND_TYPEDEF(id = 13) +; CHECK-NEXT: .long 134217728 # 0x8000000 +; CHECK-NEXT: .long 5 +; CHECK-NEXT: .long 76 # BTF_KIND_VAR(id = 14) +; CHECK-NEXT: .long 234881024 # 0xe000000 +; CHECK-NEXT: .long 12 +; CHECK-NEXT: .long 0 +; CHECK-NEXT: .long 0 # BTF_KIND_CONST(id = 15) +; CHECK-NEXT: .long 167772160 # 0xa000000 +; CHECK-NEXT: .long 12 +; CHECK-NEXT: .long 79 # BTF_KIND_VAR(id = 16) +; CHECK-NEXT: .long 234881024 # 0xe000000 +; CHECK-NEXT: .long 15 +; CHECK-NEXT: .long 0 +; CHECK-NEXT: .long 82 # BTF_KIND_DATASEC(id = 17) +; CHECK-NEXT: .long 251658243 # 0xf000003 +; CHECK-NEXT: .long 0 +; CHECK-NEXT: .long 7 +; CHECK-NEXT: .long v1 +; CHECK-NEXT: .long 8 +; CHECK-NEXT: .long 11 +; CHECK-NEXT: .long v2 +; CHECK-NEXT: .long 8 +; CHECK-NEXT: .long 14 +; CHECK-NEXT: .long v3 +; CHECK-NEXT: .long 8 +; CHECK-NEXT: .long 87 # BTF_KIND_DATASEC(id = 18) +; CHECK-NEXT: .long 251658241 # 0xf000001 +; CHECK-NEXT: .long 0 +; CHECK-NEXT: .long 16 +; CHECK-NEXT: .long v4 +; CHECK-NEXT: .long 8 +; CHECK-NEXT: .byte 0 # string offset=0 +; CHECK-NEXT: .ascii "long int" # string offset=1 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii "foo" # string offset=10 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii ".text" # string offset=14 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii "/home/yhs/work/tests/llvm/bugs/test.c" # string offset=20 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii "int" # string offset=58 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii "v1" # string offset=62 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii "v2" # string offset=65 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii "int_ptr" # string offset=68 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii "v3" # string offset=76 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii "v4" # string offset=79 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii ".bss" # string offset=82 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii ".rodata" # string offset=87 +; CHECK-NEXT: .byte 0 + +attributes #0 = { norecurse nounwind "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "frame-pointer"="all" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" } + +!llvm.dbg.cu = !{!2} +!llvm.module.flags = !{!23, !24, !25} +!llvm.ident = !{!26} + +!0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression()) +!1 = distinct !DIGlobalVariable(name: "v1", scope: !2, file: !3, line: 2, type: !22, isLocal: true, isDefinition: true) +!2 = distinct !DICompileUnit(language: DW_LANG_C99, file: !3, producer: "clang version 8.0.20181009 ", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !4, retainedTypes: !5, globals: !7, nameTableKind: None) +!3 = !DIFile(filename: "test.c", directory: "/home/yhs/work/tests/llvm/bugs") +!4 = !{} +!5 = !{!6} +!6 = !DIBasicType(name: "long int", size: 64, encoding: DW_ATE_signed) +!7 = !{!0, !8, !14, !19} +!8 = !DIGlobalVariableExpression(var: !9, expr: !DIExpression()) +!9 = distinct !DIGlobalVariable(name: "v2", scope: !2, file: !3, line: 3, type: !10, isLocal: true, isDefinition: true) +!10 = !DIDerivedType(tag: DW_TAG_volatile_type, baseType: !11) +!11 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !12, size: 64) +!12 = !DIDerivedType(tag: DW_TAG_const_type, baseType: !13) +!13 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +!14 = !DIGlobalVariableExpression(var: !15, expr: !DIExpression()) +!15 = distinct !DIGlobalVariable(name: "v3", scope: !2, file: !3, line: 4, type: !16, isLocal: true, isDefinition: true) +!16 = !DIDerivedType(tag: DW_TAG_volatile_type, baseType: !17) +!17 = !DIDerivedType(tag: DW_TAG_typedef, name: "int_ptr", file: !3, line: 1, baseType: !18) +!18 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !13, size: 64) +!19 = !DIGlobalVariableExpression(var: !20, expr: !DIExpression()) +!20 = distinct !DIGlobalVariable(name: "v4", scope: !2, file: !3, line: 5, type: !21, isLocal: true, isDefinition: true) +!21 = !DIDerivedType(tag: DW_TAG_const_type, baseType: !16) +!22 = !DIDerivedType(tag: DW_TAG_volatile_type, baseType: !18) +!23 = !{i32 2, !"Dwarf Version", i32 4} +!24 = !{i32 2, !"Debug Info Version", i32 3} +!25 = !{i32 1, !"wchar_size", i32 4} +!26 = !{!"clang version 8.0.20181009 "} +!27 = distinct !DISubprogram(name: "foo", scope: !3, file: !3, line: 6, type: !28, isLocal: false, isDefinition: true, scopeLine: 6, isOptimized: true, unit: !2, retainedNodes: !4) +!28 = !DISubroutineType(types: !5) +!29 = !DILocation(line: 6, column: 28, scope: !27) +!30 = !{!31, !31, i64 0} +!31 = !{!"any pointer", !32, i64 0} +!32 = !{!"omnipotent char", !33, i64 0} +!33 = !{!"Simple C/C++ TBAA"} +!34 = !DILocation(line: 6, column: 33, scope: !27) +!35 = !DILocation(line: 6, column: 31, scope: !27) +!36 = !DILocation(line: 6, column: 38, scope: !27) +!37 = !DILocation(line: 6, column: 36, scope: !27) +!38 = !DILocation(line: 6, column: 43, scope: !27) +!39 = !DILocation(line: 6, column: 41, scope: !27) +!40 = !DILocation(line: 6, column: 14, scope: !27) diff --git a/llvm/test/CodeGen/SBF/BTF/static-var-inited-sec.ll b/llvm/test/CodeGen/SBF/BTF/static-var-inited-sec.ll new file mode 100644 index 0000000000000..8752af0602039 --- /dev/null +++ b/llvm/test/CodeGen/SBF/BTF/static-var-inited-sec.ll @@ -0,0 +1,129 @@ +; RUN: llc -sbf-enable-btf-emission -march=sbf -filetype=asm -o - %s | FileCheck -check-prefixes=CHECK %s + +; Source code: +; static volatile char a __attribute__((section("maps"))) = 3; +; int foo() { +; static volatile short b __attribute__((section("maps"))) = 4; +; return a + b; +; } +; Compilation flag: +; clang -target bpf -O2 -g -S -emit-llvm test.c + +@foo.b = internal global i16 4, section "maps", align 2, !dbg !0 +@a = internal global i8 3, section "maps", align 1, !dbg !10 + +; Function Attrs: norecurse nounwind +define dso_local i32 @foo() local_unnamed_addr #0 !dbg !2 { + %1 = load volatile i8, i8* @a, align 1, !dbg !20, !tbaa !21 + %2 = sext i8 %1 to i32, !dbg !20 + %3 = load volatile i16, i16* @foo.b, align 2, !dbg !24, !tbaa !25 + %4 = sext i16 %3 to i32, !dbg !24 + %5 = add nsw i32 %4, %2, !dbg !27 + ret i32 %5, !dbg !28 +} + +; CHECK: .section .BTF,"",@progbits +; CHECK-NEXT: .short 60319 # 0xeb9f +; CHECK-NEXT: .byte 1 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .long 24 +; CHECK-NEXT: .long 0 +; CHECK-NEXT: .long 164 +; CHECK-NEXT: .long 164 +; CHECK-NEXT: .long 76 +; CHECK-NEXT: .long 0 # BTF_KIND_FUNC_PROTO(id = 1) +; CHECK-NEXT: .long 218103808 # 0xd000000 +; CHECK-NEXT: .long 2 +; CHECK-NEXT: .long 1 # BTF_KIND_INT(id = 2) +; CHECK-NEXT: .long 16777216 # 0x1000000 +; CHECK-NEXT: .long 4 +; CHECK-NEXT: .long 16777248 # 0x1000020 +; CHECK-NEXT: .long 5 # BTF_KIND_FUNC(id = 3) +; CHECK-NEXT: .long 201326593 # 0xc000001 +; CHECK-NEXT: .long 1 +; CHECK-NEXT: .long 0 # BTF_KIND_VOLATILE(id = 4) +; CHECK-NEXT: .long 150994944 # 0x9000000 +; CHECK-NEXT: .long 5 +; CHECK-NEXT: .long 52 # BTF_KIND_INT(id = 5) +; CHECK-NEXT: .long 16777216 # 0x1000000 +; CHECK-NEXT: .long 2 +; CHECK-NEXT: .long 16777232 # 0x1000010 +; CHECK-NEXT: .long 58 # BTF_KIND_VAR(id = 6) +; CHECK-NEXT: .long 234881024 # 0xe000000 +; CHECK-NEXT: .long 4 +; CHECK-NEXT: .long 0 +; CHECK-NEXT: .long 0 # BTF_KIND_VOLATILE(id = 7) +; CHECK-NEXT: .long 150994944 # 0x9000000 +; CHECK-NEXT: .long 8 +; CHECK-NEXT: .long 64 # BTF_KIND_INT(id = 8) +; CHECK-NEXT: .long 16777216 # 0x1000000 +; CHECK-NEXT: .long 1 +; CHECK-NEXT: .long 16777224 # 0x1000008 +; CHECK-NEXT: .long 69 # BTF_KIND_VAR(id = 9) +; CHECK-NEXT: .long 234881024 # 0xe000000 +; CHECK-NEXT: .long 7 +; CHECK-NEXT: .long 0 +; CHECK-NEXT: .long 71 # BTF_KIND_DATASEC(id = 10) +; CHECK-NEXT: .long 251658242 # 0xf000002 +; CHECK-NEXT: .long 0 +; CHECK-NEXT: .long 6 +; CHECK-NEXT: .long foo.b +; CHECK-NEXT: .long 2 +; CHECK-NEXT: .long 9 +; CHECK-NEXT: .long a +; CHECK-NEXT: .long 1 +; CHECK-NEXT: .byte 0 # string offset=0 +; CHECK-NEXT: .ascii "int" # string offset=1 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii "foo" # string offset=5 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii ".text" # string offset=9 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii "/home/yhs/work/tests/llvm/bug/test.c" # string offset=15 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii "short" # string offset=52 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii "foo.b" # string offset=58 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii "char" # string offset=64 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .byte 97 # string offset=69 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii "maps" # string offset=71 +; CHECK-NEXT: .byte 0 + +attributes #0 = { norecurse nounwind "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "frame-pointer"="all" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" } + +!llvm.dbg.cu = !{!7} +!llvm.module.flags = !{!16, !17, !18} +!llvm.ident = !{!19} + +!0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression()) +!1 = distinct !DIGlobalVariable(name: "b", scope: !2, file: !3, line: 3, type: !14, isLocal: true, isDefinition: true) +!2 = distinct !DISubprogram(name: "foo", scope: !3, file: !3, line: 2, type: !4, isLocal: false, isDefinition: true, scopeLine: 2, isOptimized: true, unit: !7, retainedNodes: !8) +!3 = !DIFile(filename: "test.c", directory: "/home/yhs/work/tests/llvm/bug") +!4 = !DISubroutineType(types: !5) +!5 = !{!6} +!6 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +!7 = distinct !DICompileUnit(language: DW_LANG_C99, file: !3, producer: "clang version 8.0.20181009 ", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !8, globals: !9, nameTableKind: None) +!8 = !{} +!9 = !{!0, !10} +!10 = !DIGlobalVariableExpression(var: !11, expr: !DIExpression()) +!11 = distinct !DIGlobalVariable(name: "a", scope: !7, file: !3, line: 1, type: !12, isLocal: true, isDefinition: true) +!12 = !DIDerivedType(tag: DW_TAG_volatile_type, baseType: !13) +!13 = !DIBasicType(name: "char", size: 8, encoding: DW_ATE_signed_char) +!14 = !DIDerivedType(tag: DW_TAG_volatile_type, baseType: !15) +!15 = !DIBasicType(name: "short", size: 16, encoding: DW_ATE_signed) +!16 = !{i32 2, !"Dwarf Version", i32 4} +!17 = !{i32 2, !"Debug Info Version", i32 3} +!18 = !{i32 1, !"wchar_size", i32 4} +!19 = !{!"clang version 8.0.20181009 "} +!20 = !DILocation(line: 4, column: 10, scope: !2) +!21 = !{!22, !22, i64 0} +!22 = !{!"omnipotent char", !23, i64 0} +!23 = !{!"Simple C/C++ TBAA"} +!24 = !DILocation(line: 4, column: 14, scope: !2) +!25 = !{!26, !26, i64 0} +!26 = !{!"short", !22, i64 0} +!27 = !DILocation(line: 4, column: 12, scope: !2) +!28 = !DILocation(line: 4, column: 3, scope: !2) diff --git a/llvm/test/CodeGen/SBF/BTF/static-var-inited.ll b/llvm/test/CodeGen/SBF/BTF/static-var-inited.ll new file mode 100644 index 0000000000000..48a527d13d5ca --- /dev/null +++ b/llvm/test/CodeGen/SBF/BTF/static-var-inited.ll @@ -0,0 +1,129 @@ +; RUN: llc -sbf-enable-btf-emission -march=sbf -filetype=asm -o - %s | FileCheck -check-prefixes=CHECK %s + +; Source code: +; static volatile char a = 3; +; int foo() { +; static volatile short b = 4; +; return a + b; +; } +; Compilation flag: +; clang -target bpf -O2 -g -S -emit-llvm test.c + +@foo.b = internal global i16 4, align 2, !dbg !0 +@a = internal global i8 3, align 1, !dbg !10 + +; Function Attrs: norecurse nounwind +define dso_local i32 @foo() local_unnamed_addr #0 !dbg !2 { + %1 = load volatile i8, i8* @a, align 1, !dbg !20, !tbaa !21 + %2 = sext i8 %1 to i32, !dbg !20 + %3 = load volatile i16, i16* @foo.b, align 2, !dbg !24, !tbaa !25 + %4 = sext i16 %3 to i32, !dbg !24 + %5 = add nsw i32 %4, %2, !dbg !27 + ret i32 %5, !dbg !28 +} + +; CHECK: .section .BTF,"",@progbits +; CHECK-NEXT: .short 60319 # 0xeb9f +; CHECK-NEXT: .byte 1 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .long 24 +; CHECK-NEXT: .long 0 +; CHECK-NEXT: .long 164 +; CHECK-NEXT: .long 164 +; CHECK-NEXT: .long 77 +; CHECK-NEXT: .long 0 # BTF_KIND_FUNC_PROTO(id = 1) +; CHECK-NEXT: .long 218103808 # 0xd000000 +; CHECK-NEXT: .long 2 +; CHECK-NEXT: .long 1 # BTF_KIND_INT(id = 2) +; CHECK-NEXT: .long 16777216 # 0x1000000 +; CHECK-NEXT: .long 4 +; CHECK-NEXT: .long 16777248 # 0x1000020 +; CHECK-NEXT: .long 5 # BTF_KIND_FUNC(id = 3) +; CHECK-NEXT: .long 201326593 # 0xc000001 +; CHECK-NEXT: .long 1 +; CHECK-NEXT: .long 0 # BTF_KIND_VOLATILE(id = 4) +; CHECK-NEXT: .long 150994944 # 0x9000000 +; CHECK-NEXT: .long 5 +; CHECK-NEXT: .long 52 # BTF_KIND_INT(id = 5) +; CHECK-NEXT: .long 16777216 # 0x1000000 +; CHECK-NEXT: .long 2 +; CHECK-NEXT: .long 16777232 # 0x1000010 +; CHECK-NEXT: .long 58 # BTF_KIND_VAR(id = 6) +; CHECK-NEXT: .long 234881024 # 0xe000000 +; CHECK-NEXT: .long 4 +; CHECK-NEXT: .long 0 +; CHECK-NEXT: .long 0 # BTF_KIND_VOLATILE(id = 7) +; CHECK-NEXT: .long 150994944 # 0x9000000 +; CHECK-NEXT: .long 8 +; CHECK-NEXT: .long 64 # BTF_KIND_INT(id = 8) +; CHECK-NEXT: .long 16777216 # 0x1000000 +; CHECK-NEXT: .long 1 +; CHECK-NEXT: .long 16777224 # 0x1000008 +; CHECK-NEXT: .long 69 # BTF_KIND_VAR(id = 9) +; CHECK-NEXT: .long 234881024 # 0xe000000 +; CHECK-NEXT: .long 7 +; CHECK-NEXT: .long 0 +; CHECK-NEXT: .long 71 # BTF_KIND_DATASEC(id = 10) +; CHECK-NEXT: .long 251658242 # 0xf000002 +; CHECK-NEXT: .long 0 +; CHECK-NEXT: .long 6 +; CHECK-NEXT: .long foo.b +; CHECK-NEXT: .long 2 +; CHECK-NEXT: .long 9 +; CHECK-NEXT: .long a +; CHECK-NEXT: .long 1 +; CHECK-NEXT: .byte 0 # string offset=0 +; CHECK-NEXT: .ascii "int" # string offset=1 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii "foo" # string offset=5 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii ".text" # string offset=9 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii "/home/yhs/work/tests/llvm/bug/test.c" # string offset=15 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii "short" # string offset=52 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii "foo.b" # string offset=58 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii "char" # string offset=64 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .byte 97 # string offset=69 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii ".data" # string offset=71 +; CHECK-NEXT: .byte 0 + +attributes #0 = { norecurse nounwind "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "frame-pointer"="all" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" } + +!llvm.dbg.cu = !{!7} +!llvm.module.flags = !{!16, !17, !18} +!llvm.ident = !{!19} + +!0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression()) +!1 = distinct !DIGlobalVariable(name: "b", scope: !2, file: !3, line: 3, type: !14, isLocal: true, isDefinition: true) +!2 = distinct !DISubprogram(name: "foo", scope: !3, file: !3, line: 2, type: !4, isLocal: false, isDefinition: true, scopeLine: 2, isOptimized: true, unit: !7, retainedNodes: !8) +!3 = !DIFile(filename: "test.c", directory: "/home/yhs/work/tests/llvm/bug") +!4 = !DISubroutineType(types: !5) +!5 = !{!6} +!6 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +!7 = distinct !DICompileUnit(language: DW_LANG_C99, file: !3, producer: "clang version 8.0.20181009 ", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !8, globals: !9, nameTableKind: None) +!8 = !{} +!9 = !{!0, !10} +!10 = !DIGlobalVariableExpression(var: !11, expr: !DIExpression()) +!11 = distinct !DIGlobalVariable(name: "a", scope: !7, file: !3, line: 1, type: !12, isLocal: true, isDefinition: true) +!12 = !DIDerivedType(tag: DW_TAG_volatile_type, baseType: !13) +!13 = !DIBasicType(name: "char", size: 8, encoding: DW_ATE_signed_char) +!14 = !DIDerivedType(tag: DW_TAG_volatile_type, baseType: !15) +!15 = !DIBasicType(name: "short", size: 16, encoding: DW_ATE_signed) +!16 = !{i32 2, !"Dwarf Version", i32 4} +!17 = !{i32 2, !"Debug Info Version", i32 3} +!18 = !{i32 1, !"wchar_size", i32 4} +!19 = !{!"clang version 8.0.20181009 "} +!20 = !DILocation(line: 4, column: 10, scope: !2) +!21 = !{!22, !22, i64 0} +!22 = !{!"omnipotent char", !23, i64 0} +!23 = !{!"Simple C/C++ TBAA"} +!24 = !DILocation(line: 4, column: 14, scope: !2) +!25 = !{!26, !26, i64 0} +!26 = !{!"short", !22, i64 0} +!27 = !DILocation(line: 4, column: 12, scope: !2) +!28 = !DILocation(line: 4, column: 3, scope: !2) diff --git a/llvm/test/CodeGen/SBF/BTF/static-var-readonly-sec.ll b/llvm/test/CodeGen/SBF/BTF/static-var-readonly-sec.ll new file mode 100644 index 0000000000000..bbbb3262988db --- /dev/null +++ b/llvm/test/CodeGen/SBF/BTF/static-var-readonly-sec.ll @@ -0,0 +1,137 @@ +; RUN: llc -sbf-enable-btf-emission -march=sbf -filetype=asm -o - %s | FileCheck -check-prefixes=CHECK %s + +; Source code: +; static volatile const char __attribute__((section("maps"))) a; +; int foo() { +; static volatile const short b __attribute__((section("maps"))) = 3; +; return a + b; +; } +; Compilation flag: +; clang -target bpf -O2 -g -S -emit-llvm test.c + +@foo.b = internal constant i16 3, section "maps", align 2, !dbg !0 +@a = internal constant i8 0, section "maps", align 1, !dbg !10 + +; Function Attrs: norecurse nounwind +define dso_local i32 @foo() local_unnamed_addr #0 !dbg !2 { + %1 = load volatile i8, i8* @a, align 1, !dbg !22, !tbaa !23 + %2 = sext i8 %1 to i32, !dbg !22 + %3 = load volatile i16, i16* @foo.b, align 2, !dbg !26, !tbaa !27 + %4 = sext i16 %3 to i32, !dbg !26 + %5 = add nsw i32 %4, %2, !dbg !29 + ret i32 %5, !dbg !30 +} + +; CHECK: .section .BTF,"",@progbits +; CHECK-NEXT: .short 60319 # 0xeb9f +; CHECK-NEXT: .byte 1 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .long 24 +; CHECK-NEXT: .long 0 +; CHECK-NEXT: .long 188 +; CHECK-NEXT: .long 188 +; CHECK-NEXT: .long 76 +; CHECK-NEXT: .long 0 # BTF_KIND_FUNC_PROTO(id = 1) +; CHECK-NEXT: .long 218103808 # 0xd000000 +; CHECK-NEXT: .long 2 +; CHECK-NEXT: .long 1 # BTF_KIND_INT(id = 2) +; CHECK-NEXT: .long 16777216 # 0x1000000 +; CHECK-NEXT: .long 4 +; CHECK-NEXT: .long 16777248 # 0x1000020 +; CHECK-NEXT: .long 5 # BTF_KIND_FUNC(id = 3) +; CHECK-NEXT: .long 201326593 # 0xc000001 +; CHECK-NEXT: .long 1 +; CHECK-NEXT: .long 0 # BTF_KIND_CONST(id = 4) +; CHECK-NEXT: .long 167772160 # 0xa000000 +; CHECK-NEXT: .long 5 +; CHECK-NEXT: .long 0 # BTF_KIND_VOLATILE(id = 5) +; CHECK-NEXT: .long 150994944 # 0x9000000 +; CHECK-NEXT: .long 6 +; CHECK-NEXT: .long 52 # BTF_KIND_INT(id = 6) +; CHECK-NEXT: .long 16777216 # 0x1000000 +; CHECK-NEXT: .long 2 +; CHECK-NEXT: .long 16777232 # 0x1000010 +; CHECK-NEXT: .long 58 # BTF_KIND_VAR(id = 7) +; CHECK-NEXT: .long 234881024 # 0xe000000 +; CHECK-NEXT: .long 4 +; CHECK-NEXT: .long 0 +; CHECK-NEXT: .long 0 # BTF_KIND_CONST(id = 8) +; CHECK-NEXT: .long 167772160 # 0xa000000 +; CHECK-NEXT: .long 9 +; CHECK-NEXT: .long 0 # BTF_KIND_VOLATILE(id = 9) +; CHECK-NEXT: .long 150994944 # 0x9000000 +; CHECK-NEXT: .long 10 +; CHECK-NEXT: .long 64 # BTF_KIND_INT(id = 10) +; CHECK-NEXT: .long 16777216 # 0x1000000 +; CHECK-NEXT: .long 1 +; CHECK-NEXT: .long 16777224 # 0x1000008 +; CHECK-NEXT: .long 69 # BTF_KIND_VAR(id = 11) +; CHECK-NEXT: .long 234881024 # 0xe000000 +; CHECK-NEXT: .long 8 +; CHECK-NEXT: .long 0 +; CHECK-NEXT: .long 71 # BTF_KIND_DATASEC(id = 12) +; CHECK-NEXT: .long 251658242 # 0xf000002 +; CHECK-NEXT: .long 0 +; CHECK-NEXT: .long 7 +; CHECK-NEXT: .long foo.b +; CHECK-NEXT: .long 2 +; CHECK-NEXT: .long 11 +; CHECK-NEXT: .long a +; CHECK-NEXT: .long 1 +; CHECK-NEXT: .byte 0 # string offset=0 +; CHECK-NEXT: .ascii "int" # string offset=1 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii "foo" # string offset=5 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii ".text" # string offset=9 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii "/home/yhs/work/tests/llvm/bug/test.c" # string offset=15 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii "short" # string offset=52 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii "foo.b" # string offset=58 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii "char" # string offset=64 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .byte 97 # string offset=69 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii "maps" # string offset=71 +; CHECK-NEXT: .byte 0 + +attributes #0 = { norecurse nounwind "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "frame-pointer"="all" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" } + +!llvm.dbg.cu = !{!7} +!llvm.module.flags = !{!18, !19, !20} +!llvm.ident = !{!21} + +!0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression()) +!1 = distinct !DIGlobalVariable(name: "b", scope: !2, file: !3, line: 3, type: !15, isLocal: true, isDefinition: true) +!2 = distinct !DISubprogram(name: "foo", scope: !3, file: !3, line: 2, type: !4, isLocal: false, isDefinition: true, scopeLine: 2, isOptimized: true, unit: !7, retainedNodes: !8) +!3 = !DIFile(filename: "test.c", directory: "/home/yhs/work/tests/llvm/bug") +!4 = !DISubroutineType(types: !5) +!5 = !{!6} +!6 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +!7 = distinct !DICompileUnit(language: DW_LANG_C99, file: !3, producer: "clang version 8.0.20181009 ", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !8, globals: !9, nameTableKind: None) +!8 = !{} +!9 = !{!0, !10} +!10 = !DIGlobalVariableExpression(var: !11, expr: !DIExpression()) +!11 = distinct !DIGlobalVariable(name: "a", scope: !7, file: !3, line: 1, type: !12, isLocal: true, isDefinition: true) +!12 = !DIDerivedType(tag: DW_TAG_const_type, baseType: !13) +!13 = !DIDerivedType(tag: DW_TAG_volatile_type, baseType: !14) +!14 = !DIBasicType(name: "char", size: 8, encoding: DW_ATE_signed_char) +!15 = !DIDerivedType(tag: DW_TAG_const_type, baseType: !16) +!16 = !DIDerivedType(tag: DW_TAG_volatile_type, baseType: !17) +!17 = !DIBasicType(name: "short", size: 16, encoding: DW_ATE_signed) +!18 = !{i32 2, !"Dwarf Version", i32 4} +!19 = !{i32 2, !"Debug Info Version", i32 3} +!20 = !{i32 1, !"wchar_size", i32 4} +!21 = !{!"clang version 8.0.20181009 "} +!22 = !DILocation(line: 4, column: 10, scope: !2) +!23 = !{!24, !24, i64 0} +!24 = !{!"omnipotent char", !25, i64 0} +!25 = !{!"Simple C/C++ TBAA"} +!26 = !DILocation(line: 4, column: 14, scope: !2) +!27 = !{!28, !28, i64 0} +!28 = !{!"short", !24, i64 0} +!29 = !DILocation(line: 4, column: 12, scope: !2) +!30 = !DILocation(line: 4, column: 3, scope: !2) diff --git a/llvm/test/CodeGen/SBF/BTF/static-var-readonly.ll b/llvm/test/CodeGen/SBF/BTF/static-var-readonly.ll new file mode 100644 index 0000000000000..9358f34867772 --- /dev/null +++ b/llvm/test/CodeGen/SBF/BTF/static-var-readonly.ll @@ -0,0 +1,137 @@ +; RUN: llc -sbf-enable-btf-emission -march=sbf -filetype=asm -o - %s | FileCheck -check-prefixes=CHECK %s + +; Source code: +; static volatile const char a; +; int foo() { +; static volatile const short b = 3; +; return a + b; +; } +; Compilation flag: +; clang -target bpf -O2 -g -S -emit-llvm test.c + +@foo.b = internal constant i16 3, align 2, !dbg !0 +@a = internal constant i8 0, align 1, !dbg !10 + +; Function Attrs: norecurse nounwind +define dso_local i32 @foo() local_unnamed_addr #0 !dbg !2 { + %1 = load volatile i8, i8* @a, align 1, !dbg !22, !tbaa !23 + %2 = sext i8 %1 to i32, !dbg !22 + %3 = load volatile i16, i16* @foo.b, align 2, !dbg !26, !tbaa !27 + %4 = sext i16 %3 to i32, !dbg !26 + %5 = add nsw i32 %4, %2, !dbg !29 + ret i32 %5, !dbg !30 +} + +; CHECK: .section .BTF,"",@progbits +; CHECK-NEXT: .short 60319 # 0xeb9f +; CHECK-NEXT: .byte 1 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .long 24 +; CHECK-NEXT: .long 0 +; CHECK-NEXT: .long 188 +; CHECK-NEXT: .long 188 +; CHECK-NEXT: .long 79 +; CHECK-NEXT: .long 0 # BTF_KIND_FUNC_PROTO(id = 1) +; CHECK-NEXT: .long 218103808 # 0xd000000 +; CHECK-NEXT: .long 2 +; CHECK-NEXT: .long 1 # BTF_KIND_INT(id = 2) +; CHECK-NEXT: .long 16777216 # 0x1000000 +; CHECK-NEXT: .long 4 +; CHECK-NEXT: .long 16777248 # 0x1000020 +; CHECK-NEXT: .long 5 # BTF_KIND_FUNC(id = 3) +; CHECK-NEXT: .long 201326593 # 0xc000001 +; CHECK-NEXT: .long 1 +; CHECK-NEXT: .long 0 # BTF_KIND_CONST(id = 4) +; CHECK-NEXT: .long 167772160 # 0xa000000 +; CHECK-NEXT: .long 5 +; CHECK-NEXT: .long 0 # BTF_KIND_VOLATILE(id = 5) +; CHECK-NEXT: .long 150994944 # 0x9000000 +; CHECK-NEXT: .long 6 +; CHECK-NEXT: .long 52 # BTF_KIND_INT(id = 6) +; CHECK-NEXT: .long 16777216 # 0x1000000 +; CHECK-NEXT: .long 2 +; CHECK-NEXT: .long 16777232 # 0x1000010 +; CHECK-NEXT: .long 58 # BTF_KIND_VAR(id = 7) +; CHECK-NEXT: .long 234881024 # 0xe000000 +; CHECK-NEXT: .long 4 +; CHECK-NEXT: .long 0 +; CHECK-NEXT: .long 0 # BTF_KIND_CONST(id = 8) +; CHECK-NEXT: .long 167772160 # 0xa000000 +; CHECK-NEXT: .long 9 +; CHECK-NEXT: .long 0 # BTF_KIND_VOLATILE(id = 9) +; CHECK-NEXT: .long 150994944 # 0x9000000 +; CHECK-NEXT: .long 10 +; CHECK-NEXT: .long 64 # BTF_KIND_INT(id = 10) +; CHECK-NEXT: .long 16777216 # 0x1000000 +; CHECK-NEXT: .long 1 +; CHECK-NEXT: .long 16777224 # 0x1000008 +; CHECK-NEXT: .long 69 # BTF_KIND_VAR(id = 11) +; CHECK-NEXT: .long 234881024 # 0xe000000 +; CHECK-NEXT: .long 8 +; CHECK-NEXT: .long 0 +; CHECK-NEXT: .long 71 # BTF_KIND_DATASEC(id = 12) +; CHECK-NEXT: .long 251658242 # 0xf000002 +; CHECK-NEXT: .long 0 +; CHECK-NEXT: .long 7 +; CHECK-NEXT: .long foo.b +; CHECK-NEXT: .long 2 +; CHECK-NEXT: .long 11 +; CHECK-NEXT: .long a +; CHECK-NEXT: .long 1 +; CHECK-NEXT: .byte 0 # string offset=0 +; CHECK-NEXT: .ascii "int" # string offset=1 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii "foo" # string offset=5 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii ".text" # string offset=9 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii "/home/yhs/work/tests/llvm/bug/test.c" # string offset=15 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii "short" # string offset=52 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii "foo.b" # string offset=58 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii "char" # string offset=64 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .byte 97 # string offset=69 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii ".rodata" # string offset=71 +; CHECK-NEXT: .byte 0 + +attributes #0 = { norecurse nounwind "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "frame-pointer"="all" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" } + +!llvm.dbg.cu = !{!7} +!llvm.module.flags = !{!18, !19, !20} +!llvm.ident = !{!21} + +!0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression()) +!1 = distinct !DIGlobalVariable(name: "b", scope: !2, file: !3, line: 3, type: !15, isLocal: true, isDefinition: true) +!2 = distinct !DISubprogram(name: "foo", scope: !3, file: !3, line: 2, type: !4, isLocal: false, isDefinition: true, scopeLine: 2, isOptimized: true, unit: !7, retainedNodes: !8) +!3 = !DIFile(filename: "test.c", directory: "/home/yhs/work/tests/llvm/bug") +!4 = !DISubroutineType(types: !5) +!5 = !{!6} +!6 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +!7 = distinct !DICompileUnit(language: DW_LANG_C99, file: !3, producer: "clang version 8.0.20181009 ", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !8, globals: !9, nameTableKind: None) +!8 = !{} +!9 = !{!0, !10} +!10 = !DIGlobalVariableExpression(var: !11, expr: !DIExpression()) +!11 = distinct !DIGlobalVariable(name: "a", scope: !7, file: !3, line: 1, type: !12, isLocal: true, isDefinition: true) +!12 = !DIDerivedType(tag: DW_TAG_const_type, baseType: !13) +!13 = !DIDerivedType(tag: DW_TAG_volatile_type, baseType: !14) +!14 = !DIBasicType(name: "char", size: 8, encoding: DW_ATE_signed_char) +!15 = !DIDerivedType(tag: DW_TAG_const_type, baseType: !16) +!16 = !DIDerivedType(tag: DW_TAG_volatile_type, baseType: !17) +!17 = !DIBasicType(name: "short", size: 16, encoding: DW_ATE_signed) +!18 = !{i32 2, !"Dwarf Version", i32 4} +!19 = !{i32 2, !"Debug Info Version", i32 3} +!20 = !{i32 1, !"wchar_size", i32 4} +!21 = !{!"clang version 8.0.20181009 "} +!22 = !DILocation(line: 4, column: 10, scope: !2) +!23 = !{!24, !24, i64 0} +!24 = !{!"omnipotent char", !25, i64 0} +!25 = !{!"Simple C/C++ TBAA"} +!26 = !DILocation(line: 4, column: 14, scope: !2) +!27 = !{!28, !28, i64 0} +!28 = !{!"short", !24, i64 0} +!29 = !DILocation(line: 4, column: 12, scope: !2) +!30 = !DILocation(line: 4, column: 3, scope: !2) diff --git a/llvm/test/CodeGen/SBF/BTF/static-var-sec.ll b/llvm/test/CodeGen/SBF/BTF/static-var-sec.ll new file mode 100644 index 0000000000000..81461c8a88b5f --- /dev/null +++ b/llvm/test/CodeGen/SBF/BTF/static-var-sec.ll @@ -0,0 +1,129 @@ +; RUN: llc -sbf-enable-btf-emission -march=sbf -filetype=asm -o - %s | FileCheck -check-prefixes=CHECK %s + +; Source code: +; static volatile char a __attribute__((section("maps"))); +; int foo() { +; static volatile short b __attribute__((section("maps"))); +; return a + b; +; } +; Compilation flag: +; clang -target bpf -O2 -g -S -emit-llvm test.c + +@foo.b = internal global i16 0, section "maps", align 2, !dbg !0 +@a = internal global i8 0, section "maps", align 1, !dbg !10 + +; Function Attrs: norecurse nounwind +define dso_local i32 @foo() local_unnamed_addr #0 !dbg !2 { + %1 = load volatile i8, i8* @a, align 1, !dbg !20, !tbaa !21 + %2 = sext i8 %1 to i32, !dbg !20 + %3 = load volatile i16, i16* @foo.b, align 2, !dbg !24, !tbaa !25 + %4 = sext i16 %3 to i32, !dbg !24 + %5 = add nsw i32 %4, %2, !dbg !27 + ret i32 %5, !dbg !28 +} + +; CHECK: .section .BTF,"",@progbits +; CHECK-NEXT: .short 60319 # 0xeb9f +; CHECK-NEXT: .byte 1 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .long 24 +; CHECK-NEXT: .long 0 +; CHECK-NEXT: .long 164 +; CHECK-NEXT: .long 164 +; CHECK-NEXT: .long 76 +; CHECK-NEXT: .long 0 # BTF_KIND_FUNC_PROTO(id = 1) +; CHECK-NEXT: .long 218103808 # 0xd000000 +; CHECK-NEXT: .long 2 +; CHECK-NEXT: .long 1 # BTF_KIND_INT(id = 2) +; CHECK-NEXT: .long 16777216 # 0x1000000 +; CHECK-NEXT: .long 4 +; CHECK-NEXT: .long 16777248 # 0x1000020 +; CHECK-NEXT: .long 5 # BTF_KIND_FUNC(id = 3) +; CHECK-NEXT: .long 201326593 # 0xc000001 +; CHECK-NEXT: .long 1 +; CHECK-NEXT: .long 0 # BTF_KIND_VOLATILE(id = 4) +; CHECK-NEXT: .long 150994944 # 0x9000000 +; CHECK-NEXT: .long 5 +; CHECK-NEXT: .long 52 # BTF_KIND_INT(id = 5) +; CHECK-NEXT: .long 16777216 # 0x1000000 +; CHECK-NEXT: .long 2 +; CHECK-NEXT: .long 16777232 # 0x1000010 +; CHECK-NEXT: .long 58 # BTF_KIND_VAR(id = 6) +; CHECK-NEXT: .long 234881024 # 0xe000000 +; CHECK-NEXT: .long 4 +; CHECK-NEXT: .long 0 +; CHECK-NEXT: .long 0 # BTF_KIND_VOLATILE(id = 7) +; CHECK-NEXT: .long 150994944 # 0x9000000 +; CHECK-NEXT: .long 8 +; CHECK-NEXT: .long 64 # BTF_KIND_INT(id = 8) +; CHECK-NEXT: .long 16777216 # 0x1000000 +; CHECK-NEXT: .long 1 +; CHECK-NEXT: .long 16777224 # 0x1000008 +; CHECK-NEXT: .long 69 # BTF_KIND_VAR(id = 9) +; CHECK-NEXT: .long 234881024 # 0xe000000 +; CHECK-NEXT: .long 7 +; CHECK-NEXT: .long 0 +; CHECK-NEXT: .long 71 # BTF_KIND_DATASEC(id = 10) +; CHECK-NEXT: .long 251658242 # 0xf000002 +; CHECK-NEXT: .long 0 +; CHECK-NEXT: .long 6 +; CHECK-NEXT: .long foo.b +; CHECK-NEXT: .long 2 +; CHECK-NEXT: .long 9 +; CHECK-NEXT: .long a +; CHECK-NEXT: .long 1 +; CHECK-NEXT: .byte 0 # string offset=0 +; CHECK-NEXT: .ascii "int" # string offset=1 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii "foo" # string offset=5 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii ".text" # string offset=9 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii "/home/yhs/work/tests/llvm/bug/test.c" # string offset=15 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii "short" # string offset=52 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii "foo.b" # string offset=58 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii "char" # string offset=64 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .byte 97 # string offset=69 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii "maps" # string offset=71 +; CHECK-NEXT: .byte 0 + +attributes #0 = { norecurse nounwind "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "frame-pointer"="all" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" } + +!llvm.dbg.cu = !{!7} +!llvm.module.flags = !{!16, !17, !18} +!llvm.ident = !{!19} + +!0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression()) +!1 = distinct !DIGlobalVariable(name: "b", scope: !2, file: !3, line: 3, type: !14, isLocal: true, isDefinition: true) +!2 = distinct !DISubprogram(name: "foo", scope: !3, file: !3, line: 2, type: !4, isLocal: false, isDefinition: true, scopeLine: 2, isOptimized: true, unit: !7, retainedNodes: !8) +!3 = !DIFile(filename: "test.c", directory: "/home/yhs/work/tests/llvm/bug") +!4 = !DISubroutineType(types: !5) +!5 = !{!6} +!6 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +!7 = distinct !DICompileUnit(language: DW_LANG_C99, file: !3, producer: "clang version 8.0.20181009 ", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !8, globals: !9, nameTableKind: None) +!8 = !{} +!9 = !{!0, !10} +!10 = !DIGlobalVariableExpression(var: !11, expr: !DIExpression()) +!11 = distinct !DIGlobalVariable(name: "a", scope: !7, file: !3, line: 1, type: !12, isLocal: true, isDefinition: true) +!12 = !DIDerivedType(tag: DW_TAG_volatile_type, baseType: !13) +!13 = !DIBasicType(name: "char", size: 8, encoding: DW_ATE_signed_char) +!14 = !DIDerivedType(tag: DW_TAG_volatile_type, baseType: !15) +!15 = !DIBasicType(name: "short", size: 16, encoding: DW_ATE_signed) +!16 = !{i32 2, !"Dwarf Version", i32 4} +!17 = !{i32 2, !"Debug Info Version", i32 3} +!18 = !{i32 1, !"wchar_size", i32 4} +!19 = !{!"clang version 8.0.20181009 "} +!20 = !DILocation(line: 4, column: 10, scope: !2) +!21 = !{!22, !22, i64 0} +!22 = !{!"omnipotent char", !23, i64 0} +!23 = !{!"Simple C/C++ TBAA"} +!24 = !DILocation(line: 4, column: 14, scope: !2) +!25 = !{!26, !26, i64 0} +!26 = !{!"short", !22, i64 0} +!27 = !DILocation(line: 4, column: 12, scope: !2) +!28 = !DILocation(line: 4, column: 3, scope: !2) diff --git a/llvm/test/CodeGen/SBF/BTF/static-var-zerolen-array.ll b/llvm/test/CodeGen/SBF/BTF/static-var-zerolen-array.ll new file mode 100644 index 0000000000000..dc90823d0369c --- /dev/null +++ b/llvm/test/CodeGen/SBF/BTF/static-var-zerolen-array.ll @@ -0,0 +1,141 @@ +; RUN: llc -sbf-enable-btf-emission -march=sbf -filetype=asm -o - %s | FileCheck -check-prefixes=CHECK %s + +; Source code: +; struct t { +; int a; +; int b; +; char c[]; +; }; +; static volatile struct t sv = {3, 4, "abcdefghi"}; +; int test() { return sv.a; } +; Compilation flag: +; clang -target bpf -O2 -g -S -emit-llvm test.c + +@sv = internal global { i32, i32, [10 x i8] } { i32 3, i32 4, [10 x i8] c"abcdefghi\00" }, align 4, !dbg !0 + +; Function Attrs: norecurse nounwind +define dso_local i32 @test() local_unnamed_addr #0 !dbg !21 { + %1 = load volatile i32, i32* getelementptr inbounds ({ i32, i32, [10 x i8] }, { i32, i32, [10 x i8] }* @sv, i64 0, i32 0), align 4, !dbg !24, !tbaa !25 + ret i32 %1, !dbg !29 +} + +; CHECK: .section .BTF,"",@progbits +; CHECK-NEXT: .short 60319 # 0xeb9f +; CHECK-NEXT: .byte 1 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .long 24 +; CHECK-NEXT: .long 0 +; CHECK-NEXT: .long 196 +; CHECK-NEXT: .long 196 +; CHECK-NEXT: .long 95 +; CHECK-NEXT: .long 0 # BTF_KIND_FUNC_PROTO(id = 1) +; CHECK-NEXT: .long 218103808 # 0xd000000 +; CHECK-NEXT: .long 2 +; CHECK-NEXT: .long 1 # BTF_KIND_INT(id = 2) +; CHECK-NEXT: .long 16777216 # 0x1000000 +; CHECK-NEXT: .long 4 +; CHECK-NEXT: .long 16777248 # 0x1000020 +; CHECK-NEXT: .long 5 # BTF_KIND_FUNC(id = 3) +; CHECK-NEXT: .long 201326593 # 0xc000001 +; CHECK-NEXT: .long 1 +; CHECK-NEXT: .long 0 # BTF_KIND_VOLATILE(id = 4) +; CHECK-NEXT: .long 150994944 # 0x9000000 +; CHECK-NEXT: .long 5 +; CHECK-NEXT: .long 53 # BTF_KIND_STRUCT(id = 5) +; CHECK-NEXT: .long 67108867 # 0x4000003 +; CHECK-NEXT: .long 8 +; CHECK-NEXT: .long 55 +; CHECK-NEXT: .long 2 +; CHECK-NEXT: .long 0 # 0x0 +; CHECK-NEXT: .long 57 +; CHECK-NEXT: .long 2 +; CHECK-NEXT: .long 32 # 0x20 +; CHECK-NEXT: .long 59 +; CHECK-NEXT: .long 7 +; CHECK-NEXT: .long 64 # 0x40 +; CHECK-NEXT: .long 61 # BTF_KIND_INT(id = 6) +; CHECK-NEXT: .long 16777216 # 0x1000000 +; CHECK-NEXT: .long 1 +; CHECK-NEXT: .long 16777224 # 0x1000008 +; CHECK-NEXT: .long 0 # BTF_KIND_ARRAY(id = 7) +; CHECK-NEXT: .long 50331648 # 0x3000000 +; CHECK-NEXT: .long 0 +; CHECK-NEXT: .long 6 +; CHECK-NEXT: .long 8 +; CHECK-NEXT: .long 0 +; CHECK-NEXT: .long 66 # BTF_KIND_INT(id = 8) +; CHECK-NEXT: .long 16777216 # 0x1000000 +; CHECK-NEXT: .long 4 +; CHECK-NEXT: .long 32 # 0x20 +; CHECK-NEXT: .long 86 # BTF_KIND_VAR(id = 9) +; CHECK-NEXT: .long 234881024 # 0xe000000 +; CHECK-NEXT: .long 4 +; CHECK-NEXT: .long 0 +; CHECK-NEXT: .long 89 # BTF_KIND_DATASEC(id = 10) +; CHECK-NEXT: .long 251658241 # 0xf000001 +; CHECK-NEXT: .long 0 +; CHECK-NEXT: .long 9 +; CHECK-NEXT: .long sv +; CHECK-NEXT: .long 20 +; CHECK-NEXT: .byte 0 # string offset=0 +; CHECK-NEXT: .ascii "int" # string offset=1 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii "test" # string offset=5 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii ".text" # string offset=10 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii "/home/yhs/work/tests/llvm/bug/test.c" # string offset=16 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .byte 116 # string offset=53 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .byte 97 # string offset=55 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .byte 98 # string offset=57 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .byte 99 # string offset=59 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii "char" # string offset=61 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii "__ARRAY_SIZE_TYPE__" # string offset=66 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii "sv" # string offset=86 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii ".data" # string offset=89 +; CHECK-NEXT: .byte 0 + +attributes #0 = { norecurse nounwind "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "frame-pointer"="all" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" } + +!llvm.dbg.cu = !{!2} +!llvm.module.flags = !{!17, !18, !19} +!llvm.ident = !{!20} + +!0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression()) +!1 = distinct !DIGlobalVariable(name: "sv", scope: !2, file: !3, line: 6, type: !6, isLocal: true, isDefinition: true) +!2 = distinct !DICompileUnit(language: DW_LANG_C99, file: !3, producer: "clang version 8.0.20181009 ", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !4, globals: !5, nameTableKind: None) +!3 = !DIFile(filename: "test.c", directory: "/home/yhs/work/tests/llvm/bug") +!4 = !{} +!5 = !{!0} +!6 = !DIDerivedType(tag: DW_TAG_volatile_type, baseType: !7) +!7 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "t", file: !3, line: 1, size: 64, elements: !8) +!8 = !{!9, !11, !12} +!9 = !DIDerivedType(tag: DW_TAG_member, name: "a", scope: !7, file: !3, line: 2, baseType: !10, size: 32) +!10 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +!11 = !DIDerivedType(tag: DW_TAG_member, name: "b", scope: !7, file: !3, line: 3, baseType: !10, size: 32, offset: 32) +!12 = !DIDerivedType(tag: DW_TAG_member, name: "c", scope: !7, file: !3, line: 4, baseType: !13, offset: 64) +!13 = !DICompositeType(tag: DW_TAG_array_type, baseType: !14, elements: !15) +!14 = !DIBasicType(name: "char", size: 8, encoding: DW_ATE_signed_char) +!15 = !{!16} +!16 = !DISubrange(count: -1) +!17 = !{i32 2, !"Dwarf Version", i32 4} +!18 = !{i32 2, !"Debug Info Version", i32 3} +!19 = !{i32 1, !"wchar_size", i32 4} +!20 = !{!"clang version 8.0.20181009 "} +!21 = distinct !DISubprogram(name: "test", scope: !3, file: !3, line: 7, type: !22, isLocal: false, isDefinition: true, scopeLine: 7, isOptimized: true, unit: !2, retainedNodes: !4) +!22 = !DISubroutineType(types: !23) +!23 = !{!10} +!24 = !DILocation(line: 7, column: 24, scope: !21) +!25 = !{!26, !26, i64 0} +!26 = !{!"int", !27, i64 0} +!27 = !{!"omnipotent char", !28, i64 0} +!28 = !{!"Simple C/C++ TBAA"} +!29 = !DILocation(line: 7, column: 14, scope: !21) diff --git a/llvm/test/CodeGen/SBF/BTF/static-var.ll b/llvm/test/CodeGen/SBF/BTF/static-var.ll new file mode 100644 index 0000000000000..2ba7957b7af85 --- /dev/null +++ b/llvm/test/CodeGen/SBF/BTF/static-var.ll @@ -0,0 +1,129 @@ +; RUN: llc -sbf-enable-btf-emission -march=sbf -filetype=asm -o - %s | FileCheck -check-prefixes=CHECK %s + +; Source code: +; static volatile char a; +; int foo() { +; static volatile short b; +; return a + b; +; } +; Compilation flag: +; clang -target bpf -O2 -g -S -emit-llvm test.c + +@foo.b = internal global i16 0, align 2, !dbg !0 +@a = internal global i8 0, align 1, !dbg !10 + +; Function Attrs: norecurse nounwind +define dso_local i32 @foo() local_unnamed_addr #0 !dbg !2 { + %1 = load volatile i8, i8* @a, align 1, !dbg !20, !tbaa !21 + %2 = sext i8 %1 to i32, !dbg !20 + %3 = load volatile i16, i16* @foo.b, align 2, !dbg !24, !tbaa !25 + %4 = sext i16 %3 to i32, !dbg !24 + %5 = add nsw i32 %4, %2, !dbg !27 + ret i32 %5, !dbg !28 +} + +; CHECK: .section .BTF,"",@progbits +; CHECK-NEXT: .short 60319 # 0xeb9f +; CHECK-NEXT: .byte 1 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .long 24 +; CHECK-NEXT: .long 0 +; CHECK-NEXT: .long 164 +; CHECK-NEXT: .long 164 +; CHECK-NEXT: .long 76 +; CHECK-NEXT: .long 0 # BTF_KIND_FUNC_PROTO(id = 1) +; CHECK-NEXT: .long 218103808 # 0xd000000 +; CHECK-NEXT: .long 2 +; CHECK-NEXT: .long 1 # BTF_KIND_INT(id = 2) +; CHECK-NEXT: .long 16777216 # 0x1000000 +; CHECK-NEXT: .long 4 +; CHECK-NEXT: .long 16777248 # 0x1000020 +; CHECK-NEXT: .long 5 # BTF_KIND_FUNC(id = 3) +; CHECK-NEXT: .long 201326593 # 0xc000001 +; CHECK-NEXT: .long 1 +; CHECK-NEXT: .long 0 # BTF_KIND_VOLATILE(id = 4) +; CHECK-NEXT: .long 150994944 # 0x9000000 +; CHECK-NEXT: .long 5 +; CHECK-NEXT: .long 52 # BTF_KIND_INT(id = 5) +; CHECK-NEXT: .long 16777216 # 0x1000000 +; CHECK-NEXT: .long 2 +; CHECK-NEXT: .long 16777232 # 0x1000010 +; CHECK-NEXT: .long 58 # BTF_KIND_VAR(id = 6) +; CHECK-NEXT: .long 234881024 # 0xe000000 +; CHECK-NEXT: .long 4 +; CHECK-NEXT: .long 0 +; CHECK-NEXT: .long 0 # BTF_KIND_VOLATILE(id = 7) +; CHECK-NEXT: .long 150994944 # 0x9000000 +; CHECK-NEXT: .long 8 +; CHECK-NEXT: .long 64 # BTF_KIND_INT(id = 8) +; CHECK-NEXT: .long 16777216 # 0x1000000 +; CHECK-NEXT: .long 1 +; CHECK-NEXT: .long 16777224 # 0x1000008 +; CHECK-NEXT: .long 69 # BTF_KIND_VAR(id = 9) +; CHECK-NEXT: .long 234881024 # 0xe000000 +; CHECK-NEXT: .long 7 +; CHECK-NEXT: .long 0 +; CHECK-NEXT: .long 71 # BTF_KIND_DATASEC(id = 10) +; CHECK-NEXT: .long 251658242 # 0xf000002 +; CHECK-NEXT: .long 0 +; CHECK-NEXT: .long 6 +; CHECK-NEXT: .long foo.b +; CHECK-NEXT: .long 2 +; CHECK-NEXT: .long 9 +; CHECK-NEXT: .long a +; CHECK-NEXT: .long 1 +; CHECK-NEXT: .byte 0 # string offset=0 +; CHECK-NEXT: .ascii "int" # string offset=1 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii "foo" # string offset=5 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii ".text" # string offset=9 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii "/home/yhs/work/tests/llvm/bug/test.c" # string offset=15 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii "short" # string offset=52 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii "foo.b" # string offset=58 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii "char" # string offset=64 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .byte 97 # string offset=69 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii ".bss" # string offset=71 +; CHECK-NEXT: .byte 0 + +attributes #0 = { norecurse nounwind "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "frame-pointer"="all" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" } + +!llvm.dbg.cu = !{!7} +!llvm.module.flags = !{!16, !17, !18} +!llvm.ident = !{!19} + +!0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression()) +!1 = distinct !DIGlobalVariable(name: "b", scope: !2, file: !3, line: 3, type: !14, isLocal: true, isDefinition: true) +!2 = distinct !DISubprogram(name: "foo", scope: !3, file: !3, line: 2, type: !4, isLocal: false, isDefinition: true, scopeLine: 2, isOptimized: true, unit: !7, retainedNodes: !8) +!3 = !DIFile(filename: "test.c", directory: "/home/yhs/work/tests/llvm/bug") +!4 = !DISubroutineType(types: !5) +!5 = !{!6} +!6 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +!7 = distinct !DICompileUnit(language: DW_LANG_C99, file: !3, producer: "clang version 8.0.20181009 ", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !8, globals: !9, nameTableKind: None) +!8 = !{} +!9 = !{!0, !10} +!10 = !DIGlobalVariableExpression(var: !11, expr: !DIExpression()) +!11 = distinct !DIGlobalVariable(name: "a", scope: !7, file: !3, line: 1, type: !12, isLocal: true, isDefinition: true) +!12 = !DIDerivedType(tag: DW_TAG_volatile_type, baseType: !13) +!13 = !DIBasicType(name: "char", size: 8, encoding: DW_ATE_signed_char) +!14 = !DIDerivedType(tag: DW_TAG_volatile_type, baseType: !15) +!15 = !DIBasicType(name: "short", size: 16, encoding: DW_ATE_signed) +!16 = !{i32 2, !"Dwarf Version", i32 4} +!17 = !{i32 2, !"Debug Info Version", i32 3} +!18 = !{i32 1, !"wchar_size", i32 4} +!19 = !{!"clang version 8.0.20181009 "} +!20 = !DILocation(line: 4, column: 10, scope: !2) +!21 = !{!22, !22, i64 0} +!22 = !{!"omnipotent char", !23, i64 0} +!23 = !{!"Simple C/C++ TBAA"} +!24 = !DILocation(line: 4, column: 14, scope: !2) +!25 = !{!26, !26, i64 0} +!26 = !{!"short", !22, i64 0} +!27 = !DILocation(line: 4, column: 12, scope: !2) +!28 = !DILocation(line: 4, column: 3, scope: !2) diff --git a/llvm/test/CodeGen/SBF/BTF/struct-anon-2.ll b/llvm/test/CodeGen/SBF/BTF/struct-anon-2.ll new file mode 100644 index 0000000000000..0ae5c89af2b08 --- /dev/null +++ b/llvm/test/CodeGen/SBF/BTF/struct-anon-2.ll @@ -0,0 +1,105 @@ +; RUN: llc -sbf-enable-btf-emission -march=sbf -filetype=asm -o - %s | FileCheck -check-prefixes=CHECK %s +; +; Source: +; struct s1 { +; struct { int A1; } a1; +; struct { long B1; } *b1; +; }; +; int f1(struct s1 *s1) { return 0; } +; Compilation flag: +; clang -target bpf -O2 -g -S -emit-llvm t.c + +%struct.s1 = type { %struct.anon, %struct.anon.0* } +%struct.anon = type { i32 } +%struct.anon.0 = type { i64 } + +; Function Attrs: norecurse nounwind readnone +define dso_local i32 @f1(%struct.s1* nocapture readnone %s1) local_unnamed_addr #0 !dbg !7 { +entry: + call void @llvm.dbg.value(metadata %struct.s1* %s1, metadata !25, metadata !DIExpression()), !dbg !26 + ret i32 0, !dbg !27 +} + +; CHECK: .long 0 # BTF_KIND_PTR(id = 1) +; CHECK-NEXT: .long 33554432 # 0x2000000 +; CHECK-NEXT: .long 2 +; CHECK-NEXT: .long 1 # BTF_KIND_STRUCT(id = 2) +; CHECK-NEXT: .long 67108866 # 0x4000002 +; CHECK-NEXT: .long 16 +; CHECK-NEXT: .long 4 +; CHECK-NEXT: .long 3 +; CHECK-NEXT: .long 0 # 0x0 +; CHECK-NEXT: .long 7 +; CHECK-NEXT: .long 5 +; CHECK-NEXT: .long 64 # 0x40 +; CHECK-NEXT: .long 0 # BTF_KIND_STRUCT(id = 3) +; CHECK-NEXT: .long 67108865 # 0x4000001 +; CHECK-NEXT: .long 4 +; CHECK-NEXT: .long 10 +; CHECK-NEXT: .long 4 +; CHECK-NEXT: .long 0 # 0x0 +; CHECK-NEXT: .long 13 # BTF_KIND_INT(id = 4) +; CHECK-NEXT: .long 16777216 # 0x1000000 +; CHECK-NEXT: .long 4 +; CHECK-NEXT: .long 16777248 # 0x1000020 +; CHECK-NEXT: .long 0 # BTF_KIND_PTR(id = 5) +; CHECK-NEXT: .long 33554432 # 0x2000000 +; CHECK-NEXT: .long 6 +; CHECK-NEXT: .long 0 # BTF_KIND_STRUCT(id = 6) +; CHECK-NEXT: .long 67108865 # 0x4000001 +; CHECK-NEXT: .long 8 +; CHECK-NEXT: .long 17 +; CHECK-NEXT: .long 7 +; CHECK-NEXT: .long 0 # 0x0 +; CHECK-NEXT: .long 20 # BTF_KIND_INT(id = 7) +; CHECK-NEXT: .long 16777216 # 0x1000000 +; CHECK-NEXT: .long 8 +; CHECK-NEXT: .long 16777280 # 0x1000040 + +; CHECK: .ascii "s1" # string offset=1 +; CHECK: .ascii "a1" # string offset=4 +; CHECK: .ascii "b1" # string offset=7 +; CHECK: .ascii "A1" # string offset=10 +; CHECK: .ascii "int" # string offset=13 +; CHECK: .ascii "B1" # string offset=17 +; CHECK: .ascii "long int" # string offset=20 + + +; Function Attrs: nounwind readnone speculatable willreturn +declare void @llvm.dbg.value(metadata, metadata, metadata) #1 + +attributes #0 = { norecurse nounwind readnone "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" } +attributes #1 = { nounwind readnone speculatable willreturn } + +!llvm.dbg.cu = !{!0} +!llvm.module.flags = !{!3, !4, !5} +!llvm.ident = !{!6} + +!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 11.0.0 (https://github.com/llvm/llvm-project.git ef36f5143d83897cc6f59ff918769d29ad5a0612)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, splitDebugInlining: false, nameTableKind: None) +!1 = !DIFile(filename: "t.c", directory: "/tmp/home/yhs/btf/tmp") +!2 = !{} +!3 = !{i32 7, !"Dwarf Version", i32 4} +!4 = !{i32 2, !"Debug Info Version", i32 3} +!5 = !{i32 1, !"wchar_size", i32 4} +!6 = !{!"clang version 11.0.0 (https://github.com/llvm/llvm-project.git ef36f5143d83897cc6f59ff918769d29ad5a0612)"} +!7 = distinct !DISubprogram(name: "f1", scope: !1, file: !1, line: 5, type: !8, scopeLine: 5, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !24) +!8 = !DISubroutineType(types: !9) +!9 = !{!10, !11} +!10 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +!11 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !12, size: 64) +!12 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "s1", file: !1, line: 1, size: 128, elements: !13) +!13 = !{!14, !18} +!14 = !DIDerivedType(tag: DW_TAG_member, name: "a1", scope: !12, file: !1, line: 2, baseType: !15, size: 32) +!15 = distinct !DICompositeType(tag: DW_TAG_structure_type, scope: !12, file: !1, line: 2, size: 32, elements: !16) +!16 = !{!17} +!17 = !DIDerivedType(tag: DW_TAG_member, name: "A1", scope: !15, file: !1, line: 2, baseType: !10, size: 32) +!18 = !DIDerivedType(tag: DW_TAG_member, name: "b1", scope: !12, file: !1, line: 3, baseType: !19, size: 64, offset: 64) +!19 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !20, size: 64) +!20 = distinct !DICompositeType(tag: DW_TAG_structure_type, scope: !12, file: !1, line: 3, size: 64, elements: !21) +!21 = !{!22} +!22 = !DIDerivedType(tag: DW_TAG_member, name: "B1", scope: !20, file: !1, line: 3, baseType: !23, size: 64) +!23 = !DIBasicType(name: "long int", size: 64, encoding: DW_ATE_signed) +!24 = !{!25} +!25 = !DILocalVariable(name: "s1", arg: 1, scope: !7, file: !1, line: 5, type: !11) +!26 = !DILocation(line: 0, scope: !7) +!27 = !DILocation(line: 5, column: 25, scope: !7) diff --git a/llvm/test/CodeGen/SBF/BTF/struct-anon.ll b/llvm/test/CodeGen/SBF/BTF/struct-anon.ll new file mode 100644 index 0000000000000..150d711640171 --- /dev/null +++ b/llvm/test/CodeGen/SBF/BTF/struct-anon.ll @@ -0,0 +1,64 @@ +; RUN: llc -sbf-enable-btf-emission -march=sbf -filetype=asm -o - %s | FileCheck -check-prefixes=CHECK %s + +; Source code: +; struct { struct {int m;}; } a; +; Compilation flag: +; clang -target bpf -O2 -g -S -emit-llvm t.c + +%struct.anon = type { %struct.anon.0 } +%struct.anon.0 = type { i32 } + +@a = common dso_local local_unnamed_addr global %struct.anon zeroinitializer, align 4, !dbg !0 + +!llvm.dbg.cu = !{!2} +!llvm.module.flags = !{!13, !14, !15} +!llvm.ident = !{!16} + +; CHECK: .section .BTF,"",@progbits +; CHECK-NEXT: .short 60319 # 0xeb9f +; CHECK-NEXT: .byte 1 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .long 24 +; CHECK-NEXT: .long 0 +; CHECK-NEXT: .long 64 +; CHECK-NEXT: .long 64 +; CHECK-NEXT: .long 7 +; CHECK-NEXT: .long 0 # BTF_KIND_STRUCT(id = 1) +; CHECK-NEXT: .long 67108865 # 0x4000001 +; CHECK-NEXT: .long 4 +; CHECK-NEXT: .long 0 +; CHECK-NEXT: .long 2 +; CHECK-NEXT: .long 0 +; CHECK-NEXT: .long 0 # BTF_KIND_STRUCT(id = 2) +; CHECK-NEXT: .long 67108865 # 0x4000001 +; CHECK-NEXT: .long 4 +; CHECK-NEXT: .long 1 +; CHECK-NEXT: .long 3 +; CHECK-NEXT: .long 0 +; CHECK-NEXT: .long 3 # BTF_KIND_INT(id = 3) +; CHECK-NEXT: .long 16777216 # 0x1000000 +; CHECK-NEXT: .long 4 +; CHECK-NEXT: .long 16777248 # 0x1000020 +; CHECK-NEXT: .byte 0 # string offset=0 +; CHECK-NEXT: .byte 109 # string offset=1 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii "int" # string offset=3 +; CHECK-NEXT: .byte 0 + +!0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression()) +!1 = distinct !DIGlobalVariable(name: "a", scope: !2, file: !3, line: 1, type: !6, isLocal: false, isDefinition: true) +!2 = distinct !DICompileUnit(language: DW_LANG_C99, file: !3, producer: "clang version 8.0.0 (trunk 344789) (llvm/trunk 344782)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !4, globals: !5, nameTableKind: None) +!3 = !DIFile(filename: "t.c", directory: "/home/yhs/tmp") +!4 = !{} +!5 = !{!0} +!6 = distinct !DICompositeType(tag: DW_TAG_structure_type, file: !3, line: 1, size: 32, elements: !7) +!7 = !{!8} +!8 = !DIDerivedType(tag: DW_TAG_member, scope: !6, file: !3, line: 1, baseType: !9, size: 32) +!9 = distinct !DICompositeType(tag: DW_TAG_structure_type, scope: !6, file: !3, line: 1, size: 32, elements: !10) +!10 = !{!11} +!11 = !DIDerivedType(tag: DW_TAG_member, name: "m", scope: !9, file: !3, line: 1, baseType: !12, size: 32) +!12 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +!13 = !{i32 2, !"Dwarf Version", i32 4} +!14 = !{i32 2, !"Debug Info Version", i32 3} +!15 = !{i32 1, !"wchar_size", i32 4} +!16 = !{!"clang version 8.0.0 (trunk 344789) (llvm/trunk 344782)"} diff --git a/llvm/test/CodeGen/SBF/BTF/struct-basic.ll b/llvm/test/CodeGen/SBF/BTF/struct-basic.ll new file mode 100644 index 0000000000000..5e65eb38cdf17 --- /dev/null +++ b/llvm/test/CodeGen/SBF/BTF/struct-basic.ll @@ -0,0 +1,69 @@ +; RUN: llc -sbf-enable-btf-emission -march=sbf -filetype=asm -o - %s | FileCheck -check-prefixes=CHECK %s + +; Source code: +; struct t1 {char m1; int n1;} a; +; Compilation flag: +; clang -target bpf -O2 -g -S -emit-llvm t.c + +%struct.t1 = type { i8, i32 } + +@a = common dso_local local_unnamed_addr global %struct.t1 zeroinitializer, align 4, !dbg !0 + +!llvm.dbg.cu = !{!2} +!llvm.module.flags = !{!12, !13, !14} +!llvm.ident = !{!15} + +; CHECK: .section .BTF,"",@progbits +; CHECK-NEXT: .short 60319 # 0xeb9f +; CHECK-NEXT: .byte 1 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .long 24 +; CHECK-NEXT: .long 0 +; CHECK-NEXT: .long 68 +; CHECK-NEXT: .long 68 +; CHECK-NEXT: .long 19 +; CHECK-NEXT: .long 1 # BTF_KIND_STRUCT(id = 1) +; CHECK-NEXT: .long 67108866 # 0x4000002 +; CHECK-NEXT: .long 8 +; CHECK-NEXT: .long 4 +; CHECK-NEXT: .long 2 +; CHECK-NEXT: .long 0 +; CHECK-NEXT: .long 7 +; CHECK-NEXT: .long 3 +; CHECK-NEXT: .long 32 +; CHECK-NEXT: .long 10 # BTF_KIND_INT(id = 2) +; CHECK-NEXT: .long 16777216 # 0x1000000 +; CHECK-NEXT: .long 1 +; CHECK-NEXT: .long 16777224 # 0x1000008 +; CHECK-NEXT: .long 15 # BTF_KIND_INT(id = 3) +; CHECK-NEXT: .long 16777216 # 0x1000000 +; CHECK-NEXT: .long 4 +; CHECK-NEXT: .long 16777248 # 0x1000020 +; CHECK-NEXT: .byte 0 # string offset=0 +; CHECK-NEXT: .ascii "t1" # string offset=1 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii "m1" # string offset=4 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii "n1" # string offset=7 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii "char" # string offset=10 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii "int" # string offset=15 +; CHECK-NEXT: .byte 0 + +!0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression()) +!1 = distinct !DIGlobalVariable(name: "a", scope: !2, file: !3, line: 1, type: !6, isLocal: false, isDefinition: true) +!2 = distinct !DICompileUnit(language: DW_LANG_C99, file: !3, producer: "clang version 8.0.0 (trunk 345296) (llvm/trunk 345297)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !4, globals: !5, nameTableKind: None) +!3 = !DIFile(filename: "t.c", directory: "/home/yhs/tmp") +!4 = !{} +!5 = !{!0} +!6 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "t1", file: !3, line: 1, size: 64, elements: !7) +!7 = !{!8, !10} +!8 = !DIDerivedType(tag: DW_TAG_member, name: "m1", scope: !6, file: !3, line: 1, baseType: !9, size: 8) +!9 = !DIBasicType(name: "char", size: 8, encoding: DW_ATE_signed_char) +!10 = !DIDerivedType(tag: DW_TAG_member, name: "n1", scope: !6, file: !3, line: 1, baseType: !11, size: 32, offset: 32) +!11 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +!12 = !{i32 2, !"Dwarf Version", i32 4} +!13 = !{i32 2, !"Debug Info Version", i32 3} +!14 = !{i32 1, !"wchar_size", i32 4} +!15 = !{!"clang version 8.0.0 (trunk 345296) (llvm/trunk 345297)"} diff --git a/llvm/test/CodeGen/SBF/BTF/struct-bitfield-typedef.ll b/llvm/test/CodeGen/SBF/BTF/struct-bitfield-typedef.ll new file mode 100644 index 0000000000000..00cb3a3eb529a --- /dev/null +++ b/llvm/test/CodeGen/SBF/BTF/struct-bitfield-typedef.ll @@ -0,0 +1,87 @@ +; RUN: llc -sbf-enable-btf-emission -march=sbf -filetype=asm -o - %s | FileCheck -check-prefixes=CHECK %s + +; Source code: +; typedef int _int; +; typedef _int __int; +; struct {char m:2; __int n:3; char p;} a; +; Compilation flag: +; clang -target bpf -O2 -g -S -emit-llvm t.c + +%struct.anon = type { i8, i8, [2 x i8] } + +@a = common dso_local local_unnamed_addr global %struct.anon zeroinitializer, align 4, !dbg !0 + +!llvm.dbg.cu = !{!2} +!llvm.module.flags = !{!15, !16, !17} +!llvm.ident = !{!18} + +; CHECK: .section .BTF,"",@progbits +; CHECK-NEXT: .short 60319 # 0xeb9f +; CHECK-NEXT: .byte 1 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .long 24 +; CHECK-NEXT: .long 0 +; CHECK-NEXT: .long 104 +; CHECK-NEXT: .long 104 +; CHECK-NEXT: .long 27 +; CHECK-NEXT: .long 0 # BTF_KIND_STRUCT(id = 1) +; CHECK-NEXT: .long 2214592515 # 0x84000003 +; CHECK-NEXT: .long 4 +; CHECK-NEXT: .long 1 +; CHECK-NEXT: .long 2 +; CHECK-NEXT: .long 33554432 # 0x2000000 +; CHECK-NEXT: .long 3 +; CHECK-NEXT: .long 3 +; CHECK-NEXT: .long 50331650 # 0x3000002 +; CHECK-NEXT: .long 5 +; CHECK-NEXT: .long 2 +; CHECK-NEXT: .long 8 # 0x8 +; CHECK-NEXT: .long 7 # BTF_KIND_INT(id = 2) +; CHECK-NEXT: .long 16777216 # 0x1000000 +; CHECK-NEXT: .long 1 +; CHECK-NEXT: .long 16777224 # 0x1000008 +; CHECK-NEXT: .long 12 # BTF_KIND_TYPEDEF(id = 3) +; CHECK-NEXT: .long 134217728 # 0x8000000 +; CHECK-NEXT: .long 4 +; CHECK-NEXT: .long 18 # BTF_KIND_TYPEDEF(id = 4) +; CHECK-NEXT: .long 134217728 # 0x8000000 +; CHECK-NEXT: .long 5 +; CHECK-NEXT: .long 23 # BTF_KIND_INT(id = 5) +; CHECK-NEXT: .long 16777216 # 0x1000000 +; CHECK-NEXT: .long 4 +; CHECK-NEXT: .long 16777248 # 0x1000020 +; CHECK-NEXT: .byte 0 # string offset=0 +; CHECK-NEXT: .byte 109 # string offset=1 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .byte 110 # string offset=3 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .byte 112 # string offset=5 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii "char" # string offset=7 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii "__int" # string offset=12 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii "_int" # string offset=18 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii "int" # string offset=23 +; CHECK-NEXT: .byte 0 + +!0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression()) +!1 = distinct !DIGlobalVariable(name: "a", scope: !2, file: !3, line: 3, type: !6, isLocal: false, isDefinition: true) +!2 = distinct !DICompileUnit(language: DW_LANG_C99, file: !3, producer: "clang version 8.0.0 (trunk 345296) (llvm/trunk 345297)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !4, globals: !5, nameTableKind: None) +!3 = !DIFile(filename: "t.c", directory: "/home/yhs/tmp") +!4 = !{} +!5 = !{!0} +!6 = distinct !DICompositeType(tag: DW_TAG_structure_type, file: !3, line: 3, size: 32, elements: !7) +!7 = !{!8, !10, !14} +!8 = !DIDerivedType(tag: DW_TAG_member, name: "m", scope: !6, file: !3, line: 3, baseType: !9, size: 2, flags: DIFlagBitField, extraData: i64 0) +!9 = !DIBasicType(name: "char", size: 8, encoding: DW_ATE_signed_char) +!10 = !DIDerivedType(tag: DW_TAG_member, name: "n", scope: !6, file: !3, line: 3, baseType: !11, size: 3, offset: 2, flags: DIFlagBitField, extraData: i64 0) +!11 = !DIDerivedType(tag: DW_TAG_typedef, name: "__int", file: !3, line: 2, baseType: !12) +!12 = !DIDerivedType(tag: DW_TAG_typedef, name: "_int", file: !3, line: 1, baseType: !13) +!13 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +!14 = !DIDerivedType(tag: DW_TAG_member, name: "p", scope: !6, file: !3, line: 3, baseType: !9, size: 8, offset: 8) +!15 = !{i32 2, !"Dwarf Version", i32 4} +!16 = !{i32 2, !"Debug Info Version", i32 3} +!17 = !{i32 1, !"wchar_size", i32 4} +!18 = !{!"clang version 8.0.0 (trunk 345296) (llvm/trunk 345297)"} diff --git a/llvm/test/CodeGen/SBF/BTF/struct-enum.ll b/llvm/test/CodeGen/SBF/BTF/struct-enum.ll new file mode 100644 index 0000000000000..368b1241b9cb0 --- /dev/null +++ b/llvm/test/CodeGen/SBF/BTF/struct-enum.ll @@ -0,0 +1,74 @@ +; RUN: llc -sbf-enable-btf-emission -march=sbf -filetype=asm -o - %s | FileCheck -check-prefixes=CHECK %s + +; Source code: +; enum t1 { A , B }; +; struct t2 { enum t1 m:2; enum t1 n; } a; +; Compilation flag: +; clang -target bpf -O2 -g -S -emit-llvm t.c + +%struct.t2 = type { i8, i32 } + +@a = common dso_local local_unnamed_addr global %struct.t2 zeroinitializer, align 4, !dbg !0 + +!llvm.dbg.cu = !{!2} +!llvm.module.flags = !{!15, !16, !17} +!llvm.ident = !{!18} + +; CHECK: .section .BTF,"",@progbits +; CHECK-NEXT: .short 60319 # 0xeb9f +; CHECK-NEXT: .byte 1 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .long 24 +; CHECK-NEXT: .long 0 +; CHECK-NEXT: .long 64 +; CHECK-NEXT: .long 64 +; CHECK-NEXT: .long 15 +; CHECK-NEXT: .long 1 # BTF_KIND_STRUCT(id = 1) +; CHECK-NEXT: .long 2214592514 # 0x84000002 +; CHECK-NEXT: .long 8 +; CHECK-NEXT: .long 4 +; CHECK-NEXT: .long 2 +; CHECK-NEXT: .long 33554432 # 0x2000000 +; CHECK-NEXT: .long 6 +; CHECK-NEXT: .long 2 +; CHECK-NEXT: .long 32 # 0x20 +; CHECK-NEXT: .long 8 # BTF_KIND_ENUM(id = 2) +; CHECK-NEXT: .long 100663298 # 0x6000002 +; CHECK-NEXT: .long 4 +; CHECK-NEXT: .long 11 +; CHECK-NEXT: .long 0 +; CHECK-NEXT: .long 13 +; CHECK-NEXT: .long 1 +; CHECK-NEXT: .byte 0 # string offset=0 +; CHECK-NEXT: .ascii "t2" # string offset=1 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .byte 109 # string offset=4 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .byte 110 # string offset=6 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii "t1" # string offset=8 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .byte 65 # string offset=11 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .byte 66 # string offset=13 +; CHECK-NEXT: .byte 0 + +!0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression()) +!1 = distinct !DIGlobalVariable(name: "a", scope: !2, file: !3, line: 2, type: !11, isLocal: false, isDefinition: true) +!2 = distinct !DICompileUnit(language: DW_LANG_C99, file: !3, producer: "clang version 8.0.0 (trunk 344789) (llvm/trunk 344782)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !4, globals: !10, nameTableKind: None) +!3 = !DIFile(filename: "t.c", directory: "/home/yhs/tmp") +!4 = !{!5} +!5 = !DICompositeType(tag: DW_TAG_enumeration_type, name: "t1", file: !3, line: 1, baseType: !6, size: 32, elements: !7) +!6 = !DIBasicType(name: "unsigned int", size: 32, encoding: DW_ATE_unsigned) +!7 = !{!8, !9} +!8 = !DIEnumerator(name: "A", value: 0, isUnsigned: true) +!9 = !DIEnumerator(name: "B", value: 1, isUnsigned: true) +!10 = !{!0} +!11 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "t2", file: !3, line: 2, size: 64, elements: !12) +!12 = !{!13, !14} +!13 = !DIDerivedType(tag: DW_TAG_member, name: "m", scope: !11, file: !3, line: 2, baseType: !5, size: 2, flags: DIFlagBitField, extraData: i64 0) +!14 = !DIDerivedType(tag: DW_TAG_member, name: "n", scope: !11, file: !3, line: 2, baseType: !5, size: 32, offset: 32) +!15 = !{i32 2, !"Dwarf Version", i32 4} +!16 = !{i32 2, !"Debug Info Version", i32 3} +!17 = !{i32 1, !"wchar_size", i32 4} +!18 = !{!"clang version 8.0.0 (trunk 344789) (llvm/trunk 344782)"} diff --git a/llvm/test/CodeGen/SBF/BTF/tag-1.ll b/llvm/test/CodeGen/SBF/BTF/tag-1.ll new file mode 100644 index 0000000000000..9c2d16d83eb1b --- /dev/null +++ b/llvm/test/CodeGen/SBF/BTF/tag-1.ll @@ -0,0 +1,90 @@ +; RUN: llc -sbf-enable-btf-emission -march=sbf -filetype=asm -o - %s | FileCheck -check-prefixes=CHECK %s + +; Source code: +; #define __tag1 __attribute__((btf_decl_tag("tag1"))) +; #define __tag2 __attribute__((btf_decl_tag("tag2"))) +; struct t1 { +; int a1; +; int a2 __tag1 __tag2; +; } __tag1 __tag2; +; struct t1 g1 __tag1 __tag2; +; Compilation flag: +; clang -target bpf -O2 -g -S -emit-llvm t.c + +%struct.t1 = type { i32, i32 } + +@g1 = dso_local local_unnamed_addr global %struct.t1 zeroinitializer, align 4, !dbg !0 + +!llvm.dbg.cu = !{!2} +!llvm.module.flags = !{!14, !15, !16, !17} +!llvm.ident = !{!18} + +!0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression()) +!1 = distinct !DIGlobalVariable(name: "g1", scope: !2, file: !3, line: 7, type: !6, isLocal: false, isDefinition: true, annotations: !11) +!2 = distinct !DICompileUnit(language: DW_LANG_C99, file: !3, producer: "clang version 13.0.0 (https://github.com/llvm/llvm-project.git 825661b8e31d0b29d78178df1e518949dfec9f9a)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !4, globals: !5, splitDebugInlining: false, nameTableKind: None) +!3 = !DIFile(filename: "t.c", directory: "/tmp/home/yhs/work/tests/llvm/btf_tag") +!4 = !{} +!5 = !{!0} +!6 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "t1", file: !3, line: 3, size: 64, elements: !7, annotations: !11) +!7 = !{!8, !10} +!8 = !DIDerivedType(tag: DW_TAG_member, name: "a1", scope: !6, file: !3, line: 4, baseType: !9, size: 32) +!9 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +!10 = !DIDerivedType(tag: DW_TAG_member, name: "a2", scope: !6, file: !3, line: 5, baseType: !9, size: 32, offset: 32, annotations: !11) +!11 = !{!12, !13} +!12 = !{!"btf_decl_tag", !"tag1"} +!13 = !{!"btf_decl_tag", !"tag2"} +!14 = !{i32 7, !"Dwarf Version", i32 4} +!15 = !{i32 2, !"Debug Info Version", i32 3} +!16 = !{i32 1, !"wchar_size", i32 4} +!17 = !{i32 7, !"frame-pointer", i32 2} +!18 = !{!"clang version 13.0.0 (https://github.com/llvm/llvm-project.git 825661b8e31d0b29d78178df1e518949dfec9f9a)"} + +; CHECK: .long 1 # BTF_KIND_STRUCT(id = 1) +; CHECK-NEXT: .long 67108866 # 0x4000002 +; CHECK-NEXT: .long 8 +; CHECK-NEXT: .long 4 +; CHECK-NEXT: .long 4 +; CHECK-NEXT: .long 0 # 0x0 +; CHECK-NEXT: .long 7 +; CHECK-NEXT: .long 4 +; CHECK-NEXT: .long 32 # 0x20 +; CHECK-NEXT: .long 10 # BTF_KIND_DECL_TAG(id = 2) +; CHECK-NEXT: .long 285212672 # 0x11000000 +; CHECK-NEXT: .long 1 +; CHECK-NEXT: .long 4294967295 +; CHECK-NEXT: .long 15 # BTF_KIND_DECL_TAG(id = 3) +; CHECK-NEXT: .long 285212672 # 0x11000000 +; CHECK-NEXT: .long 1 +; CHECK-NEXT: .long 4294967295 +; CHECK-NEXT: .long 20 # BTF_KIND_INT(id = 4) +; CHECK-NEXT: .long 16777216 # 0x1000000 +; CHECK-NEXT: .long 4 +; CHECK-NEXT: .long 16777248 # 0x1000020 +; CHECK-NEXT: .long 10 # BTF_KIND_DECL_TAG(id = 5) +; CHECK-NEXT: .long 285212672 # 0x11000000 +; CHECK-NEXT: .long 1 +; CHECK-NEXT: .long 1 +; CHECK-NEXT: .long 15 # BTF_KIND_DECL_TAG(id = 6) +; CHECK-NEXT: .long 285212672 # 0x11000000 +; CHECK-NEXT: .long 1 +; CHECK-NEXT: .long 1 +; CHECK-NEXT: .long 24 # BTF_KIND_VAR(id = 7) +; CHECK-NEXT: .long 234881024 # 0xe000000 +; CHECK-NEXT: .long 1 +; CHECK-NEXT: .long 1 +; CHECK-NEXT: .long 10 # BTF_KIND_DECL_TAG(id = 8) +; CHECK-NEXT: .long 285212672 # 0x11000000 +; CHECK-NEXT: .long 7 +; CHECK-NEXT: .long 4294967295 +; CHECK-NEXT: .long 15 # BTF_KIND_DECL_TAG(id = 9) +; CHECK-NEXT: .long 285212672 # 0x11000000 +; CHECK-NEXT: .long 7 +; CHECK-NEXT: .long 4294967295 + +; CHECK: .ascii "t1" # string offset=1 +; CHECK: .ascii "a1" # string offset=4 +; CHECK: .ascii "a2" # string offset=7 +; CHECK: .ascii "tag1" # string offset=10 +; CHECK: .ascii "tag2" # string offset=15 +; CHECK: .ascii "int" # string offset=20 +; CHECK: .ascii "g1" # string offset=24 diff --git a/llvm/test/CodeGen/SBF/BTF/tag-2.ll b/llvm/test/CodeGen/SBF/BTF/tag-2.ll new file mode 100644 index 0000000000000..5973c06365291 --- /dev/null +++ b/llvm/test/CodeGen/SBF/BTF/tag-2.ll @@ -0,0 +1,125 @@ +; RUN: llc -sbf-enable-btf-emission -march=sbf -filetype=asm -o - %s | FileCheck -check-prefixes=CHECK %s + +; Source code: +; #define __tag1 __attribute__((btf_decl_tag("tag1"))) +; #define __tag2 __attribute__((btf_decl_tag("tag2"))) +; extern int bar(int a1, int a2) __tag1 __tag2; +; int __tag1 foo(int arg1, int *arg2 __tag1) { +; ; return arg1 + *arg2 + bar(arg1, arg1 + 1); +; } +; Compilation flag: +; clang -target bpf -O2 -g -S -emit-llvm t.c + +; Function Attrs: nounwind +define dso_local i32 @foo(i32 %arg1, i32* nocapture readonly %arg2) local_unnamed_addr #0 !dbg !8 { +entry: + call void @llvm.dbg.value(metadata i32 %arg1, metadata !14, metadata !DIExpression()), !dbg !18 + call void @llvm.dbg.value(metadata i32* %arg2, metadata !15, metadata !DIExpression()), !dbg !18 + %0 = load i32, i32* %arg2, align 4, !dbg !19, !tbaa !20 + %add = add nsw i32 %0, %arg1, !dbg !24 + %add1 = add nsw i32 %arg1, 1, !dbg !25 + %call = tail call i32 @bar(i32 %arg1, i32 %add1) #3, !dbg !26 + %add2 = add nsw i32 %add, %call, !dbg !27 + ret i32 %add2, !dbg !28 +} + +declare !dbg !29 dso_local i32 @bar(i32, i32) local_unnamed_addr #1 + +; Function Attrs: nofree nosync nounwind readnone speculatable willreturn +declare void @llvm.dbg.value(metadata, metadata, metadata) #2 + +attributes #0 = { nounwind "frame-pointer"="all" "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" } +attributes #1 = { "frame-pointer"="all" "no-trapping-math"="true" "stack-protector-buffer-size"="8" } +attributes #2 = { nofree nosync nounwind readnone speculatable willreturn } +attributes #3 = { nounwind } + +!llvm.dbg.cu = !{!0} +!llvm.module.flags = !{!3, !4, !5, !6} +!llvm.ident = !{!7} + +!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 14.0.0 (https://github.com/llvm/llvm-project.git 4be11596b26383c6666f471f07463a3f79e11964)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, splitDebugInlining: false, nameTableKind: None) +!1 = !DIFile(filename: "t.c", directory: "/tmp/home/yhs/work/tests/llvm/btf_tag") +!2 = !{} +!3 = !{i32 7, !"Dwarf Version", i32 4} +!4 = !{i32 2, !"Debug Info Version", i32 3} +!5 = !{i32 1, !"wchar_size", i32 4} +!6 = !{i32 7, !"frame-pointer", i32 2} +!7 = !{!"clang version 14.0.0 (https://github.com/llvm/llvm-project.git 4be11596b26383c6666f471f07463a3f79e11964)"} +!8 = distinct !DISubprogram(name: "foo", scope: !1, file: !1, line: 4, type: !9, scopeLine: 4, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !13, annotations: !16) +!9 = !DISubroutineType(types: !10) +!10 = !{!11, !11, !12} +!11 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +!12 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !11, size: 64) +!13 = !{!14, !15} +!14 = !DILocalVariable(name: "arg1", arg: 1, scope: !8, file: !1, line: 4, type: !11) +!15 = !DILocalVariable(name: "arg2", arg: 2, scope: !8, file: !1, line: 4, type: !12, annotations: !16) +!16 = !{!17} +!17 = !{!"btf_decl_tag", !"tag1"} +!18 = !DILocation(line: 0, scope: !8) +!19 = !DILocation(line: 5, column: 17, scope: !8) +!20 = !{!21, !21, i64 0} +!21 = !{!"int", !22, i64 0} +!22 = !{!"omnipotent char", !23, i64 0} +!23 = !{!"Simple C/C++ TBAA"} +!24 = !DILocation(line: 5, column: 15, scope: !8) +!25 = !DILocation(line: 5, column: 40, scope: !8) +!26 = !DILocation(line: 5, column: 25, scope: !8) +!27 = !DILocation(line: 5, column: 23, scope: !8) +!28 = !DILocation(line: 5, column: 3, scope: !8) +!29 = !DISubprogram(name: "bar", scope: !1, file: !1, line: 3, type: !30, flags: DIFlagPrototyped, spFlags: DISPFlagOptimized, retainedNodes: !2, annotations: !32) +!30 = !DISubroutineType(types: !31) +!31 = !{!11, !11, !11} +!32 = !{!17, !33} +!33 = !{!"btf_decl_tag", !"tag2"} + +; CHECK: .long 1 # BTF_KIND_INT(id = 1) +; CHECK-NEXT: .long 16777216 # 0x1000000 +; CHECK-NEXT: .long 4 +; CHECK-NEXT: .long 16777248 # 0x1000020 +; CHECK-NEXT: .long 0 # BTF_KIND_PTR(id = 2) +; CHECK-NEXT: .long 33554432 # 0x2000000 +; CHECK-NEXT: .long 1 +; CHECK-NEXT: .long 0 # BTF_KIND_FUNC_PROTO(id = 3) +; CHECK-NEXT: .long 218103810 # 0xd000002 +; CHECK-NEXT: .long 1 +; CHECK-NEXT: .long 5 +; CHECK-NEXT: .long 1 +; CHECK-NEXT: .long 10 +; CHECK-NEXT: .long 2 +; CHECK-NEXT: .long 15 # BTF_KIND_FUNC(id = 4) +; CHECK-NEXT: .long 201326593 # 0xc000001 +; CHECK-NEXT: .long 3 +; CHECK-NEXT: .long 19 # BTF_KIND_DECL_TAG(id = 5) +; CHECK-NEXT: .long 285212672 # 0x11000000 +; CHECK-NEXT: .long 4 +; CHECK-NEXT: .long 1 +; CHECK-NEXT: .long 19 # BTF_KIND_DECL_TAG(id = 6) +; CHECK-NEXT: .long 285212672 # 0x11000000 +; CHECK-NEXT: .long 4 +; CHECK-NEXT: .long 4294967295 +; CHECK-NEXT: .long 0 # BTF_KIND_FUNC_PROTO(id = 7) +; CHECK-NEXT: .long 218103810 # 0xd000002 +; CHECK-NEXT: .long 1 +; CHECK-NEXT: .long 0 +; CHECK-NEXT: .long 1 +; CHECK-NEXT: .long 0 +; CHECK-NEXT: .long 1 +; CHECK-NEXT: .long 72 # BTF_KIND_FUNC(id = 8) +; CHECK-NEXT: .long 201326594 # 0xc000002 +; CHECK-NEXT: .long 7 +; CHECK-NEXT: .long 19 # BTF_KIND_DECL_TAG(id = 9) +; CHECK-NEXT: .long 285212672 # 0x11000000 +; CHECK-NEXT: .long 8 +; CHECK-NEXT: .long 4294967295 +; CHECK-NEXT: .long 76 # BTF_KIND_DECL_TAG(id = 10) +; CHECK-NEXT: .long 285212672 # 0x11000000 +; CHECK-NEXT: .long 8 +; CHECK-NEXT: .long 4294967295 + +; CHECK: .ascii "int" # string offset=1 +; CHECK: .ascii "arg1" # string offset=5 +; CHECK: .ascii "arg2" # string offset=10 +; CHECK: .ascii "foo" # string offset=15 +; CHECK: .ascii "tag1" # string offset=19 +; CHECK: .ascii "bar" # string offset=72 +; CHECK: .ascii "tag2" # string offset=76 diff --git a/llvm/test/CodeGen/SBF/BTF/tag-typedef.ll b/llvm/test/CodeGen/SBF/BTF/tag-typedef.ll new file mode 100644 index 0000000000000..d8acdd73e9293 --- /dev/null +++ b/llvm/test/CodeGen/SBF/BTF/tag-typedef.ll @@ -0,0 +1,86 @@ +; RUN: llc -sbf-enable-btf-emission -march=sbf -filetype=asm -o - %s | FileCheck -check-prefixes=CHECK %s + +; Source code: +; #define __tag1 __attribute__((btf_decl_tag("tag1"))) +; typedef struct { int a; } __s __tag1; +; typedef unsigned * __u __tag1; +; __s a; +; __u u; +; Compilation flag: +; clang -target bpf -O2 -g -S -emit-llvm t.c + +%struct.__s = type { i32 } + +@a = dso_local local_unnamed_addr global %struct.__s zeroinitializer, align 4, !dbg !0 +@u = dso_local local_unnamed_addr global i32* null, align 8, !dbg !5 + +!llvm.dbg.cu = !{!2} +!llvm.module.flags = !{!17, !18, !19, !20} +!llvm.ident = !{!21} + +!0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression()) +!1 = distinct !DIGlobalVariable(name: "a", scope: !2, file: !3, line: 4, type: !12, isLocal: false, isDefinition: true) +!2 = distinct !DICompileUnit(language: DW_LANG_C99, file: !3, producer: "clang version 14.0.0 (https://github.com/llvm/llvm-project.git 219b26fbcd70273ddfd4ead9387f7c69b7eb4570)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, globals: !4, splitDebugInlining: false, nameTableKind: None) +!3 = !DIFile(filename: "t.c", directory: "/tmp/home/yhs/work/tests/llvm/btf_tag") +!4 = !{!0, !5} +!5 = !DIGlobalVariableExpression(var: !6, expr: !DIExpression()) +!6 = distinct !DIGlobalVariable(name: "u", scope: !2, file: !3, line: 5, type: !7, isLocal: false, isDefinition: true) +!7 = !DIDerivedType(tag: DW_TAG_typedef, name: "__u", file: !3, line: 3, baseType: !8, annotations: !10) +!8 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !9, size: 64) +!9 = !DIBasicType(name: "unsigned int", size: 32, encoding: DW_ATE_unsigned) +!10 = !{!11} +!11 = !{!"btf_decl_tag", !"tag1"} +!12 = !DIDerivedType(tag: DW_TAG_typedef, name: "__s", file: !3, line: 2, baseType: !13, annotations: !10) +!13 = distinct !DICompositeType(tag: DW_TAG_structure_type, file: !3, line: 2, size: 32, elements: !14) +!14 = !{!15} +!15 = !DIDerivedType(tag: DW_TAG_member, name: "a", scope: !13, file: !3, line: 2, baseType: !16, size: 32) +!16 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +!17 = !{i32 7, !"Dwarf Version", i32 4} +!18 = !{i32 2, !"Debug Info Version", i32 3} +!19 = !{i32 1, !"wchar_size", i32 4} +!20 = !{i32 7, !"frame-pointer", i32 2} +!21 = !{!"clang version 14.0.0 (https://github.com/llvm/llvm-project.git 219b26fbcd70273ddfd4ead9387f7c69b7eb4570)"} + +; CHECK: .long 1 # BTF_KIND_TYPEDEF(id = 1) +; CHECK-NEXT: .long 134217728 # 0x8000000 +; CHECK-NEXT: .long 3 +; CHECK-NEXT: .long 5 # BTF_KIND_DECL_TAG(id = 2) +; CHECK-NEXT: .long 285212672 # 0x11000000 +; CHECK-NEXT: .long 1 +; CHECK-NEXT: .long 4294967295 +; CHECK-NEXT: .long 0 # BTF_KIND_STRUCT(id = 3) +; CHECK-NEXT: .long 67108865 # 0x4000001 +; CHECK-NEXT: .long 4 +; CHECK-NEXT: .long 10 +; CHECK-NEXT: .long 4 +; CHECK-NEXT: .long 0 # 0x0 +; CHECK-NEXT: .long 12 # BTF_KIND_INT(id = 4) +; CHECK-NEXT: .long 16777216 # 0x1000000 +; CHECK-NEXT: .long 4 +; CHECK-NEXT: .long 16777248 # 0x1000020 +; CHECK-NEXT: .long 10 # BTF_KIND_VAR(id = 5) +; CHECK-NEXT: .long 234881024 # 0xe000000 +; CHECK-NEXT: .long 1 +; CHECK-NEXT: .long 1 +; CHECK-NEXT: .long 16 # BTF_KIND_TYPEDEF(id = 6) +; CHECK-NEXT: .long 134217728 # 0x8000000 +; CHECK-NEXT: .long 8 +; CHECK-NEXT: .long 5 # BTF_KIND_DECL_TAG(id = 7) +; CHECK-NEXT: .long 285212672 # 0x11000000 +; CHECK-NEXT: .long 6 +; CHECK-NEXT: .long 4294967295 +; CHECK-NEXT: .long 0 # BTF_KIND_PTR(id = 8) +; CHECK-NEXT: .long 33554432 # 0x2000000 +; CHECK-NEXT: .long 9 +; CHECK-NEXT: .long 20 # BTF_KIND_INT(id = 9) +; CHECK-NEXT: .long 16777216 # 0x1000000 +; CHECK-NEXT: .long 4 +; CHECK-NEXT: .long 32 # 0x20 + +; CHECK: .ascii "__s" # string offset=1 +; CHECK: .ascii "tag1" # string offset=5 +; CHECK: .byte 97 # string offset=10 +; CHECK: .ascii "int" # string offset=12 +; CHECK: .ascii "__u" # string offset=16 +; CHECK: .ascii "unsigned int" # string offset=20 + diff --git a/llvm/test/CodeGen/SBF/BTF/type-tag-fixup-fwd.ll b/llvm/test/CodeGen/SBF/BTF/type-tag-fixup-fwd.ll new file mode 100644 index 0000000000000..2523959158760 --- /dev/null +++ b/llvm/test/CodeGen/SBF/BTF/type-tag-fixup-fwd.ll @@ -0,0 +1,130 @@ +; RUN: llc -sbf-enable-btf-emission -march=sbf -filetype=asm -o - %s | FileCheck -check-prefixes=CHECK %s +; +; Source: +; #define __tag1 __attribute__((btf_type_tag("tag1"))) +; #define __tag2 __attribute__((btf_type_tag("tag2"))) +; +; struct foo; +; struct map_value { +; struct foo __tag2 __tag1 *ptr; +; }; +; void func(struct map_value *); +; void test(void) +; { +; struct map_value v = {}; +; func(&v); +; } +; Compilation flag: +; clang -target bpf -O2 -g -S -emit-llvm test.c + +%struct.map_value = type { %struct.foo* } +%struct.foo = type opaque + +; Function Attrs: nounwind +define dso_local void @test() local_unnamed_addr #0 !dbg !7 { +entry: + %v = alloca %struct.map_value, align 8 + %0 = bitcast %struct.map_value* %v to i8*, !dbg !20 + call void @llvm.lifetime.start.p0i8(i64 8, i8* nonnull %0) #4, !dbg !20 + call void @llvm.dbg.declare(metadata %struct.map_value* %v, metadata !11, metadata !DIExpression()), !dbg !21 + %1 = bitcast %struct.map_value* %v to i64*, !dbg !21 + store i64 0, i64* %1, align 8, !dbg !21 + call void @func(%struct.map_value* noundef nonnull %v) #4, !dbg !22 + call void @llvm.lifetime.end.p0i8(i64 8, i8* nonnull %0) #4, !dbg !23 + ret void, !dbg !23 +} + +; CHECK: .long 0 # BTF_KIND_FUNC_PROTO(id = 1) +; CHECK-NEXT: .long 218103808 # 0xd000000 +; CHECK-NEXT: .long 0 +; CHECK-NEXT: .long 1 # BTF_KIND_FUNC(id = 2) +; CHECK-NEXT: .long 201326593 # 0xc000001 +; CHECK-NEXT: .long 1 +; CHECK-NEXT: .long 0 # BTF_KIND_FUNC_PROTO(id = 3) +; CHECK-NEXT: .long 218103809 # 0xd000001 +; CHECK-NEXT: .long 0 +; CHECK-NEXT: .long 0 +; CHECK-NEXT: .long 4 +; CHECK-NEXT: .long 0 # BTF_KIND_PTR(id = 4) +; CHECK-NEXT: .long 33554432 # 0x2000000 +; CHECK-NEXT: .long 5 +; CHECK-NEXT: .long 62 # BTF_KIND_STRUCT(id = 5) +; CHECK-NEXT: .long 67108865 # 0x4000001 +; CHECK-NEXT: .long 8 +; CHECK-NEXT: .long 72 +; CHECK-NEXT: .long 8 +; CHECK-NEXT: .long 0 # 0x0 +; CHECK-NEXT: .long 76 # BTF_KIND_TYPE_TAG(id = 6) +; CHECK-NEXT: .long 301989888 # 0x12000000 +; CHECK-NEXT: .long 9 +; CHECK-NEXT: .long 81 # BTF_KIND_TYPE_TAG(id = 7) +; CHECK-NEXT: .long 301989888 # 0x12000000 +; CHECK-NEXT: .long 6 +; CHECK-NEXT: .long 0 # BTF_KIND_PTR(id = 8) +; CHECK-NEXT: .long 33554432 # 0x2000000 +; CHECK-NEXT: .long 7 +; CHECK-NEXT: .long 86 # BTF_KIND_FWD(id = 9) +; CHECK-NEXT: .long 117440512 # 0x7000000 +; CHECK-NEXT: .long 0 +; CHECK-NEXT: .long 90 # BTF_KIND_FUNC(id = 10) +; CHECK-NEXT: .long 201326594 # 0xc000002 +; CHECK-NEXT: .long 3 + +; CHECK: .ascii "test" # string offset=1 +; CHECK: .ascii "map_value" # string offset=62 +; CHECK: .ascii "ptr" # string offset=72 +; CHECK: .ascii "tag2" # string offset=76 +; CHECK: .ascii "tag1" # string offset=81 +; CHECK: .ascii "foo" # string offset=86 +; CHECK: .ascii "func" # string offset=90 + +; Function Attrs: argmemonly mustprogress nofree nosync nounwind willreturn +declare void @llvm.lifetime.start.p0i8(i64 immarg, i8* nocapture) #1 + +; Function Attrs: mustprogress nofree nosync nounwind readnone speculatable willreturn +declare void @llvm.dbg.declare(metadata, metadata, metadata) #2 + +declare !dbg !24 dso_local void @func(%struct.map_value* noundef) local_unnamed_addr #3 + +; Function Attrs: argmemonly mustprogress nofree nosync nounwind willreturn +declare void @llvm.lifetime.end.p0i8(i64 immarg, i8* nocapture) #1 + +attributes #0 = { nounwind "frame-pointer"="all" "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" } +attributes #1 = { argmemonly mustprogress nofree nosync nounwind willreturn } +attributes #2 = { mustprogress nofree nosync nounwind readnone speculatable willreturn } +attributes #3 = { "frame-pointer"="all" "no-trapping-math"="true" "stack-protector-buffer-size"="8" } +attributes #4 = { nounwind } + +!llvm.dbg.cu = !{!0} +!llvm.module.flags = !{!2, !3, !4, !5} +!llvm.ident = !{!6} + +!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 15.0.0 (https://github.com/llvm/llvm-project.git 25e8505f515bc9ef6c13527ffc4a902bae3a9071)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, splitDebugInlining: false, nameTableKind: None) +!1 = !DIFile(filename: "test.c", directory: "/tmp/home/yhs/work/tests/llvm/btf_tag_type", checksumkind: CSK_MD5, checksum: "7735a89e98603fee29d352a8e9db5acb") +!2 = !{i32 7, !"Dwarf Version", i32 5} +!3 = !{i32 2, !"Debug Info Version", i32 3} +!4 = !{i32 1, !"wchar_size", i32 4} +!5 = !{i32 7, !"frame-pointer", i32 2} +!6 = !{!"clang version 15.0.0 (https://github.com/llvm/llvm-project.git 25e8505f515bc9ef6c13527ffc4a902bae3a9071)"} +!7 = distinct !DISubprogram(name: "test", scope: !1, file: !1, line: 9, type: !8, scopeLine: 10, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !10) +!8 = !DISubroutineType(types: !9) +!9 = !{null} +!10 = !{!11} +!11 = !DILocalVariable(name: "v", scope: !7, file: !1, line: 11, type: !12) +!12 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "map_value", file: !1, line: 5, size: 64, elements: !13) +!13 = !{!14} +!14 = !DIDerivedType(tag: DW_TAG_member, name: "ptr", scope: !12, file: !1, line: 6, baseType: !15, size: 64) +!15 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !16, size: 64, annotations: !17) +!16 = !DICompositeType(tag: DW_TAG_structure_type, name: "foo", file: !1, line: 4, flags: DIFlagFwdDecl) +!17 = !{!18, !19} +!18 = !{!"btf_type_tag", !"tag2"} +!19 = !{!"btf_type_tag", !"tag1"} +!20 = !DILocation(line: 11, column: 9, scope: !7) +!21 = !DILocation(line: 11, column: 26, scope: !7) +!22 = !DILocation(line: 12, column: 9, scope: !7) +!23 = !DILocation(line: 13, column: 1, scope: !7) +!24 = !DISubprogram(name: "func", scope: !1, file: !1, line: 8, type: !25, flags: DIFlagPrototyped, spFlags: DISPFlagOptimized, retainedNodes: !28) +!25 = !DISubroutineType(types: !26) +!26 = !{null, !27} +!27 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !12, size: 64) +!28 = !{} diff --git a/llvm/test/CodeGen/SBF/BTF/type-tag-fixup-resolved.ll b/llvm/test/CodeGen/SBF/BTF/type-tag-fixup-resolved.ll new file mode 100644 index 0000000000000..533047f8fb7ad --- /dev/null +++ b/llvm/test/CodeGen/SBF/BTF/type-tag-fixup-resolved.ll @@ -0,0 +1,150 @@ +; RUN: llc -sbf-enable-btf-emission -march=sbf -filetype=asm -o - %s | FileCheck -check-prefixes=CHECK %s +; +; Source: +; #define __tag1 __attribute__((btf_type_tag("tag1"))) +; #define __tag2 __attribute__((btf_type_tag("tag2"))) +; +; struct foo { +; int i; +; }; +; struct map_value { +; struct foo __tag2 __tag1 *ptr; +; }; +; void func(struct map_value *, struct foo *); +; void test(void) +; { +; struct map_value v = {}; +; func(&v, v.ptr); +; } +; Compilation flag: +; clang -target bpf -O2 -g -S -emit-llvm test.c + +%struct.map_value = type { %struct.foo* } +%struct.foo = type { i32 } + +; Function Attrs: nounwind +define dso_local void @test() local_unnamed_addr #0 !dbg !7 { +entry: + %v = alloca %struct.map_value, align 8 + %0 = bitcast %struct.map_value* %v to i8*, !dbg !23 + call void @llvm.lifetime.start.p0i8(i64 8, i8* nonnull %0) #4, !dbg !23 + call void @llvm.dbg.declare(metadata %struct.map_value* %v, metadata !11, metadata !DIExpression()), !dbg !24 + %1 = bitcast %struct.map_value* %v to i64*, !dbg !24 + store i64 0, i64* %1, align 8, !dbg !24 + call void @func(%struct.map_value* noundef nonnull %v, %struct.foo* noundef null) #4, !dbg !25 + call void @llvm.lifetime.end.p0i8(i64 8, i8* nonnull %0) #4, !dbg !26 + ret void, !dbg !26 +} + +; CHECK: .long 0 # BTF_KIND_FUNC_PROTO(id = 1) +; CHECK-NEXT: .long 218103808 # 0xd000000 +; CHECK-NEXT: .long 0 +; CHECK-NEXT: .long 1 # BTF_KIND_FUNC(id = 2) +; CHECK-NEXT: .long 201326593 # 0xc000001 +; CHECK-NEXT: .long 1 +; CHECK-NEXT: .long 0 # BTF_KIND_FUNC_PROTO(id = 3) +; CHECK-NEXT: .long 218103810 # 0xd000002 +; CHECK-NEXT: .long 0 +; CHECK-NEXT: .long 0 +; CHECK-NEXT: .long 4 +; CHECK-NEXT: .long 0 +; CHECK-NEXT: .long 7 +; CHECK-NEXT: .long 0 # BTF_KIND_PTR(id = 4) +; CHECK-NEXT: .long 33554432 # 0x2000000 +; CHECK-NEXT: .long 5 +; CHECK-NEXT: .long 63 # BTF_KIND_STRUCT(id = 5) +; CHECK-NEXT: .long 67108865 # 0x4000001 +; CHECK-NEXT: .long 8 +; CHECK-NEXT: .long 73 +; CHECK-NEXT: .long 6 +; CHECK-NEXT: .long 0 # 0x0 +; CHECK-NEXT: .long 0 # BTF_KIND_PTR(id = 6) +; CHECK-NEXT: .long 33554432 # 0x2000000 +; CHECK-NEXT: .long 12 +; CHECK-NEXT: .long 0 # BTF_KIND_PTR(id = 7) +; CHECK-NEXT: .long 33554432 # 0x2000000 +; CHECK-NEXT: .long 8 +; CHECK-NEXT: .long 77 # BTF_KIND_STRUCT(id = 8) +; CHECK-NEXT: .long 67108865 # 0x4000001 +; CHECK-NEXT: .long 4 +; CHECK-NEXT: .long 81 +; CHECK-NEXT: .long 9 +; CHECK-NEXT: .long 0 # 0x0 +; CHECK-NEXT: .long 83 # BTF_KIND_INT(id = 9) +; CHECK-NEXT: .long 16777216 # 0x1000000 +; CHECK-NEXT: .long 4 +; CHECK-NEXT: .long 16777248 # 0x1000020 +; CHECK-NEXT: .long 87 # BTF_KIND_FUNC(id = 10) +; CHECK-NEXT: .long 201326594 # 0xc000002 +; CHECK-NEXT: .long 3 +; CHECK-NEXT: .long 92 # BTF_KIND_TYPE_TAG(id = 11) +; CHECK-NEXT: .long 301989888 # 0x12000000 +; CHECK-NEXT: .long 8 +; CHECK-NEXT: .long 97 # BTF_KIND_TYPE_TAG(id = 12) +; CHECK-NEXT: .long 301989888 # 0x12000000 +; CHECK-NEXT: .long 11 + +; CHECK: .ascii "test" # string offset=1 +; CHECK: .ascii "map_value" # string offset=63 +; CHECK: .ascii "ptr" # string offset=73 +; CHECK: .ascii "foo" # string offset=77 +; CHECK: .byte 105 # string offset=81 +; CHECK: .ascii "int" # string offset=83 +; CHECK: .ascii "func" # string offset=87 +; CHECK: .ascii "tag2" # string offset=92 +; CHECK: .ascii "tag1" # string offset=97 + +; Function Attrs: argmemonly mustprogress nofree nosync nounwind willreturn +declare void @llvm.lifetime.start.p0i8(i64 immarg, i8* nocapture) #1 + +; Function Attrs: mustprogress nofree nosync nounwind readnone speculatable willreturn +declare void @llvm.dbg.declare(metadata, metadata, metadata) #2 + +declare !dbg !27 dso_local void @func(%struct.map_value* noundef, %struct.foo* noundef) local_unnamed_addr #3 + +; Function Attrs: argmemonly mustprogress nofree nosync nounwind willreturn +declare void @llvm.lifetime.end.p0i8(i64 immarg, i8* nocapture) #1 + +attributes #0 = { nounwind "frame-pointer"="all" "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" } +attributes #1 = { argmemonly mustprogress nofree nosync nounwind willreturn } +attributes #2 = { mustprogress nofree nosync nounwind readnone speculatable willreturn } +attributes #3 = { "frame-pointer"="all" "no-trapping-math"="true" "stack-protector-buffer-size"="8" } +attributes #4 = { nounwind } + +!llvm.dbg.cu = !{!0} +!llvm.module.flags = !{!2, !3, !4, !5} +!llvm.ident = !{!6} + +!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 15.0.0 (https://github.com/llvm/llvm-project.git 25e8505f515bc9ef6c13527ffc4a902bae3a9071)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, splitDebugInlining: false, nameTableKind: None) +!1 = !DIFile(filename: "test.c", directory: "/tmp//home/yhs/work/tests/llvm/btf_tag_type", checksumkind: CSK_MD5, checksum: "8b3b8281c3b4240403467e0c9461251d") +!2 = !{i32 7, !"Dwarf Version", i32 5} +!3 = !{i32 2, !"Debug Info Version", i32 3} +!4 = !{i32 1, !"wchar_size", i32 4} +!5 = !{i32 7, !"frame-pointer", i32 2} +!6 = !{!"clang version 15.0.0 (https://github.com/llvm/llvm-project.git 25e8505f515bc9ef6c13527ffc4a902bae3a9071)"} +!7 = distinct !DISubprogram(name: "test", scope: !1, file: !1, line: 11, type: !8, scopeLine: 12, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !10) +!8 = !DISubroutineType(types: !9) +!9 = !{null} +!10 = !{!11} +!11 = !DILocalVariable(name: "v", scope: !7, file: !1, line: 13, type: !12) +!12 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "map_value", file: !1, line: 7, size: 64, elements: !13) +!13 = !{!14} +!14 = !DIDerivedType(tag: DW_TAG_member, name: "ptr", scope: !12, file: !1, line: 8, baseType: !15, size: 64) +!15 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !16, size: 64, annotations: !20) +!16 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "foo", file: !1, line: 4, size: 32, elements: !17) +!17 = !{!18} +!18 = !DIDerivedType(tag: DW_TAG_member, name: "i", scope: !16, file: !1, line: 5, baseType: !19, size: 32) +!19 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +!20 = !{!21, !22} +!21 = !{!"btf_type_tag", !"tag2"} +!22 = !{!"btf_type_tag", !"tag1"} +!23 = !DILocation(line: 13, column: 9, scope: !7) +!24 = !DILocation(line: 13, column: 26, scope: !7) +!25 = !DILocation(line: 14, column: 9, scope: !7) +!26 = !DILocation(line: 15, column: 1, scope: !7) +!27 = !DISubprogram(name: "func", scope: !1, file: !1, line: 10, type: !28, flags: DIFlagPrototyped, spFlags: DISPFlagOptimized, retainedNodes: !32) +!28 = !DISubroutineType(types: !29) +!29 = !{null, !30, !31} +!30 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !12, size: 64) +!31 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !16, size: 64) +!32 = !{} diff --git a/llvm/test/CodeGen/SBF/BTF/type-tag-var.ll b/llvm/test/CodeGen/SBF/BTF/type-tag-var.ll new file mode 100644 index 0000000000000..d2d5932bcea2b --- /dev/null +++ b/llvm/test/CodeGen/SBF/BTF/type-tag-var.ll @@ -0,0 +1,62 @@ +; RUN: llc -sbf-enable-btf-emission -march=sbf -filetype=asm -o - %s | FileCheck -check-prefixes=CHECK %s +; +; Source: +; #define __tag1 __attribute__((btf_type_tag("tag1"))) +; #define __tag2 __attribute__((btf_type_tag("tag2"))) +; int __tag1 * __tag1 __tag2 *g; +; Compilation flag: +; clang -target bpf -O2 -g -S -emit-llvm test.c + +@g = dso_local local_unnamed_addr global i32** null, align 8, !dbg !0 + +!llvm.dbg.cu = !{!2} +!llvm.module.flags = !{!12, !13, !14, !15} +!llvm.ident = !{!16} + +!0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression()) +!1 = distinct !DIGlobalVariable(name: "g", scope: !2, file: !3, line: 3, type: !5, isLocal: false, isDefinition: true) +!2 = distinct !DICompileUnit(language: DW_LANG_C99, file: !3, producer: "clang version 14.0.0 (https://github.com/llvm/llvm-project.git 077b2e0cf1e97c4d97ca5ceab3ec0192ed11c66e)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, globals: !4, splitDebugInlining: false, nameTableKind: None) +!3 = !DIFile(filename: "test.c", directory: "/tmp/home/yhs/work/tests/llvm/btf_tag_type") +!4 = !{!0} +!5 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !6, size: 64, annotations: !10) +!6 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !7, size: 64, annotations: !8) +!7 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +!8 = !{!9} +!9 = !{!"btf_type_tag", !"tag1"} +!10 = !{!9, !11} +!11 = !{!"btf_type_tag", !"tag2"} + +; CHECK: .long 1 # BTF_KIND_TYPE_TAG(id = 1) +; CHECK-NEXT: .long 301989888 # 0x12000000 +; CHECK-NEXT: .long 5 +; CHECK-NEXT: .long 6 # BTF_KIND_TYPE_TAG(id = 2) +; CHECK-NEXT: .long 301989888 # 0x12000000 +; CHECK-NEXT: .long 1 +; CHECK-NEXT: .long 0 # BTF_KIND_PTR(id = 3) +; CHECK-NEXT: .long 33554432 # 0x2000000 +; CHECK-NEXT: .long 2 +; CHECK-NEXT: .long 1 # BTF_KIND_TYPE_TAG(id = 4) +; CHECK-NEXT: .long 301989888 # 0x12000000 +; CHECK-NEXT: .long 6 +; CHECK-NEXT: .long 0 # BTF_KIND_PTR(id = 5) +; CHECK-NEXT: .long 33554432 # 0x2000000 +; CHECK-NEXT: .long 4 +; CHECK-NEXT: .long 11 # BTF_KIND_INT(id = 6) +; CHECK-NEXT: .long 16777216 # 0x1000000 +; CHECK-NEXT: .long 4 +; CHECK-NEXT: .long 16777248 # 0x1000020 +; CHECK-NEXT: .long 15 # BTF_KIND_VAR(id = 7) +; CHECK-NEXT: .long 234881024 # 0xe000000 +; CHECK-NEXT: .long 3 +; CHECK-NEXT: .long 1 + +; CHECK: .ascii "tag1" # string offset=1 +; CHECK: .ascii "tag2" # string offset=6 +; CHECK: .ascii "int" # string offset=11 +; CHECK: .byte 103 # string offset=15 + +!12 = !{i32 7, !"Dwarf Version", i32 4} +!13 = !{i32 2, !"Debug Info Version", i32 3} +!14 = !{i32 1, !"wchar_size", i32 4} +!15 = !{i32 7, !"frame-pointer", i32 2} +!16 = !{!"clang version 14.0.0 (https://github.com/llvm/llvm-project.git 077b2e0cf1e97c4d97ca5ceab3ec0192ed11c66e)"} diff --git a/llvm/test/CodeGen/SBF/BTF/uchar.ll b/llvm/test/CodeGen/SBF/BTF/uchar.ll new file mode 100644 index 0000000000000..80543f3715d95 --- /dev/null +++ b/llvm/test/CodeGen/SBF/BTF/uchar.ll @@ -0,0 +1,41 @@ +; RUN: llc -sbf-enable-btf-emission -march=sbf -filetype=asm -o - %s | FileCheck -check-prefixes=CHECK %s + +; Source code: +; unsigned char a; +; Compilation flag: +; clang -target bpf -O2 -g -S -emit-llvm t.c + +@a = common dso_local local_unnamed_addr global i8 0, align 1, !dbg !0 + +!llvm.dbg.cu = !{!2} +!llvm.module.flags = !{!7, !8, !9} +!llvm.ident = !{!10} + +; CHECK: .section .BTF,"",@progbits +; CHECK-NEXT: .short 60319 # 0xeb9f +; CHECK-NEXT: .byte 1 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .long 24 +; CHECK-NEXT: .long 0 +; CHECK-NEXT: .long 16 +; CHECK-NEXT: .long 16 +; CHECK-NEXT: .long 15 +; CHECK-NEXT: .long 1 # BTF_KIND_INT(id = 1) +; CHECK-NEXT: .long 16777216 # 0x1000000 +; CHECK-NEXT: .long 1 +; CHECK-NEXT: .long 8 # 0x8 +; CHECK-NEXT: .byte 0 # string offset=0 +; CHECK-NEXT: .ascii "unsigned char" # string offset=1 +; CHECK-NEXT: .byte 0 + +!0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression()) +!1 = distinct !DIGlobalVariable(name: "a", scope: !2, file: !3, line: 1, type: !6, isLocal: false, isDefinition: true) +!2 = distinct !DICompileUnit(language: DW_LANG_C99, file: !3, producer: "clang version 8.0.0 (trunk 345296) (llvm/trunk 345297)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !4, globals: !5, nameTableKind: None) +!3 = !DIFile(filename: "t.c", directory: "/home/yhs/tmp") +!4 = !{} +!5 = !{!0} +!6 = !DIBasicType(name: "unsigned char", size: 8, encoding: DW_ATE_unsigned_char) +!7 = !{i32 2, !"Dwarf Version", i32 4} +!8 = !{i32 2, !"Debug Info Version", i32 3} +!9 = !{i32 1, !"wchar_size", i32 4} +!10 = !{!"clang version 8.0.0 (trunk 345296) (llvm/trunk 345297)"} diff --git a/llvm/test/CodeGen/SBF/BTF/uint.ll b/llvm/test/CodeGen/SBF/BTF/uint.ll new file mode 100644 index 0000000000000..48419cc4742a8 --- /dev/null +++ b/llvm/test/CodeGen/SBF/BTF/uint.ll @@ -0,0 +1,41 @@ +; RUN: llc -sbf-enable-btf-emission -march=sbf -filetype=asm -o - %s | FileCheck -check-prefixes=CHECK %s + +; Source code: +; unsigned a; +; Compilation flag: +; clang -target bpf -O2 -g -S -emit-llvm t.c + +@a = common dso_local local_unnamed_addr global i32 0, align 4, !dbg !0 + +!llvm.dbg.cu = !{!2} +!llvm.module.flags = !{!7, !8, !9} +!llvm.ident = !{!10} + +; CHECK: .section .BTF,"",@progbits +; CHECK-NEXT: .short 60319 # 0xeb9f +; CHECK-NEXT: .byte 1 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .long 24 +; CHECK-NEXT: .long 0 +; CHECK-NEXT: .long 16 +; CHECK-NEXT: .long 16 +; CHECK-NEXT: .long 14 +; CHECK-NEXT: .long 1 # BTF_KIND_INT(id = 1) +; CHECK-NEXT: .long 16777216 # 0x1000000 +; CHECK-NEXT: .long 4 +; CHECK-NEXT: .long 32 # 0x20 +; CHECK-NEXT: .byte 0 # string offset=0 +; CHECK-NEXT: .ascii "unsigned int" # string offset=1 +; CHECK-NEXT: .byte 0 + +!0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression()) +!1 = distinct !DIGlobalVariable(name: "a", scope: !2, file: !3, line: 1, type: !6, isLocal: false, isDefinition: true) +!2 = distinct !DICompileUnit(language: DW_LANG_C99, file: !3, producer: "clang version 8.0.0 (trunk 344789) (llvm/trunk 344782)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !4, globals: !5, nameTableKind: None) +!3 = !DIFile(filename: "t.c", directory: "/home/yhs/tmp") +!4 = !{} +!5 = !{!0} +!6 = !DIBasicType(name: "unsigned int", size: 32, encoding: DW_ATE_unsigned) +!7 = !{i32 2, !"Dwarf Version", i32 4} +!8 = !{i32 2, !"Debug Info Version", i32 3} +!9 = !{i32 1, !"wchar_size", i32 4} +!10 = !{!"clang version 8.0.0 (trunk 344789) (llvm/trunk 344782)"} diff --git a/llvm/test/CodeGen/SBF/BTF/ulonglong.ll b/llvm/test/CodeGen/SBF/BTF/ulonglong.ll new file mode 100644 index 0000000000000..b631e64f581d4 --- /dev/null +++ b/llvm/test/CodeGen/SBF/BTF/ulonglong.ll @@ -0,0 +1,41 @@ +; RUN: llc -sbf-enable-btf-emission -march=sbf -filetype=asm -o - %s | FileCheck -check-prefixes=CHECK %s + +; Source code: +; unsigned long long a; +; Compilation flag: +; clang -target bpf -O2 -g -S -emit-llvm t.c + +@a = common dso_local local_unnamed_addr global i64 0, align 8, !dbg !0 + +!llvm.dbg.cu = !{!2} +!llvm.module.flags = !{!7, !8, !9} +!llvm.ident = !{!10} + +; CHECK: .section .BTF,"",@progbits +; CHECK-NEXT: .short 60319 # 0xeb9f +; CHECK-NEXT: .byte 1 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .long 24 +; CHECK-NEXT: .long 0 +; CHECK-NEXT: .long 16 +; CHECK-NEXT: .long 16 +; CHECK-NEXT: .long 24 +; CHECK-NEXT: .long 1 # BTF_KIND_INT(id = 1) +; CHECK-NEXT: .long 16777216 # 0x1000000 +; CHECK-NEXT: .long 8 +; CHECK-NEXT: .long 64 # 0x40 +; CHECK-NEXT: .byte 0 # string offset=0 +; CHECK-NEXT: .ascii "long long unsigned int" # string offset=1 +; CHECK-NEXT: .byte 0 + +!0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression()) +!1 = distinct !DIGlobalVariable(name: "a", scope: !2, file: !3, line: 1, type: !6, isLocal: false, isDefinition: true) +!2 = distinct !DICompileUnit(language: DW_LANG_C99, file: !3, producer: "clang version 8.0.0 (trunk 344789) (llvm/trunk 344782)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !4, globals: !5, nameTableKind: None) +!3 = !DIFile(filename: "t.c", directory: "/home/yhs/tmp") +!4 = !{} +!5 = !{!0} +!6 = !DIBasicType(name: "long long unsigned int", size: 64, encoding: DW_ATE_unsigned) +!7 = !{i32 2, !"Dwarf Version", i32 4} +!8 = !{i32 2, !"Debug Info Version", i32 3} +!9 = !{i32 1, !"wchar_size", i32 4} +!10 = !{!"clang version 8.0.0 (trunk 344789) (llvm/trunk 344782)"} diff --git a/llvm/test/CodeGen/SBF/BTF/union-array-typedef.ll b/llvm/test/CodeGen/SBF/BTF/union-array-typedef.ll new file mode 100644 index 0000000000000..1e56731437142 --- /dev/null +++ b/llvm/test/CodeGen/SBF/BTF/union-array-typedef.ll @@ -0,0 +1,91 @@ +; RUN: llc -sbf-enable-btf-emission -march=sbf -filetype=asm -o - %s | FileCheck -check-prefixes=CHECK %s + +; Source code: +; typedef int _int; +; union t {char m[4]; _int n;} a; +; Compilation flag: +; clang -target bpf -O2 -g -S -emit-llvm t.c + +%union.t = type { i32 } + +@a = common dso_local local_unnamed_addr global %union.t zeroinitializer, align 4, !dbg !0 + +!llvm.dbg.cu = !{!2} +!llvm.module.flags = !{!16, !17, !18} +!llvm.ident = !{!19} + +; CHECK: .section .BTF,"",@progbits +; CHECK-NEXT: .short 60319 # 0xeb9f +; CHECK-NEXT: .byte 1 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .long 24 +; CHECK-NEXT: .long 0 +; CHECK-NEXT: .long 120 +; CHECK-NEXT: .long 120 +; CHECK-NEXT: .long 41 +; CHECK-NEXT: .long 1 # BTF_KIND_UNION(id = 1) +; CHECK-NEXT: .long 83886082 # 0x5000002 +; CHECK-NEXT: .long 4 +; CHECK-NEXT: .long 3 +; CHECK-NEXT: .long 3 +; CHECK-NEXT: .long 0 # 0x0 +; CHECK-NEXT: .long 5 +; CHECK-NEXT: .long 5 +; CHECK-NEXT: .long 0 # 0x0 +; CHECK-NEXT: .long 7 # BTF_KIND_INT(id = 2) +; CHECK-NEXT: .long 16777216 # 0x1000000 +; CHECK-NEXT: .long 1 +; CHECK-NEXT: .long 16777224 # 0x1000008 +; CHECK-NEXT: .long 0 # BTF_KIND_ARRAY(id = 3) +; CHECK-NEXT: .long 50331648 # 0x3000000 +; CHECK-NEXT: .long 0 +; CHECK-NEXT: .long 2 +; CHECK-NEXT: .long 4 +; CHECK-NEXT: .long 4 +; CHECK-NEXT: .long 12 # BTF_KIND_INT(id = 4) +; CHECK-NEXT: .long 16777216 # 0x1000000 +; CHECK-NEXT: .long 4 +; CHECK-NEXT: .long 32 # 0x20 +; CHECK-NEXT: .long 32 # BTF_KIND_TYPEDEF(id = 5) +; CHECK-NEXT: .long 134217728 # 0x8000000 +; CHECK-NEXT: .long 6 +; CHECK-NEXT: .long 37 # BTF_KIND_INT(id = 6) +; CHECK-NEXT: .long 16777216 # 0x1000000 +; CHECK-NEXT: .long 4 +; CHECK-NEXT: .long 16777248 # 0x1000020 +; CHECK-NEXT: .byte 0 # string offset=0 +; CHECK-NEXT: .byte 116 # string offset=1 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .byte 109 # string offset=3 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .byte 110 # string offset=5 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii "char" # string offset=7 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii "__ARRAY_SIZE_TYPE__" # string offset=12 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii "_int" # string offset=32 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii "int" # string offset=37 +; CHECK-NEXT: .byte 0 + +!0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression()) +!1 = distinct !DIGlobalVariable(name: "a", scope: !2, file: !3, line: 2, type: !6, isLocal: false, isDefinition: true) +!2 = distinct !DICompileUnit(language: DW_LANG_C99, file: !3, producer: "clang version 8.0.0 (trunk 345296) (llvm/trunk 345297)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !4, globals: !5, nameTableKind: None) +!3 = !DIFile(filename: "t.c", directory: "/home/yhs/tmp") +!4 = !{} +!5 = !{!0} +!6 = distinct !DICompositeType(tag: DW_TAG_union_type, name: "t", file: !3, line: 2, size: 32, elements: !7) +!7 = !{!8, !13} +!8 = !DIDerivedType(tag: DW_TAG_member, name: "m", scope: !6, file: !3, line: 2, baseType: !9, size: 32) +!9 = !DICompositeType(tag: DW_TAG_array_type, baseType: !10, size: 32, elements: !11) +!10 = !DIBasicType(name: "char", size: 8, encoding: DW_ATE_signed_char) +!11 = !{!12} +!12 = !DISubrange(count: 4) +!13 = !DIDerivedType(tag: DW_TAG_member, name: "n", scope: !6, file: !3, line: 2, baseType: !14, size: 32) +!14 = !DIDerivedType(tag: DW_TAG_typedef, name: "_int", file: !3, line: 1, baseType: !15) +!15 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +!16 = !{i32 2, !"Dwarf Version", i32 4} +!17 = !{i32 2, !"Debug Info Version", i32 3} +!18 = !{i32 1, !"wchar_size", i32 4} +!19 = !{!"clang version 8.0.0 (trunk 345296) (llvm/trunk 345297)"} diff --git a/llvm/test/CodeGen/SBF/BTF/ushort.ll b/llvm/test/CodeGen/SBF/BTF/ushort.ll new file mode 100644 index 0000000000000..742c353fcdb15 --- /dev/null +++ b/llvm/test/CodeGen/SBF/BTF/ushort.ll @@ -0,0 +1,41 @@ +; RUN: llc -sbf-enable-btf-emission -march=sbf -filetype=asm -o - %s | FileCheck -check-prefixes=CHECK %s + +; Source code: +; unsigned short a; +; Compilation flag: +; clang -target bpf -O2 -g -S -emit-llvm t.c + +@a = common dso_local local_unnamed_addr global i16 0, align 2, !dbg !0 + +!llvm.dbg.cu = !{!2} +!llvm.module.flags = !{!7, !8, !9} +!llvm.ident = !{!10} + +; CHECK: .section .BTF,"",@progbits +; CHECK-NEXT: .short 60319 # 0xeb9f +; CHECK-NEXT: .byte 1 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .long 24 +; CHECK-NEXT: .long 0 +; CHECK-NEXT: .long 16 +; CHECK-NEXT: .long 16 +; CHECK-NEXT: .long 16 +; CHECK-NEXT: .long 1 # BTF_KIND_INT(id = 1) +; CHECK-NEXT: .long 16777216 # 0x1000000 +; CHECK-NEXT: .long 2 +; CHECK-NEXT: .long 16 # 0x10 +; CHECK-NEXT: .byte 0 # string offset=0 +; CHECK-NEXT: .ascii "unsigned short" # string offset=1 +; CHECK-NEXT: .byte 0 + +!0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression()) +!1 = distinct !DIGlobalVariable(name: "a", scope: !2, file: !3, line: 1, type: !6, isLocal: false, isDefinition: true) +!2 = distinct !DICompileUnit(language: DW_LANG_C99, file: !3, producer: "clang version 8.0.0 (trunk 344789) (llvm/trunk 344782)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !4, globals: !5, nameTableKind: None) +!3 = !DIFile(filename: "t.c", directory: "/home/yhs/tmp") +!4 = !{} +!5 = !{!0} +!6 = !DIBasicType(name: "unsigned short", size: 16, encoding: DW_ATE_unsigned) +!7 = !{i32 2, !"Dwarf Version", i32 4} +!8 = !{i32 2, !"Debug Info Version", i32 3} +!9 = !{i32 1, !"wchar_size", i32 4} +!10 = !{!"clang version 8.0.0 (trunk 344789) (llvm/trunk 344782)"} diff --git a/llvm/test/CodeGen/SBF/BTF/weak-global-2.ll b/llvm/test/CodeGen/SBF/BTF/weak-global-2.ll new file mode 100644 index 0000000000000..38a0b14721a1e --- /dev/null +++ b/llvm/test/CodeGen/SBF/BTF/weak-global-2.ll @@ -0,0 +1,65 @@ +; RUN: llc -sbf-enable-btf-emission -march=sbf -filetype=asm -o - %s | FileCheck -check-prefixes=CHECK %s +; +; Source code: +; char g __attribute__((weak)) = 2; +; int test() { +; return g; +; } +; Compilation flag: +; clang -target bpf -O2 -g -S -emit-llvm test.c + +@g = weak dso_local local_unnamed_addr global i8 2, align 1, !dbg !0 +; Function Attrs: norecurse nounwind readonly +define dso_local i32 @test() local_unnamed_addr #0 !dbg !11 { +entry: + %0 = load i8, i8* @g, align 1, !dbg !15, !tbaa !16 + %conv = sext i8 %0 to i32, !dbg !15 + ret i32 %conv, !dbg !19 +} + +; CHECK: .long 55 # BTF_KIND_INT(id = 4) +; CHECK-NEXT: .long 16777216 # 0x1000000 +; CHECK-NEXT: .long 1 +; CHECK-NEXT: .long 16777224 # 0x1000008 +; CHECK-NEXT: .long 60 # BTF_KIND_VAR(id = 5) +; CHECK-NEXT: .long 234881024 # 0xe000000 +; CHECK-NEXT: .long 4 +; CHECK-NEXT: .long 1 +; CHECK-NEXT: .long 62 # BTF_KIND_DATASEC(id = 6) +; CHECK-NEXT: .long 251658241 # 0xf000001 +; CHECK-NEXT: .long 0 +; CHECK-NEXT: .long 5 +; CHECK-NEXT: .long g +; CHECK-NEXT: .long 1 + +; CHECK: .ascii "char" # string offset=55 +; CHECK: .byte 103 # string offset=60 +; CHECK: .ascii ".data" # string offset=62 + + +attributes #0 = { norecurse nounwind readonly "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" } + +!llvm.dbg.cu = !{!2} +!llvm.module.flags = !{!7, !8, !9} +!llvm.ident = !{!10} + +!0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression()) +!1 = distinct !DIGlobalVariable(name: "g", scope: !2, file: !3, line: 1, type: !6, isLocal: false, isDefinition: true) +!2 = distinct !DICompileUnit(language: DW_LANG_C99, file: !3, producer: "clang version 10.0.0 (https://github.com/llvm/llvm-project.git edf6717d8d30034da932b95350898e03c90a5082)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !4, globals: !5, nameTableKind: None) +!3 = !DIFile(filename: "test.c", directory: "/tmp/home/yhs/work/tests/global") +!4 = !{} +!5 = !{!0} +!6 = !DIBasicType(name: "char", size: 8, encoding: DW_ATE_signed_char) +!7 = !{i32 7, !"Dwarf Version", i32 4} +!8 = !{i32 2, !"Debug Info Version", i32 3} +!9 = !{i32 1, !"wchar_size", i32 4} +!10 = !{!"clang version 10.0.0 (https://github.com/llvm/llvm-project.git edf6717d8d30034da932b95350898e03c90a5082)"} +!11 = distinct !DISubprogram(name: "test", scope: !3, file: !3, line: 2, type: !12, scopeLine: 2, flags: DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !2, retainedNodes: !4) +!12 = !DISubroutineType(types: !13) +!13 = !{!14} +!14 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +!15 = !DILocation(line: 3, column: 10, scope: !11) +!16 = !{!17, !17, i64 0} +!17 = !{!"omnipotent char", !18, i64 0} +!18 = !{!"Simple C/C++ TBAA"} +!19 = !DILocation(line: 3, column: 3, scope: !11) diff --git a/llvm/test/CodeGen/SBF/BTF/weak-global-3.ll b/llvm/test/CodeGen/SBF/BTF/weak-global-3.ll new file mode 100644 index 0000000000000..f072e8cad453e --- /dev/null +++ b/llvm/test/CodeGen/SBF/BTF/weak-global-3.ll @@ -0,0 +1,85 @@ +; RUN: llc -sbf-enable-btf-emission -march=sbf -filetype=asm -o - %s | FileCheck -check-prefixes=CHECK %s +; +; Source code: +; const volatile char g __attribute__((weak)) = 2; +; int test() { +; return g; +; } +; Compilation flag: +; clang -target bpf -O2 -g -S -emit-llvm test.c + +@g = weak_odr dso_local constant i8 2, align 1, !dbg !0 + +; Function Attrs: nofree norecurse nounwind willreturn +define dso_local i32 @test() local_unnamed_addr #0 !dbg !13 { +entry: + %0 = load volatile i8, i8* @g, align 1, !dbg !17, !tbaa !18 + %conv = sext i8 %0 to i32, !dbg !17 + ret i32 %conv, !dbg !21 +} + +; CHECK: .long 0 # BTF_KIND_FUNC_PROTO(id = 1) +; CHECK-NEXT: .long 218103808 # 0xd000000 +; CHECK-NEXT: .long 2 +; CHECK-NEXT: .long 1 # BTF_KIND_INT(id = 2) +; CHECK-NEXT: .long 16777216 # 0x1000000 +; CHECK-NEXT: .long 4 +; CHECK-NEXT: .long 16777248 # 0x1000020 +; CHECK-NEXT: .long 5 # BTF_KIND_FUNC(id = 3) +; CHECK-NEXT: .long 201326593 # 0xc000001 +; CHECK-NEXT: .long 1 +; CHECK-NEXT: .long 0 # BTF_KIND_CONST(id = 4) +; CHECK-NEXT: .long 167772160 # 0xa000000 +; CHECK-NEXT: .long 5 +; CHECK-NEXT: .long 0 # BTF_KIND_VOLATILE(id = 5) +; CHECK-NEXT: .long 150994944 # 0x9000000 +; CHECK-NEXT: .long 6 +; CHECK-NEXT: .long 47 # BTF_KIND_INT(id = 6) +; CHECK-NEXT: .long 16777216 # 0x1000000 +; CHECK-NEXT: .long 1 +; CHECK-NEXT: .long 16777224 # 0x1000008 +; CHECK-NEXT: .long 52 # BTF_KIND_VAR(id = 7) +; CHECK-NEXT: .long 234881024 # 0xe000000 +; CHECK-NEXT: .long 4 +; CHECK-NEXT: .long 1 +; CHECK-NEXT: .long 54 # BTF_KIND_DATASEC(id = 8) +; CHECK-NEXT: .long 251658241 # 0xf000001 +; CHECK-NEXT: .long 0 +; CHECK-NEXT: .long 7 +; CHECK-NEXT: .long g +; CHECK-NEXT: .long 1 + +; CHECK: .ascii "int" # string offset=1 +; CHECK: .ascii "test" # string offset=5 +; CHECK: .ascii "char" # string offset=47 +; CHECK: .byte 103 # string offset=52 +; CHECK: .ascii ".rodata" # string offset=54 + +attributes #0 = { nofree norecurse nounwind willreturn "frame-pointer"="all" "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" } + +!llvm.dbg.cu = !{!2} +!llvm.module.flags = !{!9, !10, !11} +!llvm.ident = !{!12} + +!0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression()) +!1 = distinct !DIGlobalVariable(name: "g", scope: !2, file: !3, line: 1, type: !6, isLocal: false, isDefinition: true) +!2 = distinct !DICompileUnit(language: DW_LANG_C99, file: !3, producer: "clang version 13.0.0 (https://github.com/llvm/llvm-project.git 9cc417cbca1cece0d55fa3d1e15682943a06139e)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !4, globals: !5, splitDebugInlining: false, nameTableKind: None) +!3 = !DIFile(filename: "test.c", directory: "/tmp/home/yhs/btf/tests") +!4 = !{} +!5 = !{!0} +!6 = !DIDerivedType(tag: DW_TAG_const_type, baseType: !7) +!7 = !DIDerivedType(tag: DW_TAG_volatile_type, baseType: !8) +!8 = !DIBasicType(name: "char", size: 8, encoding: DW_ATE_signed_char) +!9 = !{i32 7, !"Dwarf Version", i32 4} +!10 = !{i32 2, !"Debug Info Version", i32 3} +!11 = !{i32 1, !"wchar_size", i32 4} +!12 = !{!"clang version 13.0.0 (https://github.com/llvm/llvm-project.git 9cc417cbca1cece0d55fa3d1e15682943a06139e)"} +!13 = distinct !DISubprogram(name: "test", scope: !3, file: !3, line: 2, type: !14, scopeLine: 2, flags: DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !2, retainedNodes: !4) +!14 = !DISubroutineType(types: !15) +!15 = !{!16} +!16 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +!17 = !DILocation(line: 3, column: 10, scope: !13) +!18 = !{!19, !19, i64 0} +!19 = !{!"omnipotent char", !20, i64 0} +!20 = !{!"Simple C/C++ TBAA"} +!21 = !DILocation(line: 3, column: 3, scope: !13) diff --git a/llvm/test/CodeGen/SBF/BTF/weak-global.ll b/llvm/test/CodeGen/SBF/BTF/weak-global.ll new file mode 100644 index 0000000000000..3116517f31c0b --- /dev/null +++ b/llvm/test/CodeGen/SBF/BTF/weak-global.ll @@ -0,0 +1,64 @@ +; RUN: llc -sbf-enable-btf-emission -march=sbf -filetype=asm -o - %s | FileCheck -check-prefixes=CHECK %s +; +; Source code: +; char g __attribute__((weak)); +; int test() { +; return g; +; } +; Compilation flag: +; clang -target bpf -O2 -g -S -emit-llvm test.c + +@g = weak dso_local local_unnamed_addr global i8 0, align 1, !dbg !0 +; Function Attrs: norecurse nounwind readonly +define dso_local i32 @test() local_unnamed_addr #0 !dbg !11 { +entry: + %0 = load i8, i8* @g, align 1, !dbg !15, !tbaa !16 + %conv = sext i8 %0 to i32, !dbg !15 + ret i32 %conv, !dbg !19 +} + +; CHECK: .long 55 # BTF_KIND_INT(id = 4) +; CHECK-NEXT: .long 16777216 # 0x1000000 +; CHECK-NEXT: .long 1 +; CHECK-NEXT: .long 16777224 # 0x1000008 +; CHECK-NEXT: .long 60 # BTF_KIND_VAR(id = 5) +; CHECK-NEXT: .long 234881024 # 0xe000000 +; CHECK-NEXT: .long 4 +; CHECK-NEXT: .long 1 +; CHECK-NEXT: .long 62 # BTF_KIND_DATASEC(id = 6) +; CHECK-NEXT: .long 251658241 # 0xf000001 +; CHECK-NEXT: .long 0 +; CHECK-NEXT: .long 5 +; CHECK-NEXT: .long g +; CHECK-NEXT: .long 1 + +; CHECK: .ascii "char" # string offset=55 +; CHECK: .byte 103 # string offset=60 +; CHECK: .ascii ".bss" # string offset=62 + +attributes #0 = { norecurse nounwind readonly "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" } + +!llvm.dbg.cu = !{!2} +!llvm.module.flags = !{!7, !8, !9} +!llvm.ident = !{!10} + +!0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression()) +!1 = distinct !DIGlobalVariable(name: "g", scope: !2, file: !3, line: 1, type: !6, isLocal: false, isDefinition: true) +!2 = distinct !DICompileUnit(language: DW_LANG_C99, file: !3, producer: "clang version 10.0.0 (https://github.com/llvm/llvm-project.git edf6717d8d30034da932b95350898e03c90a5082)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !4, globals: !5, nameTableKind: None) +!3 = !DIFile(filename: "test.c", directory: "/tmp/home/yhs/work/tests/global") +!4 = !{} +!5 = !{!0} +!6 = !DIBasicType(name: "char", size: 8, encoding: DW_ATE_signed_char) +!7 = !{i32 7, !"Dwarf Version", i32 4} +!8 = !{i32 2, !"Debug Info Version", i32 3} +!9 = !{i32 1, !"wchar_size", i32 4} +!10 = !{!"clang version 10.0.0 (https://github.com/llvm/llvm-project.git edf6717d8d30034da932b95350898e03c90a5082)"} +!11 = distinct !DISubprogram(name: "test", scope: !3, file: !3, line: 2, type: !12, scopeLine: 2, flags: DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !2, retainedNodes: !4) +!12 = !DISubroutineType(types: !13) +!13 = !{!14} +!14 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +!15 = !DILocation(line: 3, column: 10, scope: !11) +!16 = !{!17, !17, i64 0} +!17 = !{!"omnipotent char", !18, i64 0} +!18 = !{!"Simple C/C++ TBAA"} +!19 = !DILocation(line: 3, column: 3, scope: !11) diff --git a/llvm/test/CodeGen/SBF/CORE/anon-struct-argument-pragma.ll b/llvm/test/CodeGen/SBF/CORE/anon-struct-argument-pragma.ll new file mode 100644 index 0000000000000..3ccbaa1b5688d --- /dev/null +++ b/llvm/test/CodeGen/SBF/CORE/anon-struct-argument-pragma.ll @@ -0,0 +1,100 @@ +; RUN: opt -O2 -mtriple=sbf %s | llvm-dis > %t1 +; RUN: llc -sbf-enable-btf-emission -o - %t1 | FileCheck %s +; +; Source: +; #pragma clang attribute push (__attribute__((preserve_access_index)), apply_to = record) +; typedef struct { +; union { +; void *kernel; +; void *user; +; }; +; unsigned is_kernel : 1; +; } sockptr_t; +; #pragma clang attribute pop +; int test(sockptr_t *arg) { +; return arg->is_kernel; +; } +; Compilation flag: +; clang -target bpf -O2 -S -emit-llvm -g -Xclang -disable-llvm-passes test.c + +%struct.sockptr_t = type { %union.anon, i8 } +%union.anon = type { ptr } + +; Function Attrs: nounwind +define dso_local i32 @test(ptr noundef %arg) #0 !dbg !7 { +entry: + %arg.addr = alloca ptr, align 8 + store ptr %arg, ptr %arg.addr, align 8, !tbaa !25 + call void @llvm.dbg.declare(metadata ptr %arg.addr, metadata !24, metadata !DIExpression()), !dbg !29 + %0 = load ptr, ptr %arg.addr, align 8, !dbg !30, !tbaa !25 + %1 = call ptr @llvm.preserve.struct.access.index.p0.p0(ptr elementtype(%struct.sockptr_t) %0, i32 1, i32 1), !dbg !31, !llvm.preserve.access.index !13 + %bf.load = load i8, ptr %1, align 8, !dbg !31 + %bf.clear = and i8 %bf.load, 1, !dbg !31 + %bf.cast = zext i8 %bf.clear to i32, !dbg !31 + ret i32 %bf.cast, !dbg !32 +} + +; CHECK: .long 1 # BTF_KIND_TYPEDEF(id = 2) +; CHECK-NEXT: .long 134217728 # 0x8000000 +; CHECK-NEXT: .long 3 +; CHECK-NEXT: .long 0 # BTF_KIND_STRUCT(id = 3) + +; CHECK: .ascii "sockptr_t" # string offset=1 +; CHECK: .ascii ".text" # string offset=59 +; CHECK: .ascii "0:1" # string offset=65 + +; CHECK: .long 16 # FieldReloc +; CHECK-NEXT: .long 59 # Field reloc section string offset=59 +; CHECK-NEXT: .long 1 +; CHECK-NEXT: .long .Ltmp[[#]] +; CHECK-NEXT: .long 2 +; CHECK-NEXT: .long 65 +; CHECK-NEXT: .long 0 + +; Function Attrs: nocallback nofree nosync nounwind readnone speculatable willreturn +declare void @llvm.dbg.declare(metadata, metadata, metadata) #1 + +; Function Attrs: nocallback nofree nosync nounwind readnone willreturn +declare ptr @llvm.preserve.struct.access.index.p0.p0(ptr, i32 immarg, i32 immarg) #2 + +attributes #0 = { nounwind "frame-pointer"="all" "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" } +attributes #1 = { nocallback nofree nosync nounwind readnone speculatable willreturn } +attributes #2 = { nocallback nofree nosync nounwind readnone willreturn } + +!llvm.dbg.cu = !{!0} +!llvm.module.flags = !{!2, !3, !4, !5} +!llvm.ident = !{!6} + +!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 15.0.0 (https://github.com/llvm/llvm-project.git d81a8759c969344c1e96992aab30f5b5a9d5ffd3)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, splitDebugInlining: false, nameTableKind: None) +!1 = !DIFile(filename: "test.c", directory: "/tmp/home/yhs/work/test/anon", checksumkind: CSK_MD5, checksum: "7ba33bf2146cc86b1c8396f6d3eace81") +!2 = !{i32 7, !"Dwarf Version", i32 5} +!3 = !{i32 2, !"Debug Info Version", i32 3} +!4 = !{i32 1, !"wchar_size", i32 4} +!5 = !{i32 7, !"frame-pointer", i32 2} +!6 = !{!"clang version 15.0.0 (https://github.com/llvm/llvm-project.git d81a8759c969344c1e96992aab30f5b5a9d5ffd3)"} +!7 = distinct !DISubprogram(name: "test", scope: !1, file: !1, line: 10, type: !8, scopeLine: 10, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !23) +!8 = !DISubroutineType(types: !9) +!9 = !{!10, !11} +!10 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +!11 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !12, size: 64) +!12 = !DIDerivedType(tag: DW_TAG_typedef, name: "sockptr_t", file: !1, line: 8, baseType: !13) +!13 = distinct !DICompositeType(tag: DW_TAG_structure_type, file: !1, line: 2, size: 128, elements: !14) +!14 = !{!15, !21} +!15 = !DIDerivedType(tag: DW_TAG_member, scope: !13, file: !1, line: 3, baseType: !16, size: 64) +!16 = distinct !DICompositeType(tag: DW_TAG_union_type, scope: !13, file: !1, line: 3, size: 64, elements: !17) +!17 = !{!18, !20} +!18 = !DIDerivedType(tag: DW_TAG_member, name: "kernel", scope: !16, file: !1, line: 4, baseType: !19, size: 64) +!19 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: null, size: 64) +!20 = !DIDerivedType(tag: DW_TAG_member, name: "user", scope: !16, file: !1, line: 5, baseType: !19, size: 64) +!21 = !DIDerivedType(tag: DW_TAG_member, name: "is_kernel", scope: !13, file: !1, line: 7, baseType: !22, size: 1, offset: 64, flags: DIFlagBitField, extraData: i64 64) +!22 = !DIBasicType(name: "unsigned int", size: 32, encoding: DW_ATE_unsigned) +!23 = !{!24} +!24 = !DILocalVariable(name: "arg", arg: 1, scope: !7, file: !1, line: 10, type: !11) +!25 = !{!26, !26, i64 0} +!26 = !{!"any pointer", !27, i64 0} +!27 = !{!"omnipotent char", !28, i64 0} +!28 = !{!"Simple C/C++ TBAA"} +!29 = !DILocation(line: 10, column: 21, scope: !7) +!30 = !DILocation(line: 11, column: 10, scope: !7) +!31 = !DILocation(line: 11, column: 15, scope: !7) +!32 = !DILocation(line: 11, column: 3, scope: !7) diff --git a/llvm/test/CodeGen/SBF/CORE/anon-union-localvar-attr.ll b/llvm/test/CodeGen/SBF/CORE/anon-union-localvar-attr.ll new file mode 100644 index 0000000000000..b218747c30458 --- /dev/null +++ b/llvm/test/CodeGen/SBF/CORE/anon-union-localvar-attr.ll @@ -0,0 +1,124 @@ +; RUN: opt -O2 -mtriple=sbf %s | llvm-dis > %t1 +; RUN: llc -sbf-enable-btf-emission -o - %t1 | FileCheck %s +; +; Source: +; typedef union { +; struct { +; void *kernel; +; void *user; +; }; +; unsigned is_kernel : 1; +; } __attribute__((preserve_access_index)) sockptr_t; +; void *foo(void); +; int test() { +; sockptr_t *arg = foo(); +; return __builtin_preserve_field_info(arg->is_kernel, 1); +; } +; Compilation flag: +; clang -target bpf -O2 -S -emit-llvm -g -Xclang -disable-llvm-passes test.c + +%union.sockptr_t = type { %struct.anon } +%struct.anon = type { ptr, ptr } + +; Function Attrs: nounwind +define dso_local i32 @test() #0 !dbg !7 { +entry: + %arg = alloca ptr, align 8 + call void @llvm.lifetime.start.p0(i64 8, ptr %arg) #6, !dbg !25 + call void @llvm.dbg.declare(metadata ptr %arg, metadata !12, metadata !DIExpression()), !dbg !26 + %call = call ptr @foo(), !dbg !27 + store ptr %call, ptr %arg, align 8, !dbg !26, !tbaa !28 + %0 = load ptr, ptr %arg, align 8, !dbg !32, !tbaa !28 + %1 = call ptr @llvm.preserve.struct.access.index.p0.p0(ptr elementtype(%union.sockptr_t) %0, i32 0, i32 1), !dbg !33, !llvm.preserve.access.index !15 + %2 = call i32 @llvm.bpf.preserve.field.info.p0(ptr %1, i64 1), !dbg !34 + call void @llvm.lifetime.end.p0(i64 8, ptr %arg) #6, !dbg !35 + ret i32 %2, !dbg !36 +} + +; CHECK: .long 56 # BTF_KIND_TYPEDEF(id = 7) +; CHECK-NEXT: .long 134217728 # 0x8000000 +; CHECK-NEXT: .long 8 +; CHECK-NEXT: .long 0 # BTF_KIND_UNION(id = 8) + +; CHECK: .ascii ".text" # string offset=10 +; CHECK: .ascii "sockptr_t" # string offset=56 +; CHECK: .ascii "0:1" # string offset=101 + +; CHECK: .long 16 # FieldReloc +; CHECK-NEXT: .long 10 # Field reloc section string offset=10 +; CHECK-NEXT: .long 1 +; CHECK-NEXT: .long .Ltmp[[#]] +; CHECK-NEXT: .long 7 +; CHECK-NEXT: .long 101 +; CHECK-NEXT: .long 1 + +; Function Attrs: argmemonly nocallback nofree nosync nounwind willreturn +declare void @llvm.lifetime.start.p0(i64 immarg, ptr nocapture) #1 + +; Function Attrs: nocallback nofree nosync nounwind readnone speculatable willreturn +declare void @llvm.dbg.declare(metadata, metadata, metadata) #2 + +declare !dbg !37 dso_local ptr @foo() #3 + +; Function Attrs: nocallback nofree nosync nounwind readnone willreturn +declare ptr @llvm.preserve.struct.access.index.p0.p0(ptr, i32 immarg, i32 immarg) #4 + +; Function Attrs: nounwind readnone +declare i32 @llvm.bpf.preserve.field.info.p0(ptr, i64 immarg) #5 + +; Function Attrs: argmemonly nocallback nofree nosync nounwind willreturn +declare void @llvm.lifetime.end.p0(i64 immarg, ptr nocapture) #1 + +attributes #0 = { nounwind "frame-pointer"="all" "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" } +attributes #1 = { argmemonly nocallback nofree nosync nounwind willreturn } +attributes #2 = { nocallback nofree nosync nounwind readnone speculatable willreturn } +attributes #3 = { "frame-pointer"="all" "no-trapping-math"="true" "stack-protector-buffer-size"="8" } +attributes #4 = { nocallback nofree nosync nounwind readnone willreturn } +attributes #5 = { nounwind readnone } +attributes #6 = { nounwind } + +!llvm.dbg.cu = !{!0} +!llvm.module.flags = !{!2, !3, !4, !5} +!llvm.ident = !{!6} + +!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 15.0.0 (https://github.com/llvm/llvm-project.git 8c7d5118961e7ffc0304126ec2122d21e2eb1f79)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, splitDebugInlining: false, nameTableKind: None) +!1 = !DIFile(filename: "test.c", directory: "/tmp/home/yhs/work/test/anon", checksumkind: CSK_MD5, checksum: "03904da5c5e53b14bb1effb6d9d5e025") +!2 = !{i32 7, !"Dwarf Version", i32 5} +!3 = !{i32 2, !"Debug Info Version", i32 3} +!4 = !{i32 1, !"wchar_size", i32 4} +!5 = !{i32 7, !"frame-pointer", i32 2} +!6 = !{!"clang version 15.0.0 (https://github.com/llvm/llvm-project.git 8c7d5118961e7ffc0304126ec2122d21e2eb1f79)"} +!7 = distinct !DISubprogram(name: "test", scope: !1, file: !1, line: 9, type: !8, scopeLine: 9, flags: DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !11) +!8 = !DISubroutineType(types: !9) +!9 = !{!10} +!10 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +!11 = !{!12} +!12 = !DILocalVariable(name: "arg", scope: !7, file: !1, line: 10, type: !13) +!13 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !14, size: 64) +!14 = !DIDerivedType(tag: DW_TAG_typedef, name: "sockptr_t", file: !1, line: 7, baseType: !15) +!15 = distinct !DICompositeType(tag: DW_TAG_union_type, file: !1, line: 1, size: 128, elements: !16) +!16 = !{!17, !23} +!17 = !DIDerivedType(tag: DW_TAG_member, scope: !15, file: !1, line: 2, baseType: !18, size: 128) +!18 = distinct !DICompositeType(tag: DW_TAG_structure_type, scope: !15, file: !1, line: 2, size: 128, elements: !19) +!19 = !{!20, !22} +!20 = !DIDerivedType(tag: DW_TAG_member, name: "kernel", scope: !18, file: !1, line: 3, baseType: !21, size: 64) +!21 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: null, size: 64) +!22 = !DIDerivedType(tag: DW_TAG_member, name: "user", scope: !18, file: !1, line: 4, baseType: !21, size: 64, offset: 64) +!23 = !DIDerivedType(tag: DW_TAG_member, name: "is_kernel", scope: !15, file: !1, line: 6, baseType: !24, size: 1, flags: DIFlagBitField, extraData: i64 0) +!24 = !DIBasicType(name: "unsigned int", size: 32, encoding: DW_ATE_unsigned) +!25 = !DILocation(line: 10, column: 3, scope: !7) +!26 = !DILocation(line: 10, column: 14, scope: !7) +!27 = !DILocation(line: 10, column: 20, scope: !7) +!28 = !{!29, !29, i64 0} +!29 = !{!"any pointer", !30, i64 0} +!30 = !{!"omnipotent char", !31, i64 0} +!31 = !{!"Simple C/C++ TBAA"} +!32 = !DILocation(line: 11, column: 40, scope: !7) +!33 = !DILocation(line: 11, column: 45, scope: !7) +!34 = !DILocation(line: 11, column: 10, scope: !7) +!35 = !DILocation(line: 12, column: 1, scope: !7) +!36 = !DILocation(line: 11, column: 3, scope: !7) +!37 = !DISubprogram(name: "foo", scope: !1, file: !1, line: 8, type: !38, flags: DIFlagPrototyped, spFlags: DISPFlagOptimized, retainedNodes: !40) +!38 = !DISubroutineType(types: !39) +!39 = !{!21} +!40 = !{} diff --git a/llvm/test/CodeGen/SBF/CORE/anon-union-localvar-pragma.ll b/llvm/test/CodeGen/SBF/CORE/anon-union-localvar-pragma.ll new file mode 100644 index 0000000000000..9c6663bf8ce06 --- /dev/null +++ b/llvm/test/CodeGen/SBF/CORE/anon-union-localvar-pragma.ll @@ -0,0 +1,127 @@ +; RUN: opt -O2 -mtriple=sbf %s | llvm-dis > %t1 +; RUN: llc -sbf-enable-btf-emission -o - %t1 | FileCheck %s +; +; Source: +; #pragma clang attribute push (__attribute__((preserve_access_index)), apply_to = record) +; typedef union { +; struct { +; void *kernel; +; void *user; +; }; +; unsigned is_kernel : 1; +; } sockptr_t; +; #pragma clang attribute pop +; void *foo(void); +; int test() { +; sockptr_t *arg = foo(); +; return __builtin_preserve_field_info(arg->is_kernel, 1); +; } +; Compilation flag: +; clang -target bpf -O2 -S -emit-llvm -g -Xclang -disable-llvm-passes test.c + +%union.sockptr_t = type { %struct.anon } +%struct.anon = type { ptr, ptr } + +; Function Attrs: nounwind +define dso_local i32 @test() #0 !dbg !7 { +entry: + %arg = alloca ptr, align 8 + call void @llvm.lifetime.start.p0(i64 8, ptr %arg) #6, !dbg !25 + call void @llvm.dbg.declare(metadata ptr %arg, metadata !12, metadata !DIExpression()), !dbg !26 + %call = call ptr @foo(), !dbg !27 + store ptr %call, ptr %arg, align 8, !dbg !26, !tbaa !28 + %0 = load ptr, ptr %arg, align 8, !dbg !32, !tbaa !28 + %1 = call ptr @llvm.preserve.struct.access.index.p0.p0(ptr elementtype(%union.sockptr_t) %0, i32 0, i32 1), !dbg !33, !llvm.preserve.access.index !15 + %2 = call i32 @llvm.bpf.preserve.field.info.p0(ptr %1, i64 1), !dbg !34 + call void @llvm.lifetime.end.p0(i64 8, ptr %arg) #6, !dbg !35 + ret i32 %2, !dbg !36 +} + +; CHECK: .long 56 # BTF_KIND_TYPEDEF(id = 7) +; CHECK-NEXT: .long 134217728 # 0x8000000 +; CHECK-NEXT: .long 8 +; CHECK-NEXT: .long 0 # BTF_KIND_UNION(id = 8) + +; CHECK: .ascii ".text" # string offset=10 +; CHECK: .ascii "sockptr_t" # string offset=56 +; CHECK: .ascii "0:1" # string offset=101 + + +; CHECK: .long 16 # FieldReloc +; CHECK-NEXT: .long 10 # Field reloc section string offset=10 +; CHECK-NEXT: .long 1 +; CHECK-NEXT: .long .Ltmp[[#]] +; CHECK-NEXT: .long 7 +; CHECK-NEXT: .long 101 +; CHECK-NEXT: .long 1 + +; Function Attrs: argmemonly nocallback nofree nosync nounwind willreturn +declare void @llvm.lifetime.start.p0(i64 immarg, ptr nocapture) #1 + +; Function Attrs: nocallback nofree nosync nounwind readnone speculatable willreturn +declare void @llvm.dbg.declare(metadata, metadata, metadata) #2 + +declare !dbg !37 dso_local ptr @foo() #3 + +; Function Attrs: nocallback nofree nosync nounwind readnone willreturn +declare ptr @llvm.preserve.struct.access.index.p0.p0(ptr, i32 immarg, i32 immarg) #4 + +; Function Attrs: nounwind readnone +declare i32 @llvm.bpf.preserve.field.info.p0(ptr, i64 immarg) #5 + +; Function Attrs: argmemonly nocallback nofree nosync nounwind willreturn +declare void @llvm.lifetime.end.p0(i64 immarg, ptr nocapture) #1 + +attributes #0 = { nounwind "frame-pointer"="all" "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" } +attributes #1 = { argmemonly nocallback nofree nosync nounwind willreturn } +attributes #2 = { nocallback nofree nosync nounwind readnone speculatable willreturn } +attributes #3 = { "frame-pointer"="all" "no-trapping-math"="true" "stack-protector-buffer-size"="8" } +attributes #4 = { nocallback nofree nosync nounwind readnone willreturn } +attributes #5 = { nounwind readnone } +attributes #6 = { nounwind } + +!llvm.dbg.cu = !{!0} +!llvm.module.flags = !{!2, !3, !4, !5} +!llvm.ident = !{!6} + +!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 15.0.0 (https://github.com/llvm/llvm-project.git 8c7d5118961e7ffc0304126ec2122d21e2eb1f79)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, splitDebugInlining: false, nameTableKind: None) +!1 = !DIFile(filename: "test.c", directory: "/tmp/home/yhs/work/test/anon", checksumkind: CSK_MD5, checksum: "2c5f698241a8b5ddf345a5743dfca258") +!2 = !{i32 7, !"Dwarf Version", i32 5} +!3 = !{i32 2, !"Debug Info Version", i32 3} +!4 = !{i32 1, !"wchar_size", i32 4} +!5 = !{i32 7, !"frame-pointer", i32 2} +!6 = !{!"clang version 15.0.0 (https://github.com/llvm/llvm-project.git 8c7d5118961e7ffc0304126ec2122d21e2eb1f79)"} +!7 = distinct !DISubprogram(name: "test", scope: !1, file: !1, line: 11, type: !8, scopeLine: 11, flags: DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !11) +!8 = !DISubroutineType(types: !9) +!9 = !{!10} +!10 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +!11 = !{!12} +!12 = !DILocalVariable(name: "arg", scope: !7, file: !1, line: 12, type: !13) +!13 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !14, size: 64) +!14 = !DIDerivedType(tag: DW_TAG_typedef, name: "sockptr_t", file: !1, line: 8, baseType: !15) +!15 = distinct !DICompositeType(tag: DW_TAG_union_type, file: !1, line: 2, size: 128, elements: !16) +!16 = !{!17, !23} +!17 = !DIDerivedType(tag: DW_TAG_member, scope: !15, file: !1, line: 3, baseType: !18, size: 128) +!18 = distinct !DICompositeType(tag: DW_TAG_structure_type, scope: !15, file: !1, line: 3, size: 128, elements: !19) +!19 = !{!20, !22} +!20 = !DIDerivedType(tag: DW_TAG_member, name: "kernel", scope: !18, file: !1, line: 4, baseType: !21, size: 64) +!21 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: null, size: 64) +!22 = !DIDerivedType(tag: DW_TAG_member, name: "user", scope: !18, file: !1, line: 5, baseType: !21, size: 64, offset: 64) +!23 = !DIDerivedType(tag: DW_TAG_member, name: "is_kernel", scope: !15, file: !1, line: 7, baseType: !24, size: 1, flags: DIFlagBitField, extraData: i64 0) +!24 = !DIBasicType(name: "unsigned int", size: 32, encoding: DW_ATE_unsigned) +!25 = !DILocation(line: 12, column: 3, scope: !7) +!26 = !DILocation(line: 12, column: 14, scope: !7) +!27 = !DILocation(line: 12, column: 20, scope: !7) +!28 = !{!29, !29, i64 0} +!29 = !{!"any pointer", !30, i64 0} +!30 = !{!"omnipotent char", !31, i64 0} +!31 = !{!"Simple C/C++ TBAA"} +!32 = !DILocation(line: 13, column: 40, scope: !7) +!33 = !DILocation(line: 13, column: 45, scope: !7) +!34 = !DILocation(line: 13, column: 10, scope: !7) +!35 = !DILocation(line: 14, column: 1, scope: !7) +!36 = !DILocation(line: 13, column: 3, scope: !7) +!37 = !DISubprogram(name: "foo", scope: !1, file: !1, line: 10, type: !38, flags: DIFlagPrototyped, spFlags: DISPFlagOptimized, retainedNodes: !40) +!38 = !DISubroutineType(types: !39) +!39 = !{!21} +!40 = !{} diff --git a/llvm/test/CodeGen/SBF/CORE/btf-id-duplicate.ll b/llvm/test/CodeGen/SBF/CORE/btf-id-duplicate.ll new file mode 100644 index 0000000000000..c45449929e31d --- /dev/null +++ b/llvm/test/CodeGen/SBF/CORE/btf-id-duplicate.ll @@ -0,0 +1,99 @@ +; RUN: opt -O2 -mtriple=sbf %s | llvm-dis > %t1 +; RUN: llc -sbf-enable-btf-emission -o - %t1 | FileCheck %s +; RUN: opt -passes='default' -mtriple=sbf %s | llvm-dis > %t1 +; RUN: llc -sbf-enable-btf-emission -o - %t1 | FileCheck %s +; +; Source: +; struct s1 { int a; int b; }; +; int foo(struct s1 *arg) { return __builtin_btf_type_id(*arg, 0); } +; int bar(struct s1 *arg) { return __builtin_btf_type_id(*arg, 0); } +; Compilation flag: +; clang -target bpf -O2 -S -emit-llvm -g -Xclang -disable-llvm-passes test.c + +%struct.s1 = type { i32, i32 } + +; Function Attrs: nounwind +define dso_local i32 @foo(%struct.s1* %arg) #0 !dbg !7 { +entry: + %arg.addr = alloca %struct.s1*, align 8 + store %struct.s1* %arg, %struct.s1** %arg.addr, align 8, !tbaa !18 + call void @llvm.dbg.declare(metadata %struct.s1** %arg.addr, metadata !17, metadata !DIExpression()), !dbg !22 + %0 = call i64 @llvm.bpf.btf.type.id(i32 0, i64 0), !dbg !23, !llvm.preserve.access.index !12 + %conv = trunc i64 %0 to i32, !dbg !23 + ret i32 %conv, !dbg !24 +} + +; Function Attrs: nofree nosync nounwind readnone speculatable willreturn +declare void @llvm.dbg.declare(metadata, metadata, metadata) #1 + +; Function Attrs: nounwind readnone +declare i64 @llvm.bpf.btf.type.id(i32, i64) #2 + +; Function Attrs: nounwind +define dso_local i32 @bar(%struct.s1* %arg) #0 !dbg !25 { +entry: + %arg.addr = alloca %struct.s1*, align 8 + store %struct.s1* %arg, %struct.s1** %arg.addr, align 8, !tbaa !18 + call void @llvm.dbg.declare(metadata %struct.s1** %arg.addr, metadata !27, metadata !DIExpression()), !dbg !28 + %0 = call i64 @llvm.bpf.btf.type.id(i32 1, i64 0), !dbg !29, !llvm.preserve.access.index !12 + %conv = trunc i64 %0 to i32, !dbg !29 + ret i32 %conv, !dbg !30 +} + +; CHECK: .long 1 # BTF_KIND_STRUCT(id = 2) + +; CHECK: .ascii "s1" # string offset=1 +; CHECK: .ascii ".text" # string offset=20 +; CHECK: .byte 48 # string offset=26 + +; CHECK: .long 16 # FieldReloc +; CHECK-NEXT: .long 20 # Field reloc section string offset=20 +; CHECK-NEXT: .long 2 +; CHECK-NEXT: .long .Ltmp{{[0-9]+}} +; CHECK-NEXT: .long 2 +; CHECK-NEXT: .long 26 +; CHECK-NEXT: .long 6 +; CHECK-NEXT: .long .Ltmp{{[0-9]+}} +; CHECK-NEXT: .long 2 +; CHECK-NEXT: .long 26 +; CHECK-NEXT: .long 6 + +attributes #0 = { nounwind "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" } +attributes #1 = { nofree nosync nounwind readnone speculatable willreturn } +attributes #2 = { nounwind readnone } + +!llvm.dbg.cu = !{!0} +!llvm.module.flags = !{!3, !4, !5} +!llvm.ident = !{!6} + +!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 12.0.0 (https://github.com/llvm/llvm-project.git c1c153c3c70641a23c4a9540a897ff2d4eb4c5b2)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, splitDebugInlining: false, nameTableKind: None) +!1 = !DIFile(filename: "test.c", directory: "/home/yhs/work/tests/dup") +!2 = !{} +!3 = !{i32 7, !"Dwarf Version", i32 4} +!4 = !{i32 2, !"Debug Info Version", i32 3} +!5 = !{i32 1, !"wchar_size", i32 4} +!6 = !{!"clang version 12.0.0 (https://github.com/llvm/llvm-project.git c1c153c3c70641a23c4a9540a897ff2d4eb4c5b2)"} +!7 = distinct !DISubprogram(name: "foo", scope: !1, file: !1, line: 2, type: !8, scopeLine: 2, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !16) +!8 = !DISubroutineType(types: !9) +!9 = !{!10, !11} +!10 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +!11 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !12, size: 64) +!12 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "s1", file: !1, line: 1, size: 64, elements: !13) +!13 = !{!14, !15} +!14 = !DIDerivedType(tag: DW_TAG_member, name: "a", scope: !12, file: !1, line: 1, baseType: !10, size: 32) +!15 = !DIDerivedType(tag: DW_TAG_member, name: "b", scope: !12, file: !1, line: 1, baseType: !10, size: 32, offset: 32) +!16 = !{!17} +!17 = !DILocalVariable(name: "arg", arg: 1, scope: !7, file: !1, line: 2, type: !11) +!18 = !{!19, !19, i64 0} +!19 = !{!"any pointer", !20, i64 0} +!20 = !{!"omnipotent char", !21, i64 0} +!21 = !{!"Simple C/C++ TBAA"} +!22 = !DILocation(line: 2, column: 20, scope: !7) +!23 = !DILocation(line: 2, column: 34, scope: !7) +!24 = !DILocation(line: 2, column: 27, scope: !7) +!25 = distinct !DISubprogram(name: "bar", scope: !1, file: !1, line: 3, type: !8, scopeLine: 3, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !26) +!26 = !{!27} +!27 = !DILocalVariable(name: "arg", arg: 1, scope: !25, file: !1, line: 3, type: !11) +!28 = !DILocation(line: 3, column: 20, scope: !25) +!29 = !DILocation(line: 3, column: 34, scope: !25) +!30 = !DILocation(line: 3, column: 27, scope: !25) diff --git a/llvm/test/CodeGen/SBF/CORE/field-reloc-alu32.ll b/llvm/test/CodeGen/SBF/CORE/field-reloc-alu32.ll new file mode 100644 index 0000000000000..c39a7678dd04a --- /dev/null +++ b/llvm/test/CodeGen/SBF/CORE/field-reloc-alu32.ll @@ -0,0 +1,75 @@ +; RUN: opt -O2 %s | llvm-dis > %t1 +; RUN: llc -sbf-enable-btf-emission -mattr=+alu32 -filetype=asm -o - %t1 | FileCheck -check-prefixes=CHECK %s +; Source code: +; struct b { int d; int e; } c; +; int f() { +; return __builtin_preserve_field_info(c.e, 0); +; } +; Compilation flag: +; clang -target bpf -O2 -g -S -emit-llvm -Xclang -disable-llvm-passes test.c + +target triple = "sbf" + +%struct.b = type { i32, i32 } + +@c = common dso_local global %struct.b zeroinitializer, align 4, !dbg !0 + +; Function Attrs: nounwind readnone +define dso_local i32 @f() local_unnamed_addr #0 !dbg !15 { +entry: + %0 = tail call i32* @llvm.preserve.struct.access.index.p0i32.p0s_struct.bs(%struct.b* elementtype(%struct.b) nonnull @c, i32 1, i32 1), !dbg !18, !llvm.preserve.access.index !6 + %1 = tail call i32 @llvm.bpf.preserve.field.info.p0i32(i32* %0, i64 0), !dbg !19 + ret i32 %1, !dbg !20 +} + +; CHECK: mov64 r0, 4 +; CHECK: exit + +; CHECK: .long 13 # BTF_KIND_STRUCT(id = 4) + +; CHECK: .ascii ".text" # string offset=7 +; CHECK: .byte 98 # string offset=13 +; CHECK: .ascii "0:1" # string offset=19 + +; CHECK: .long 16 # FieldReloc +; CHECK-NEXT: .long 7 # Field reloc section string offset=7 +; CHECK-NEXT: .long 1 +; CHECK-NEXT: .long .Ltmp{{[0-9]+}} +; CHECK-NEXT: .long 4 +; CHECK-NEXT: .long 19 +; CHECK-NEXT: .long 0 + +; Function Attrs: nounwind readnone +declare i32* @llvm.preserve.struct.access.index.p0i32.p0s_struct.bs(%struct.b*, i32, i32) #1 + +; Function Attrs: nounwind readnone +declare i32 @llvm.bpf.preserve.field.info.p0i32(i32*, i64) #1 + +attributes #0 = { nounwind readnone "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" } +attributes #1 = { nounwind readnone } + +!llvm.dbg.cu = !{!2} +!llvm.module.flags = !{!11, !12, !13} +!llvm.ident = !{!14} + +!0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression()) +!1 = distinct !DIGlobalVariable(name: "c", scope: !2, file: !3, line: 1, type: !6, isLocal: false, isDefinition: true) +!2 = distinct !DICompileUnit(language: DW_LANG_C99, file: !3, producer: "clang version 10.0.0 (https://github.com/llvm/llvm-project.git d5509db439a1bb3f0822c42398c8b5921a665478)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !4, globals: !5, nameTableKind: None) +!3 = !DIFile(filename: "test.c", directory: "/tmp/home/yhs/work/tests/core") +!4 = !{} +!5 = !{!0} +!6 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "b", file: !3, line: 1, size: 64, elements: !7) +!7 = !{!8, !10} +!8 = !DIDerivedType(tag: DW_TAG_member, name: "d", scope: !6, file: !3, line: 1, baseType: !9, size: 32) +!9 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +!10 = !DIDerivedType(tag: DW_TAG_member, name: "e", scope: !6, file: !3, line: 1, baseType: !9, size: 32, offset: 32) +!11 = !{i32 2, !"Dwarf Version", i32 4} +!12 = !{i32 2, !"Debug Info Version", i32 3} +!13 = !{i32 1, !"wchar_size", i32 4} +!14 = !{!"clang version 10.0.0 (https://github.com/llvm/llvm-project.git d5509db439a1bb3f0822c42398c8b5921a665478)"} +!15 = distinct !DISubprogram(name: "f", scope: !3, file: !3, line: 2, type: !16, scopeLine: 2, isDefinition: true, isOptimized: true, unit: !2, retainedNodes: !4) +!16 = !DISubroutineType(types: !17) +!17 = !{!9} +!18 = !DILocation(line: 3, column: 42, scope: !15) +!19 = !DILocation(line: 3, column: 10, scope: !15) +!20 = !DILocation(line: 3, column: 3, scope: !15) diff --git a/llvm/test/CodeGen/SBF/CORE/field-reloc-bitfield-1.ll b/llvm/test/CodeGen/SBF/CORE/field-reloc-bitfield-1.ll new file mode 100644 index 0000000000000..5d4d12d25353c --- /dev/null +++ b/llvm/test/CodeGen/SBF/CORE/field-reloc-bitfield-1.ll @@ -0,0 +1,126 @@ +; RUN: opt -O2 %s | llvm-dis > %t1 +; RUN: llc -sbf-enable-btf-emission -filetype=asm -o - %t1 | FileCheck -check-prefixes=CHECK,CHECK-EL,CHECK-ALU64 %s +; RUN: llc -sbf-enable-btf-emission -mattr=+alu32 -filetype=asm -o - %t1 | FileCheck -check-prefixes=CHECK,CHECK-EL,CHECK-ALU32 %s +; Source code: +; struct s { +; unsigned long long f1; +; unsigned f2; +; unsigned f3; +; unsigned f4; +; unsigned char f5; +; unsigned bf1:5, +; bf2:1; +; }; +; enum {FIELD_TYPE_OFFSET = 0, FIELD_TYPE_SIZE = 1, FIELD_TYPE_LSHIFT_U64 = 4,}; +; int test(struct s *arg) { +; return __builtin_preserve_field_info(arg->bf2, FIELD_TYPE_OFFSET) + +; __builtin_preserve_field_info(arg->bf2, FIELD_TYPE_SIZE) + +; __builtin_preserve_field_info(arg->bf2, FIELD_TYPE_LSHIFT_U64); +; } +; Compilation flag: +; clang -target bpfel -O2 -g -S -emit-llvm -Xclang -disable-llvm-passes test.c + +target triple = "sbf" + +%struct.s = type { i64, i32, i32, i32, i8, i8 } + +; Function Attrs: nounwind readnone +define dso_local i32 @test(%struct.s* %arg) local_unnamed_addr #0 !dbg !13 { +entry: + call void @llvm.dbg.value(metadata %struct.s* %arg, metadata !30, metadata !DIExpression()), !dbg !31 + %0 = tail call i8* @llvm.preserve.struct.access.index.p0i8.p0s_struct.ss(%struct.s* elementtype(%struct.s) %arg, i32 5, i32 6), !dbg !32, !llvm.preserve.access.index !18 + %1 = tail call i32 @llvm.bpf.preserve.field.info.p0i8(i8* %0, i64 0), !dbg !33 + %2 = tail call i32 @llvm.bpf.preserve.field.info.p0i8(i8* %0, i64 1), !dbg !34 + %add = add i32 %2, %1, !dbg !35 + %3 = tail call i32 @llvm.bpf.preserve.field.info.p0i8(i8* %0, i64 4), !dbg !36 + %add1 = add i32 %add, %3, !dbg !37 + ret i32 %add1, !dbg !38 +} + +; CHECK: mov64 r1, 16 +; CHECK: mov64 r0, 8 +; CHECK-ALU64: add64 r0, r1 +; CHECK-ALU32: add32 w0, w1 +; CHECK-EL: mov64 r1, 18 +; CHECK-ALU64: add64 r0, r1 +; CHECK-ALU32: add32 w0, w1 +; CHECK: exit + +; CHECK: .long 1 # BTF_KIND_STRUCT(id = 2) + +; CHECK: .byte 115 # string offset=1 +; CHECK: .ascii ".text" # string offset=89 +; CHECK: .ascii "0:6" # string offset=95 + +; CHECK: .long 16 # FieldReloc +; CHECK-NEXT: .long 89 # Field reloc section string offset=89 +; CHECK-NEXT: .long 3 +; CHECK-NEXT: .long .Ltmp{{[0-9]+}} +; CHECK-NEXT: .long 2 +; CHECK-NEXT: .long 95 +; CHECK-NEXT: .long 0 +; CHECK-NEXT: .long .Ltmp{{[0-9]+}} +; CHECK-NEXT: .long 2 +; CHECK-NEXT: .long 95 +; CHECK-NEXT: .long 1 +; CHECK-NEXT: .long .Ltmp{{[0-9]+}} +; CHECK-NEXT: .long 2 +; CHECK-NEXT: .long 95 +; CHECK-NEXT: .long 4 + +; Function Attrs: nounwind readnone +declare i8* @llvm.preserve.struct.access.index.p0i8.p0s_struct.ss(%struct.s*, i32, i32) #1 + +; Function Attrs: nounwind readnone +declare i32 @llvm.bpf.preserve.field.info.p0i8(i8*, i64) #1 + +; Function Attrs: nounwind readnone speculatable +declare void @llvm.dbg.value(metadata, metadata, metadata) #2 + +attributes #0 = { nounwind readnone "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" } +attributes #1 = { nounwind readnone } +attributes #2 = { nounwind readnone speculatable } + +!llvm.dbg.cu = !{!0} +!llvm.module.flags = !{!9, !10, !11} +!llvm.ident = !{!12} + +!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 10.0.0 (https://github.com/llvm/llvm-project.git bc6913e314806882e2b537b5b03996800078d2ad)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, nameTableKind: None) +!1 = !DIFile(filename: "test.c", directory: "/tmp/home/yhs/work/tests/core") +!2 = !{!3} +!3 = !DICompositeType(tag: DW_TAG_enumeration_type, file: !1, line: 10, baseType: !4, size: 32, elements: !5) +!4 = !DIBasicType(name: "unsigned int", size: 32, encoding: DW_ATE_unsigned) +!5 = !{!6, !7, !8} +!6 = !DIEnumerator(name: "FIELD_TYPE_OFFSET", value: 0, isUnsigned: true) +!7 = !DIEnumerator(name: "FIELD_TYPE_SIZE", value: 1, isUnsigned: true) +!8 = !DIEnumerator(name: "FIELD_TYPE_LSHIFT_U64", value: 4, isUnsigned: true) +!9 = !{i32 2, !"Dwarf Version", i32 4} +!10 = !{i32 2, !"Debug Info Version", i32 3} +!11 = !{i32 1, !"wchar_size", i32 4} +!12 = !{!"clang version 10.0.0 (https://github.com/llvm/llvm-project.git bc6913e314806882e2b537b5b03996800078d2ad)"} +!13 = distinct !DISubprogram(name: "test", scope: !1, file: !1, line: 11, type: !14, scopeLine: 11, flags: DIFlagPrototyped, isDefinition: true, isOptimized: true, unit: !0, retainedNodes: !29) +!14 = !DISubroutineType(types: !15) +!15 = !{!16, !17} +!16 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +!17 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !18, size: 64) +!18 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "s", file: !1, line: 1, size: 192, elements: !19) +!19 = !{!20, !22, !23, !24, !25, !27, !28} +!20 = !DIDerivedType(tag: DW_TAG_member, name: "f1", scope: !18, file: !1, line: 2, baseType: !21, size: 64) +!21 = !DIBasicType(name: "long long unsigned int", size: 64, encoding: DW_ATE_unsigned) +!22 = !DIDerivedType(tag: DW_TAG_member, name: "f2", scope: !18, file: !1, line: 3, baseType: !4, size: 32, offset: 64) +!23 = !DIDerivedType(tag: DW_TAG_member, name: "f3", scope: !18, file: !1, line: 4, baseType: !4, size: 32, offset: 96) +!24 = !DIDerivedType(tag: DW_TAG_member, name: "f4", scope: !18, file: !1, line: 5, baseType: !4, size: 32, offset: 128) +!25 = !DIDerivedType(tag: DW_TAG_member, name: "f5", scope: !18, file: !1, line: 6, baseType: !26, size: 8, offset: 160) +!26 = !DIBasicType(name: "unsigned char", size: 8, encoding: DW_ATE_unsigned_char) +!27 = !DIDerivedType(tag: DW_TAG_member, name: "bf1", scope: !18, file: !1, line: 7, baseType: !4, size: 5, offset: 168, flags: DIFlagBitField, extraData: i64 168) +!28 = !DIDerivedType(tag: DW_TAG_member, name: "bf2", scope: !18, file: !1, line: 8, baseType: !4, size: 1, offset: 173, flags: DIFlagBitField, extraData: i64 168) +!29 = !{!30} +!30 = !DILocalVariable(name: "arg", arg: 1, scope: !13, file: !1, line: 11, type: !17) +!31 = !DILocation(line: 0, scope: !13) +!32 = !DILocation(line: 12, column: 45, scope: !13) +!33 = !DILocation(line: 12, column: 10, scope: !13) +!34 = !DILocation(line: 13, column: 10, scope: !13) +!35 = !DILocation(line: 12, column: 69, scope: !13) +!36 = !DILocation(line: 14, column: 10, scope: !13) +!37 = !DILocation(line: 13, column: 67, scope: !13) +!38 = !DILocation(line: 12, column: 3, scope: !13) diff --git a/llvm/test/CodeGen/SBF/CORE/field-reloc-bitfield-2.ll b/llvm/test/CodeGen/SBF/CORE/field-reloc-bitfield-2.ll new file mode 100644 index 0000000000000..78354493464a4 --- /dev/null +++ b/llvm/test/CodeGen/SBF/CORE/field-reloc-bitfield-2.ll @@ -0,0 +1,124 @@ +; RUN: opt -O2 %s | llvm-dis > %t1 +; RUN: llc -sbf-enable-btf-emission -filetype=asm -o - %t1 | FileCheck -check-prefixes=CHECK,CHECK-EL,CHECK-ALU64 %s +; RUN: llc -sbf-enable-btf-emission -mattr=+alu32 -filetype=asm -o - %t1 | FileCheck -check-prefixes=CHECK,CHECK-EL,CHECK-ALU32 %s +; Source code: +; struct s { +; char f1; +; char bf1:6, +; bf2:2, +; bf3:5, +; bf4:3; +; }; +; enum {FIELD_TYPE_OFFSET = 0, FIELD_TYPE_SIZE = 1, FIELD_TYPE_LSHIFT_U64 = 4,}; +; int test(struct s *arg) { +; return __builtin_preserve_field_info(arg->bf4, FIELD_TYPE_OFFSET) + +; __builtin_preserve_field_info(arg->bf4, FIELD_TYPE_SIZE) + +; __builtin_preserve_field_info(arg->bf4, FIELD_TYPE_LSHIFT_U64); +; } +; For this case, the IR type has the same starting storage offset for fields +; bf1, bf1, bf3 and bf4 and the ABI alignment is 1 byte. So for bf4 access, +; the starting offset has to be at the beginning of field bf3. +; Compilation flag: +; clang -target bpfel -O2 -g -S -emit-llvm -Xclang -disable-llvm-passes test.c + +target triple = "sbf" + +%struct.s = type <{ i8, i16 }> + +; Function Attrs: nounwind readnone +define dso_local i32 @test(%struct.s* %arg) local_unnamed_addr #0 !dbg !13 { +entry: + call void @llvm.dbg.value(metadata %struct.s* %arg, metadata !27, metadata !DIExpression()), !dbg !28 + %0 = tail call i16* @llvm.preserve.struct.access.index.p0i16.p0s_struct.ss(%struct.s* elementtype(%struct.s) %arg, i32 1, i32 4), !dbg !29, !llvm.preserve.access.index !18 + %1 = tail call i32 @llvm.bpf.preserve.field.info.p0i16(i16* %0, i64 0), !dbg !30 + %2 = tail call i32 @llvm.bpf.preserve.field.info.p0i16(i16* %0, i64 1), !dbg !31 + %add = add i32 %2, %1, !dbg !32 + %3 = tail call i32 @llvm.bpf.preserve.field.info.p0i16(i16* %0, i64 4), !dbg !33 + %add1 = add i32 %add, %3, !dbg !34 + ret i32 %add1, !dbg !35 +} + +; CHECK: mov64 r1, 2 +; CHECK: mov64 r0, 1 +; CHECK-ALU64: add64 r0, r1 +; CHECK-ALU32: add32 w0, w1 +; CHECK-EL: mov64 r1, 56 +; CHECK-ALU64: add64 r0, r1 +; CHECK-ALU32: add32 w0, w1 +; CHECK: exit + +; CHECK: .long 1 # BTF_KIND_STRUCT(id = 2) + +; CHECK: .byte 115 # string offset=1 +; CHECK: .ascii ".text" # string offset=40 +; CHECK: .ascii "0:4" # string offset=46 + +; CHECK: .long 16 # FieldReloc +; CHECK-NEXT: .long 40 # Field reloc section string offset=40 +; CHECK-NEXT: .long 3 +; CHECK-NEXT: .long .Ltmp{{[0-9]+}} +; CHECK-NEXT: .long 2 +; CHECK-NEXT: .long 46 +; CHECK-NEXT: .long 0 +; CHECK-NEXT: .long .Ltmp{{[0-9]+}} +; CHECK-NEXT: .long 2 +; CHECK-NEXT: .long 46 +; CHECK-NEXT: .long 1 +; CHECK-NEXT: .long .Ltmp{{[0-9]+}} +; CHECK-NEXT: .long 2 +; CHECK-NEXT: .long 46 +; CHECK-NEXT: .long 4 + +; Function Attrs: nounwind readnone +declare i16* @llvm.preserve.struct.access.index.p0i16.p0s_struct.ss(%struct.s*, i32, i32) #1 + +; Function Attrs: nounwind readnone +declare i32 @llvm.bpf.preserve.field.info.p0i16(i16*, i64) #1 + +; Function Attrs: nounwind readnone speculatable +declare void @llvm.dbg.value(metadata, metadata, metadata) #2 + +attributes #0 = { nounwind readnone "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" } +attributes #1 = { nounwind readnone } +attributes #2 = { nounwind readnone speculatable } + +!llvm.dbg.cu = !{!0} +!llvm.module.flags = !{!9, !10, !11} +!llvm.ident = !{!12} + +!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 10.0.0 (https://github.com/llvm/llvm-project.git 630ca91834ecc06349cb3b4bd2982c1b85b5ad96)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, nameTableKind: None) +!1 = !DIFile(filename: "test.c", directory: "/tmp/home/yhs/work/tests/core") +!2 = !{!3} +!3 = !DICompositeType(tag: DW_TAG_enumeration_type, file: !1, line: 8, baseType: !4, size: 32, elements: !5) +!4 = !DIBasicType(name: "unsigned int", size: 32, encoding: DW_ATE_unsigned) +!5 = !{!6, !7, !8} +!6 = !DIEnumerator(name: "FIELD_TYPE_OFFSET", value: 0, isUnsigned: true) +!7 = !DIEnumerator(name: "FIELD_TYPE_SIZE", value: 1, isUnsigned: true) +!8 = !DIEnumerator(name: "FIELD_TYPE_LSHIFT_U64", value: 4, isUnsigned: true) +!9 = !{i32 2, !"Dwarf Version", i32 4} +!10 = !{i32 2, !"Debug Info Version", i32 3} +!11 = !{i32 1, !"wchar_size", i32 4} +!12 = !{!"clang version 10.0.0 (https://github.com/llvm/llvm-project.git 630ca91834ecc06349cb3b4bd2982c1b85b5ad96)"} +!13 = distinct !DISubprogram(name: "test", scope: !1, file: !1, line: 9, type: !14, scopeLine: 9, flags: DIFlagPrototyped, isDefinition: true, isOptimized: true, unit: !0, retainedNodes: !26) +!14 = !DISubroutineType(types: !15) +!15 = !{!16, !17} +!16 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +!17 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !18, size: 64) +!18 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "s", file: !1, line: 1, size: 24, elements: !19) +!19 = !{!20, !22, !23, !24, !25} +!20 = !DIDerivedType(tag: DW_TAG_member, name: "f1", scope: !18, file: !1, line: 2, baseType: !21, size: 8) +!21 = !DIBasicType(name: "char", size: 8, encoding: DW_ATE_signed_char) +!22 = !DIDerivedType(tag: DW_TAG_member, name: "bf1", scope: !18, file: !1, line: 3, baseType: !21, size: 6, offset: 8, flags: DIFlagBitField, extraData: i64 8) +!23 = !DIDerivedType(tag: DW_TAG_member, name: "bf2", scope: !18, file: !1, line: 4, baseType: !21, size: 2, offset: 14, flags: DIFlagBitField, extraData: i64 8) +!24 = !DIDerivedType(tag: DW_TAG_member, name: "bf3", scope: !18, file: !1, line: 5, baseType: !21, size: 5, offset: 16, flags: DIFlagBitField, extraData: i64 8) +!25 = !DIDerivedType(tag: DW_TAG_member, name: "bf4", scope: !18, file: !1, line: 6, baseType: !21, size: 3, offset: 21, flags: DIFlagBitField, extraData: i64 8) +!26 = !{!27} +!27 = !DILocalVariable(name: "arg", arg: 1, scope: !13, file: !1, line: 9, type: !17) +!28 = !DILocation(line: 0, scope: !13) +!29 = !DILocation(line: 10, column: 45, scope: !13) +!30 = !DILocation(line: 10, column: 10, scope: !13) +!31 = !DILocation(line: 11, column: 10, scope: !13) +!32 = !DILocation(line: 10, column: 69, scope: !13) +!33 = !DILocation(line: 12, column: 10, scope: !13) +!34 = !DILocation(line: 11, column: 67, scope: !13) +!35 = !DILocation(line: 10, column: 3, scope: !13) diff --git a/llvm/test/CodeGen/SBF/CORE/field-reloc-bitfield-record-align16.ll b/llvm/test/CodeGen/SBF/CORE/field-reloc-bitfield-record-align16.ll new file mode 100644 index 0000000000000..a32df0da09b0b --- /dev/null +++ b/llvm/test/CodeGen/SBF/CORE/field-reloc-bitfield-record-align16.ll @@ -0,0 +1,105 @@ +; RUN: opt -O2 %s | llvm-dis > %t1 +; RUN: llc -sbf-enable-btf-emission -filetype=asm -o - %t1 | FileCheck %s +; Source code: +; struct t2 { +; int a[8]; +; long: 64; +; long: 64; +; long: 64; +; long: 64; +; }; +; +; struct t1 { +; int f1: 1; +; int f2: 2; +; long: 61; +; long: 64; +; long: 64; +; long: 64; +; long: 64; +; long: 64; +; long: 64; +; long: 64; +; struct t2 f3; +; } __attribute__((preserve_access_index)); +; +; struct t1 g; +; int foo() { +; return g.f1; +; } +; Compilation flag: +; clang -target bpfel -O2 -g -S -emit-llvm -Xclang -disable-llvm-passes test.c + +; ModuleID = 'test.c' +source_filename = "test.c" +target datalayout = "e-m:e-p:64:64-i64:64-i128:128-n32:64-S128" +target triple = "sbf" + +%struct.t1 = type { i512, %struct.t2 } +%struct.t2 = type { [8 x i32], i256 } + +@g = dso_local global %struct.t1 zeroinitializer, align 4, !dbg !0 + +; Function Attrs: nounwind +define dso_local i32 @foo() #0 !dbg !22 { +entry: + %0 = call i512* @llvm.preserve.struct.access.index.p0i512.p0s_struct.t1s(%struct.t1* elementtype(%struct.t1) @g, i32 0, i32 0), !dbg !26, !llvm.preserve.access.index !5 + %bf.load = load i512, i512* %0, align 4, !dbg !26 + %bf.shl = shl i512 %bf.load, 511, !dbg !26 + %bf.ashr = ashr i512 %bf.shl, 511, !dbg !26 + %bf.cast = trunc i512 %bf.ashr to i32, !dbg !26 + ret i32 %bf.cast, !dbg !27 +} + +; CHECK: .long 68 # BTF_KIND_STRUCT(id = 4) + +; CHECK: .ascii ".text" # string offset=9 +; CHECK: .ascii "t1" # string offset=68 +; CHECK: .ascii "0:0" # string offset=105 + +; CHECK: .long 16 # FieldReloc +; CHECK: .long 9 # Field reloc section string offset=9 +; CHECK: .long 1 +; CHECK: .long .Ltmp[[#]] +; CHECK: .long 4 +; CHECK: .long 105 +; CHECK: .long 0 + +; Function Attrs: nofree nosync nounwind readnone willreturn +declare i512* @llvm.preserve.struct.access.index.p0i512.p0s_struct.t1s(%struct.t1*, i32 immarg, i32 immarg) #1 + +attributes #0 = { nounwind "frame-pointer"="all" "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" } +attributes #1 = { nofree nosync nounwind readnone willreturn } + +!llvm.dbg.cu = !{!2} +!llvm.module.flags = !{!17, !18, !19, !20} +!llvm.ident = !{!21} + +!0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression()) +!1 = distinct !DIGlobalVariable(name: "g", scope: !2, file: !3, line: 23, type: !5, isLocal: false, isDefinition: true) +!2 = distinct !DICompileUnit(language: DW_LANG_C99, file: !3, producer: "clang version 15.0.0 (https://github.com/llvm/llvm-project.git 468279d2d249e44ffa3535a613245b4ceb81a908)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, globals: !4, splitDebugInlining: false, nameTableKind: None) +!3 = !DIFile(filename: "test.c", directory: "/tmp/home/yhs/work/tests/llvm/bitfield/simple", checksumkind: CSK_MD5, checksum: "b9c80125731b87136772eec36d0b48a3") +!4 = !{!0} +!5 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "t1", file: !3, line: 9, size: 1024, elements: !6) +!6 = !{!7, !9, !10} +!7 = !DIDerivedType(tag: DW_TAG_member, name: "f1", scope: !5, file: !3, line: 10, baseType: !8, size: 1, flags: DIFlagBitField, extraData: i64 0) +!8 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +!9 = !DIDerivedType(tag: DW_TAG_member, name: "f2", scope: !5, file: !3, line: 11, baseType: !8, size: 2, offset: 1, flags: DIFlagBitField, extraData: i64 0) +!10 = !DIDerivedType(tag: DW_TAG_member, name: "f3", scope: !5, file: !3, line: 20, baseType: !11, size: 512, offset: 512) +!11 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "t2", file: !3, line: 1, size: 512, elements: !12) +!12 = !{!13} +!13 = !DIDerivedType(tag: DW_TAG_member, name: "a", scope: !11, file: !3, line: 2, baseType: !14, size: 256) +!14 = !DICompositeType(tag: DW_TAG_array_type, baseType: !8, size: 256, elements: !15) +!15 = !{!16} +!16 = !DISubrange(count: 8) +!17 = !{i32 7, !"Dwarf Version", i32 5} +!18 = !{i32 2, !"Debug Info Version", i32 3} +!19 = !{i32 1, !"wchar_size", i32 4} +!20 = !{i32 7, !"frame-pointer", i32 2} +!21 = !{!"clang version 15.0.0 (https://github.com/llvm/llvm-project.git 468279d2d249e44ffa3535a613245b4ceb81a908)"} +!22 = distinct !DISubprogram(name: "foo", scope: !3, file: !3, line: 24, type: !23, scopeLine: 24, flags: DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !2, retainedNodes: !25) +!23 = !DISubroutineType(types: !24) +!24 = !{!8} +!25 = !{} +!26 = !DILocation(line: 25, column: 12, scope: !22) +!27 = !DILocation(line: 25, column: 3, scope: !22) diff --git a/llvm/test/CodeGen/SBF/CORE/field-reloc-duplicate.ll b/llvm/test/CodeGen/SBF/CORE/field-reloc-duplicate.ll new file mode 100644 index 0000000000000..f3b85d7666c16 --- /dev/null +++ b/llvm/test/CodeGen/SBF/CORE/field-reloc-duplicate.ll @@ -0,0 +1,106 @@ +; RUN: opt -O2 -mtriple=sbf %s | llvm-dis > %t1 +; RUN: llc -sbf-enable-btf-emission -o - %t1 | FileCheck %s +; RUN: opt -passes='default' -mtriple=sbf %s | llvm-dis > %t1 +; RUN: llc -sbf-enable-btf-emission -o - %t1 | FileCheck %s +; +; Source: +; struct s1 { int a; int b; } __attribute__((preserve_access_index)); +; int foo(struct s1 *arg) { return arg->a; } +; int bar(struct s1 *arg) { return arg->a; } +; Compilation flag: +; clang -target bpf -O2 -S -emit-llvm -g -Xclang -disable-llvm-passes test.c + +%struct.s1 = type { i32, i32 } + +; Function Attrs: nounwind +define dso_local i32 @foo(%struct.s1* %arg) #0 !dbg !7 { +entry: + %arg.addr = alloca %struct.s1*, align 8 + store %struct.s1* %arg, %struct.s1** %arg.addr, align 8, !tbaa !18 + call void @llvm.dbg.declare(metadata %struct.s1** %arg.addr, metadata !17, metadata !DIExpression()), !dbg !22 + %0 = load %struct.s1*, %struct.s1** %arg.addr, align 8, !dbg !23, !tbaa !18 + %1 = call i32* @llvm.preserve.struct.access.index.p0i32.p0s_struct.s1s(%struct.s1* elementtype(%struct.s1) %0, i32 0, i32 0), !dbg !24, !llvm.preserve.access.index !12 + %2 = load i32, i32* %1, align 4, !dbg !24, !tbaa !25 + ret i32 %2, !dbg !28 +} + +; Function Attrs: nounwind readnone speculatable willreturn +declare void @llvm.dbg.declare(metadata, metadata, metadata) #1 + +; Function Attrs: nounwind readnone +declare i32* @llvm.preserve.struct.access.index.p0i32.p0s_struct.s1s(%struct.s1*, i32 immarg, i32 immarg) #2 + +; Function Attrs: nounwind +define dso_local i32 @bar(%struct.s1* %arg) #0 !dbg !29 { +entry: + %arg.addr = alloca %struct.s1*, align 8 + store %struct.s1* %arg, %struct.s1** %arg.addr, align 8, !tbaa !18 + call void @llvm.dbg.declare(metadata %struct.s1** %arg.addr, metadata !31, metadata !DIExpression()), !dbg !32 + %0 = load %struct.s1*, %struct.s1** %arg.addr, align 8, !dbg !33, !tbaa !18 + %1 = call i32* @llvm.preserve.struct.access.index.p0i32.p0s_struct.s1s(%struct.s1* elementtype(%struct.s1) %0, i32 0, i32 0), !dbg !34, !llvm.preserve.access.index !12 + %2 = load i32, i32* %1, align 4, !dbg !34, !tbaa !25 + ret i32 %2, !dbg !35 +} + +; CHECK: .long 1 # BTF_KIND_STRUCT(id = 2) + +; CHECK: .ascii "s1" # string offset=1 +; CHECK: .ascii ".text" # string offset=20 +; CHECK: .ascii "0:0" # string offset=26 + +; CHECK: .long 16 # FieldReloc +; CHECK-NEXT: .long 20 # Field reloc section string offset=20 +; CHECK-NEXT: .long 2 +; CHECK-NEXT: .long .Ltmp{{[0-9]+}} +; CHECK-NEXT: .long 2 +; CHECK-NEXT: .long 26 +; CHECK-NEXT: .long 0 +; CHECK-NEXT: .long .Ltmp{{[0-9]+}} +; CHECK-NEXT: .long 2 +; CHECK-NEXT: .long 26 +; CHECK-NEXT: .long 0 + +attributes #0 = { nounwind "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" } +attributes #1 = { nounwind readnone speculatable willreturn } +attributes #2 = { nounwind readnone } + +!llvm.dbg.cu = !{!0} +!llvm.module.flags = !{!3, !4, !5} +!llvm.ident = !{!6} + +!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 12.0.0 (https://github.com/llvm/llvm-project.git 2f40e20613758b3e11a15494c09f4b6973673d6b)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, splitDebugInlining: false, nameTableKind: None) +!1 = !DIFile(filename: "test.c", directory: "/tmp/home/yhs/work/tests/core") +!2 = !{} +!3 = !{i32 7, !"Dwarf Version", i32 4} +!4 = !{i32 2, !"Debug Info Version", i32 3} +!5 = !{i32 1, !"wchar_size", i32 4} +!6 = !{!"clang version 12.0.0 (https://github.com/llvm/llvm-project.git 2f40e20613758b3e11a15494c09f4b6973673d6b)"} +!7 = distinct !DISubprogram(name: "foo", scope: !1, file: !1, line: 2, type: !8, scopeLine: 2, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !16) +!8 = !DISubroutineType(types: !9) +!9 = !{!10, !11} +!10 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +!11 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !12, size: 64) +!12 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "s1", file: !1, line: 1, size: 64, elements: !13) +!13 = !{!14, !15} +!14 = !DIDerivedType(tag: DW_TAG_member, name: "a", scope: !12, file: !1, line: 1, baseType: !10, size: 32) +!15 = !DIDerivedType(tag: DW_TAG_member, name: "b", scope: !12, file: !1, line: 1, baseType: !10, size: 32, offset: 32) +!16 = !{!17} +!17 = !DILocalVariable(name: "arg", arg: 1, scope: !7, file: !1, line: 2, type: !11) +!18 = !{!19, !19, i64 0} +!19 = !{!"any pointer", !20, i64 0} +!20 = !{!"omnipotent char", !21, i64 0} +!21 = !{!"Simple C/C++ TBAA"} +!22 = !DILocation(line: 2, column: 20, scope: !7) +!23 = !DILocation(line: 2, column: 34, scope: !7) +!24 = !DILocation(line: 2, column: 39, scope: !7) +!25 = !{!26, !27, i64 0} +!26 = !{!"s1", !27, i64 0, !27, i64 4} +!27 = !{!"int", !20, i64 0} +!28 = !DILocation(line: 2, column: 27, scope: !7) +!29 = distinct !DISubprogram(name: "bar", scope: !1, file: !1, line: 3, type: !8, scopeLine: 3, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !30) +!30 = !{!31} +!31 = !DILocalVariable(name: "arg", arg: 1, scope: !29, file: !1, line: 3, type: !11) +!32 = !DILocation(line: 3, column: 20, scope: !29) +!33 = !DILocation(line: 3, column: 34, scope: !29) +!34 = !DILocation(line: 3, column: 39, scope: !29) +!35 = !DILocation(line: 3, column: 27, scope: !29) diff --git a/llvm/test/CodeGen/SBF/CORE/field-reloc-st-imm.ll b/llvm/test/CodeGen/SBF/CORE/field-reloc-st-imm.ll new file mode 100644 index 0000000000000..7f76a4b92957b --- /dev/null +++ b/llvm/test/CodeGen/SBF/CORE/field-reloc-st-imm.ll @@ -0,0 +1,155 @@ +; RUN: llc -march=sbf -mattr=+store-imm -sbf-enable-btf-emission < %s | FileCheck %s +; RUN: llc -march=sbf -mattr=+store-imm,+mem-encoding -sbf-enable-btf-emission < %s | FileCheck %s + +; Make sure that CO-RE relocations had been generated correctly for +; BPF_ST (store immediate) instructions and that +; BPFMISimplifyPatchable optimizations had been applied. +; +; Generated from the following source code: +; +; #define __pai __attribute__((preserve_access_index)) +; +; struct foo { +; unsigned char b; +; unsigned short h; +; unsigned int w; +; unsigned long d; +; } __pai; +; +; void bar(volatile struct foo *p) { +; p->b = 1; +; p->h = 2; +; p->w = 3; +; p->d = 4; +; } +; +; Using the following command: +; +; clang -g -O2 -S -emit-llvm --target=sbf test.c + +@"llvm.foo:0:0$0:0" = external global i64, !llvm.preserve.access.index !0 #0 +@"llvm.foo:0:2$0:1" = external global i64, !llvm.preserve.access.index !0 #0 +@"llvm.foo:0:4$0:2" = external global i64, !llvm.preserve.access.index !0 #0 +@"llvm.foo:0:8$0:3" = external global i64, !llvm.preserve.access.index !0 #0 + +; Function Attrs: nofree nounwind +define dso_local void @bar(ptr noundef %p) local_unnamed_addr #1 !dbg !18 { +entry: + call void @llvm.dbg.value(metadata ptr %p, metadata !24, metadata !DIExpression()), !dbg !25 + %0 = load i64, ptr @"llvm.foo:0:0$0:0", align 8 + %1 = getelementptr i8, ptr %p, i64 %0 + %2 = tail call ptr @llvm.bpf.passthrough.p0.p0(i32 0, ptr %1) + store volatile i8 1, ptr %2, align 8, !dbg !26, !tbaa !27 + %3 = load i64, ptr @"llvm.foo:0:2$0:1", align 8 + %4 = getelementptr i8, ptr %p, i64 %3 + %5 = tail call ptr @llvm.bpf.passthrough.p0.p0(i32 1, ptr %4) + store volatile i16 2, ptr %5, align 2, !dbg !34, !tbaa !35 + %6 = load i64, ptr @"llvm.foo:0:4$0:2", align 8 + %7 = getelementptr i8, ptr %p, i64 %6 + %8 = tail call ptr @llvm.bpf.passthrough.p0.p0(i32 2, ptr %7) + store volatile i32 3, ptr %8, align 4, !dbg !36, !tbaa !37 + %9 = load i64, ptr @"llvm.foo:0:8$0:3", align 8 + %10 = getelementptr i8, ptr %p, i64 %9 + %11 = tail call ptr @llvm.bpf.passthrough.p0.p0(i32 3, ptr %10) + store volatile i64 4, ptr %11, align 8, !dbg !38, !tbaa !39 + ret void, !dbg !40 +} + +; CHECK: [[L0:.Ltmp.*]]: +; CHECK: stb [r1 + 0], 1 +; CHECK: [[L2:.Ltmp.*]]: +; CHECK: sth [r1 + 2], 2 +; CHECK: [[L4:.Ltmp.*]]: +; CHECK: stw [r1 + 4], 3 +; CHECK: [[L6:.Ltmp.*]]: +; CHECK: stdw [r1 + 8], 4 + +; CHECK: .section .BTF +; ... +; CHECK: .long [[FOO:.*]] # BTF_KIND_STRUCT(id = [[FOO_ID:.*]]) +; ... +; CHECK: .ascii "foo" # string offset=[[FOO]] +; CHECK: .ascii ".text" # string offset=[[TEXT:.*]] +; CHECK: .ascii "0:0" # string offset=[[S1:.*]] +; CHECK: .ascii "0:1" # string offset=[[S2:.*]] +; CHECK: .ascii "0:2" # string offset=[[S3:.*]] +; CHECK: .ascii "0:3" # string offset=[[S4:.*]] + +; CHECK: .section .BTF.ext +; ... +; CHECK: .long [[#]] # FieldReloc +; CHECK-NEXT: .long [[TEXT]] # Field reloc section string offset=[[TEXT]] +; CHECK-NEXT: .long [[#]] +; CHECK-NEXT: .long [[L0]] +; CHECK-NEXT: .long [[FOO_ID]] +; CHECK-NEXT: .long [[S1]] +; CHECK-NEXT: .long 0 +; CHECK-NEXT: .long [[L2]] +; CHECK-NEXT: .long [[FOO_ID]] +; CHECK-NEXT: .long [[S2]] +; CHECK-NEXT: .long 0 +; CHECK-NEXT: .long [[L4]] +; CHECK-NEXT: .long [[FOO_ID]] +; CHECK-NEXT: .long [[S3]] +; CHECK-NEXT: .long 0 +; CHECK-NEXT: .long [[L6]] +; CHECK-NEXT: .long [[FOO_ID]] +; CHECK-NEXT: .long [[S4]] +; CHECK-NEXT: .long 0 + +; Function Attrs: nofree nosync nounwind memory(none) +declare ptr @llvm.bpf.passthrough.p0.p0(i32, ptr) #2 + +; Function Attrs: nocallback nofree nosync nounwind speculatable willreturn memory(none) +declare void @llvm.dbg.value(metadata, metadata, metadata) #3 + +attributes #0 = { "btf_ama" } +attributes #1 = { nofree nounwind "frame-pointer"="all" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="v4" } +attributes #2 = { nofree nosync nounwind memory(none) } +attributes #3 = { nocallback nofree nosync nounwind speculatable willreturn memory(none) } + +!llvm.dbg.cu = !{!11} +!llvm.module.flags = !{!12, !13, !14, !15, !16} +!llvm.ident = !{!17} + +!0 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "foo", file: !1, line: 3, size: 128, elements: !2) +!1 = !DIFile(filename: "some-file.c", directory: "/some/dir", checksumkind: CSK_MD5, checksum: "e5d03b4d39dfffadc6c607e956c37996") +!2 = !{!3, !5, !7, !9} +!3 = !DIDerivedType(tag: DW_TAG_member, name: "b", scope: !0, file: !1, line: 4, baseType: !4, size: 8) +!4 = !DIBasicType(name: "unsigned char", size: 8, encoding: DW_ATE_unsigned_char) +!5 = !DIDerivedType(tag: DW_TAG_member, name: "h", scope: !0, file: !1, line: 5, baseType: !6, size: 16, offset: 16) +!6 = !DIBasicType(name: "unsigned short", size: 16, encoding: DW_ATE_unsigned) +!7 = !DIDerivedType(tag: DW_TAG_member, name: "w", scope: !0, file: !1, line: 6, baseType: !8, size: 32, offset: 32) +!8 = !DIBasicType(name: "unsigned int", size: 32, encoding: DW_ATE_unsigned) +!9 = !DIDerivedType(tag: DW_TAG_member, name: "d", scope: !0, file: !1, line: 7, baseType: !10, size: 64, offset: 64) +!10 = !DIBasicType(name: "unsigned long", size: 64, encoding: DW_ATE_unsigned) +!11 = distinct !DICompileUnit(language: DW_LANG_C11, file: !1, producer: "clang version 18.0.0 ...", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, splitDebugInlining: false, nameTableKind: None) +!12 = !{i32 7, !"Dwarf Version", i32 5} +!13 = !{i32 2, !"Debug Info Version", i32 3} +!14 = !{i32 1, !"wchar_size", i32 4} +!15 = !{i32 7, !"frame-pointer", i32 2} +!16 = !{i32 7, !"debug-info-assignment-tracking", i1 true} +!17 = !{!"clang version 18.0.0 ..."} +!18 = distinct !DISubprogram(name: "bar", scope: !1, file: !1, line: 10, type: !19, scopeLine: 10, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !11, retainedNodes: !23) +!19 = !DISubroutineType(types: !20) +!20 = !{null, !21} +!21 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !22, size: 64) +!22 = !DIDerivedType(tag: DW_TAG_volatile_type, baseType: !0) +!23 = !{!24} +!24 = !DILocalVariable(name: "p", arg: 1, scope: !18, file: !1, line: 10, type: !21) +!25 = !DILocation(line: 0, scope: !18) +!26 = !DILocation(line: 11, column: 8, scope: !18) +!27 = !{!28, !29, i64 0} +!28 = !{!"foo", !29, i64 0, !31, i64 2, !32, i64 4, !33, i64 8} +!29 = !{!"omnipotent char", !30, i64 0} +!30 = !{!"Simple C/C++ TBAA"} +!31 = !{!"short", !29, i64 0} +!32 = !{!"int", !29, i64 0} +!33 = !{!"long", !29, i64 0} +!34 = !DILocation(line: 12, column: 8, scope: !18) +!35 = !{!28, !31, i64 2} +!36 = !DILocation(line: 13, column: 8, scope: !18) +!37 = !{!28, !32, i64 4} +!38 = !DILocation(line: 14, column: 8, scope: !18) +!39 = !{!28, !33, i64 8} +!40 = !DILocation(line: 15, column: 1, scope: !18) \ No newline at end of file diff --git a/llvm/test/CodeGen/SBF/CORE/intrinsic-array-2.ll b/llvm/test/CodeGen/SBF/CORE/intrinsic-array-2.ll new file mode 100644 index 0000000000000..4756ae5dc097e --- /dev/null +++ b/llvm/test/CodeGen/SBF/CORE/intrinsic-array-2.ll @@ -0,0 +1,84 @@ +; RUN: opt -O2 %s | llvm-dis > %t1 +; RUN: llc -sbf-enable-btf-emission -filetype=asm -o - %t1 | FileCheck %s +; RUN: llc -sbf-enable-btf-emission -mattr=+alu32 -filetype=asm -o - %t1 | FileCheck %s + +; Source: +; enum { FIELD_EXISTENCE = 2, }; +; struct s1 { int a1; }; +; int test() { +; struct s1 *v = 0; +; return __builtin_preserve_field_info(v[0], FIELD_EXISTENCE); +; } +; Compilation flag: +; clang -target bpf -O2 -g -S -emit-llvm -Xclang -disable-llvm-passes test.c + +target triple = "sbf" + +%struct.s1 = type { i32 } + +; Function Attrs: nounwind readnone +define dso_local i32 @test() local_unnamed_addr #0 !dbg !17 { +entry: + call void @llvm.dbg.value(metadata %struct.s1* null, metadata !21, metadata !DIExpression()), !dbg !22 + %0 = tail call %struct.s1* @llvm.preserve.array.access.index.p0s_struct.s1s.p0s_struct.s1s(%struct.s1* elementtype(%struct.s1) null, i32 0, i32 0), !dbg !23, !llvm.preserve.access.index !8 + %1 = tail call i32 @llvm.bpf.preserve.field.info.p0s_struct.s1s(%struct.s1* %0, i64 2), !dbg !24 + ret i32 %1, !dbg !25 +} + +; CHECK: .long 16 # BTF_KIND_STRUCT(id = 4) + +; CHECK: .ascii ".text" # string offset=10 +; CHECK: .ascii "s1" # string offset=16 +; CHECK: .byte 48 # string offset=22 + +; CHECK: .long 16 # FieldReloc +; CHECK-NEXT: .long 10 # Field reloc section string offset=10 +; CHECK-NEXT: .long 1 +; CHECK-NEXT: .long .Ltmp{{[0-9]+}} +; CHECK-NEXT: .long 4 +; CHECK-NEXT: .long 22 +; CHECK-NEXT: .long 2 + +; Function Attrs: nounwind readnone +declare %struct.s1* @llvm.preserve.array.access.index.p0s_struct.s1s.p0s_struct.s1s(%struct.s1*, i32 immarg, i32 immarg) #1 + +; Function Attrs: nounwind readnone +declare i32 @llvm.bpf.preserve.field.info.p0s_struct.s1s(%struct.s1*, i64 immarg) #1 + +; Function Attrs: nounwind readnone speculatable willreturn +declare void @llvm.dbg.value(metadata, metadata, metadata) #2 + +attributes #0 = { nounwind readnone "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" } +attributes #1 = { nounwind readnone } +attributes #2 = { nounwind readnone speculatable willreturn } + +!llvm.dbg.cu = !{!0} +!llvm.module.flags = !{!13, !14, !15} +!llvm.ident = !{!16} + +!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 11.0.0 (https://github.com/llvm/llvm-project.git 32791937d7aceb0a5e1eaabf1bb1a6dbe1639792)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, retainedTypes: !7, splitDebugInlining: false, nameTableKind: None) +!1 = !DIFile(filename: "test.c", directory: "/tmp/home/yhs/work/tests/core") +!2 = !{!3} +!3 = !DICompositeType(tag: DW_TAG_enumeration_type, file: !1, line: 1, baseType: !4, size: 32, elements: !5) +!4 = !DIBasicType(name: "unsigned int", size: 32, encoding: DW_ATE_unsigned) +!5 = !{!6} +!6 = !DIEnumerator(name: "FIELD_EXISTENCE", value: 2, isUnsigned: true) +!7 = !{!8} +!8 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !9, size: 64) +!9 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "s1", file: !1, line: 2, size: 32, elements: !10) +!10 = !{!11} +!11 = !DIDerivedType(tag: DW_TAG_member, name: "a1", scope: !9, file: !1, line: 2, baseType: !12, size: 32) +!12 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +!13 = !{i32 7, !"Dwarf Version", i32 4} +!14 = !{i32 2, !"Debug Info Version", i32 3} +!15 = !{i32 1, !"wchar_size", i32 4} +!16 = !{!"clang version 11.0.0 (https://github.com/llvm/llvm-project.git 32791937d7aceb0a5e1eaabf1bb1a6dbe1639792)"} +!17 = distinct !DISubprogram(name: "test", scope: !1, file: !1, line: 3, type: !18, scopeLine: 3, flags: DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !20) +!18 = !DISubroutineType(types: !19) +!19 = !{!12} +!20 = !{!21} +!21 = !DILocalVariable(name: "v", scope: !17, file: !1, line: 4, type: !8) +!22 = !DILocation(line: 0, scope: !17) +!23 = !DILocation(line: 5, column: 40, scope: !17) +!24 = !DILocation(line: 5, column: 10, scope: !17) +!25 = !DILocation(line: 5, column: 3, scope: !17) diff --git a/llvm/test/CodeGen/SBF/CORE/intrinsic-array.ll b/llvm/test/CodeGen/SBF/CORE/intrinsic-array.ll new file mode 100644 index 0000000000000..b869622704301 --- /dev/null +++ b/llvm/test/CodeGen/SBF/CORE/intrinsic-array.ll @@ -0,0 +1,85 @@ +; RUN: opt -O2 %s | llvm-dis > %t1 +; RUN: llc -sbf-enable-btf-emission -filetype=asm -o - %t1 | FileCheck %s +; RUN: llc -sbf-enable-btf-emission -mattr=+alu32 -filetype=asm -o - %t1 | FileCheck %s +; +; Source code: +; #define _(x) (__builtin_preserve_access_index(x)) +; struct s { int a; int b; }; +; int get_value(const void *addr); +; int test(struct s *arg) { return get_value(_(&arg[2].b)); } +; Compiler flag to generate IR: +; clang -target bpf -S -O2 -g -emit-llvm -Xclang -disable-llvm-passes test.c + +target triple = "sbf" + +%struct.s = type { i32, i32 } + +; Function Attrs: nounwind +define dso_local i32 @test(%struct.s* %arg) local_unnamed_addr #0 !dbg !7 { +entry: + call void @llvm.dbg.value(metadata %struct.s* %arg, metadata !17, metadata !DIExpression()), !dbg !18 + %0 = tail call %struct.s* @llvm.preserve.array.access.index.p0s_struct.ss.p0s_struct.ss(%struct.s* elementtype(%struct.s) %arg, i32 0, i32 2), !dbg !19, !llvm.preserve.access.index !11 + %1 = tail call i32* @llvm.preserve.struct.access.index.p0i32.p0s_struct.ss(%struct.s* elementtype(%struct.s) %0, i32 1, i32 1), !dbg !19, !llvm.preserve.access.index !12 + %2 = bitcast i32* %1 to i8*, !dbg !19 + %call = tail call i32 @get_value(i8* %2) #4, !dbg !20 + ret i32 %call, !dbg !21 +} +; CHECK-LABEL: test +; CHECK: [[RELOC:.Ltmp[0-9]+]] +; CHECK: mov64 r2, 20 +; CHECK: add64 r1, r2 +; CHECK: call get_value +; CHECK: exit +; +; CHECK: .section .BTF.ext,"",@progbits +; CHECK: .long 16 # FieldReloc +; CHECK-NEXT: .long 20 # Field reloc section string offset=20 +; CHECK-NEXT: .long 1 +; CHECK-NEXT: .long [[RELOC]] +; CHECK-NEXT: .long 2 +; CHECK-NEXT: .long 26 +; CHECK-NEXT: .long 0 + +declare dso_local i32 @get_value(i8*) local_unnamed_addr #1 + +; Function Attrs: nounwind readnone +declare %struct.s* @llvm.preserve.array.access.index.p0s_struct.ss.p0s_struct.ss(%struct.s*, i32 immarg, i32 immarg) #2 + +; Function Attrs: nounwind readnone +declare i32* @llvm.preserve.struct.access.index.p0i32.p0s_struct.ss(%struct.s*, i32 immarg, i32 immarg) #2 + +; Function Attrs: nounwind readnone speculatable +declare void @llvm.dbg.value(metadata, metadata, metadata) #3 + +attributes #0 = { nounwind "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "frame-pointer"="all" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" } +attributes #1 = { "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "frame-pointer"="all" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" } +attributes #2 = { nounwind readnone } +attributes #3 = { nounwind readnone speculatable } +attributes #4 = { nounwind } + +!llvm.dbg.cu = !{!0} +!llvm.module.flags = !{!3, !4, !5} +!llvm.ident = !{!6} + +!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 9.0.0 (trunk 365789)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, nameTableKind: None) +!1 = !DIFile(filename: "test.c", directory: "/tmp/home/yhs/work/tests/core") +!2 = !{} +!3 = !{i32 2, !"Dwarf Version", i32 4} +!4 = !{i32 2, !"Debug Info Version", i32 3} +!5 = !{i32 1, !"wchar_size", i32 4} +!6 = !{!"clang version 9.0.0 (trunk 365789)"} +!7 = distinct !DISubprogram(name: "test", scope: !1, file: !1, line: 4, type: !8, scopeLine: 4, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !16) +!8 = !DISubroutineType(types: !9) +!9 = !{!10, !11} +!10 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +!11 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !12, size: 64) +!12 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "s", file: !1, line: 2, size: 64, elements: !13) +!13 = !{!14, !15} +!14 = !DIDerivedType(tag: DW_TAG_member, name: "a", scope: !12, file: !1, line: 2, baseType: !10, size: 32) +!15 = !DIDerivedType(tag: DW_TAG_member, name: "b", scope: !12, file: !1, line: 2, baseType: !10, size: 32, offset: 32) +!16 = !{!17} +!17 = !DILocalVariable(name: "arg", arg: 1, scope: !7, file: !1, line: 4, type: !11) +!18 = !DILocation(line: 0, scope: !7) +!19 = !DILocation(line: 4, column: 44, scope: !7) +!20 = !DILocation(line: 4, column: 34, scope: !7) +!21 = !DILocation(line: 4, column: 27, scope: !7) diff --git a/llvm/test/CodeGen/SBF/CORE/intrinsic-fieldinfo-byte-size-1.ll b/llvm/test/CodeGen/SBF/CORE/intrinsic-fieldinfo-byte-size-1.ll new file mode 100644 index 0000000000000..896b3bdfaad70 --- /dev/null +++ b/llvm/test/CodeGen/SBF/CORE/intrinsic-fieldinfo-byte-size-1.ll @@ -0,0 +1,154 @@ +; RUN: opt -O2 %s | llvm-dis > %t1 +; RUN: llc -sbf-enable-btf-emission -filetype=asm -o - %t1 | FileCheck -check-prefixes=CHECK,CHECK-ALU64 %s +; RUN: llc -sbf-enable-btf-emission -mattr=+alu32 -filetype=asm -o - %t1 | FileCheck -check-prefixes=CHECK,CHECK-ALU32 %s +; Source code: +; typedef struct s1 { int a1:7; int a2:4; int a3:5; int a4:16;} __s1; +; union u1 { int b1; __s1 b2; }; +; enum { FIELD_BYTE_SIZE = 1, }; +; int test(union u1 *arg) { +; unsigned r1 = __builtin_preserve_field_info(arg->b2.a1, FIELD_BYTE_SIZE); +; unsigned r2 = __builtin_preserve_field_info(arg->b2.a2, FIELD_BYTE_SIZE); +; unsigned r3 = __builtin_preserve_field_info(arg->b2.a3, FIELD_BYTE_SIZE); +; unsigned r4 = __builtin_preserve_field_info(arg->b2.a4, FIELD_BYTE_SIZE); +; /* r1: 4, r2: 4, r3: 4, r4: 4 */ +; return r1 + r2 + r3 + r4; +; } +; Compilation flag: +; clang -target bpf -O2 -g -S -emit-llvm -Xclang -disable-llvm-passes test.c + +target triple = "sbf" + +%union.u1 = type { i32 } +%struct.s1 = type { i32 } + +; Function Attrs: nounwind readnone +define dso_local i32 @test(%union.u1* %arg) local_unnamed_addr #0 !dbg !11 { +entry: + call void @llvm.dbg.value(metadata %union.u1* %arg, metadata !28, metadata !DIExpression()), !dbg !33 + %0 = tail call %union.u1* @llvm.preserve.union.access.index.p0s_union.u1s.p0s_union.u1s(%union.u1* %arg, i32 1), !dbg !34, !llvm.preserve.access.index !16 + %b2 = bitcast %union.u1* %0 to %struct.s1*, !dbg !34 + %1 = tail call i32* @llvm.preserve.struct.access.index.p0i32.p0s_struct.s1s(%struct.s1* elementtype(%struct.s1) %b2, i32 0, i32 0), !dbg !35, !llvm.preserve.access.index !21 + %2 = tail call i32 @llvm.bpf.preserve.field.info.p0i32(i32* %1, i64 1), !dbg !36 + call void @llvm.dbg.value(metadata i32 %2, metadata !29, metadata !DIExpression()), !dbg !33 + %3 = tail call i32* @llvm.preserve.struct.access.index.p0i32.p0s_struct.s1s(%struct.s1* elementtype(%struct.s1) %b2, i32 0, i32 1), !dbg !37, !llvm.preserve.access.index !21 + %4 = tail call i32 @llvm.bpf.preserve.field.info.p0i32(i32* %3, i64 1), !dbg !38 + call void @llvm.dbg.value(metadata i32 %4, metadata !30, metadata !DIExpression()), !dbg !33 + %5 = tail call i32* @llvm.preserve.struct.access.index.p0i32.p0s_struct.s1s(%struct.s1* elementtype(%struct.s1) %b2, i32 0, i32 2), !dbg !39, !llvm.preserve.access.index !21 + %6 = tail call i32 @llvm.bpf.preserve.field.info.p0i32(i32* %5, i64 1), !dbg !40 + call void @llvm.dbg.value(metadata i32 %6, metadata !31, metadata !DIExpression()), !dbg !33 + %7 = tail call i32* @llvm.preserve.struct.access.index.p0i32.p0s_struct.s1s(%struct.s1* elementtype(%struct.s1) %b2, i32 0, i32 3), !dbg !41, !llvm.preserve.access.index !21 + %8 = tail call i32 @llvm.bpf.preserve.field.info.p0i32(i32* %7, i64 1), !dbg !42 + call void @llvm.dbg.value(metadata i32 %8, metadata !32, metadata !DIExpression()), !dbg !33 + %add = add i32 %4, %2, !dbg !43 + %add4 = add i32 %add, %6, !dbg !44 + %add5 = add i32 %add4, %8, !dbg !45 + ret i32 %add5, !dbg !46 +} + +; CHECK: mov64 r1, 4 +; CHECK: mov64 r0, 4 +; CHECK-ALU64: add64 r0, r1 +; CHECK-ALU32: add32 w0, w1 +; CHECK: mov64 r1, 4 +; CHECK-ALU64: add64 r0, r1 +; CHECK-ALU32: add32 w0, w1 +; CHECK: mov64 r1, 4 +; CHECK-ALU64: add64 r0, r1 +; CHECK-ALU32: add32 w0, w1 +; CHECK: exit + +; CHECK: .long 1 # BTF_KIND_UNION(id = 2) +; CHECK: .ascii "u1" # string offset=1 +; CHECK: .ascii ".text" # string offset=43 +; CHECK: .ascii "0:1:0" # string offset=49 +; CHECK: .ascii "0:1:1" # string offset=92 +; CHECK: .ascii "0:1:2" # string offset=98 +; CHECK: .ascii "0:1:3" # string offset=104 + +; CHECK: .long 16 # FieldReloc +; CHECK-NEXT: .long 43 # Field reloc section string offset=43 +; CHECK-NEXT: .long 4 +; CHECK-NEXT: .long .Ltmp{{[0-9]+}} +; CHECK-NEXT: .long 2 +; CHECK-NEXT: .long 49 +; CHECK-NEXT: .long 1 +; CHECK-NEXT: .long .Ltmp{{[0-9]+}} +; CHECK-NEXT: .long 2 +; CHECK-NEXT: .long 92 +; CHECK-NEXT: .long 1 +; CHECK-NEXT: .long .Ltmp{{[0-9]+}} +; CHECK-NEXT: .long 2 +; CHECK-NEXT: .long 98 +; CHECK-NEXT: .long 1 +; CHECK-NEXT: .long .Ltmp{{[0-9]+}} +; CHECK-NEXT: .long 2 +; CHECK-NEXT: .long 104 +; CHECK-NEXT: .long 1 + +; Function Attrs: nounwind readnone +declare %union.u1* @llvm.preserve.union.access.index.p0s_union.u1s.p0s_union.u1s(%union.u1*, i32) #1 + +; Function Attrs: nounwind readnone +declare i32* @llvm.preserve.struct.access.index.p0i32.p0s_struct.s1s(%struct.s1*, i32, i32) #1 + +; Function Attrs: nounwind readnone +declare i32 @llvm.bpf.preserve.field.info.p0i32(i32*, i64) #1 + +; Function Attrs: nounwind readnone speculatable willreturn +declare void @llvm.dbg.value(metadata, metadata, metadata) #2 + +attributes #0 = { nounwind readnone "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" } +attributes #1 = { nounwind readnone } +attributes #2 = { nounwind readnone speculatable willreturn } + +!llvm.dbg.cu = !{!0} +!llvm.module.flags = !{!7, !8, !9} +!llvm.ident = !{!10} + +!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 10.0.0 (https://github.com/llvm/llvm-project.git 4a60741b74384f14b21fdc0131ede326438840ab)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, nameTableKind: None) +!1 = !DIFile(filename: "test.c", directory: "/tmp/home/yhs/work/tests/core") +!2 = !{!3} +!3 = !DICompositeType(tag: DW_TAG_enumeration_type, file: !1, line: 3, baseType: !4, size: 32, elements: !5) +!4 = !DIBasicType(name: "unsigned int", size: 32, encoding: DW_ATE_unsigned) +!5 = !{!6} +!6 = !DIEnumerator(name: "FIELD_BYTE_SIZE", value: 1, isUnsigned: true) +!7 = !{i32 2, !"Dwarf Version", i32 4} +!8 = !{i32 2, !"Debug Info Version", i32 3} +!9 = !{i32 1, !"wchar_size", i32 4} +!10 = !{!"clang version 10.0.0 (https://github.com/llvm/llvm-project.git 4a60741b74384f14b21fdc0131ede326438840ab)"} +!11 = distinct !DISubprogram(name: "test", scope: !1, file: !1, line: 4, type: !12, scopeLine: 4, flags: DIFlagPrototyped, isDefinition: true, isOptimized: true, unit: !0, retainedNodes: !27) +!12 = !DISubroutineType(types: !13) +!13 = !{!14, !15} +!14 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +!15 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !16, size: 64) +!16 = distinct !DICompositeType(tag: DW_TAG_union_type, name: "u1", file: !1, line: 2, size: 32, elements: !17) +!17 = !{!18, !19} +!18 = !DIDerivedType(tag: DW_TAG_member, name: "b1", scope: !16, file: !1, line: 2, baseType: !14, size: 32) +!19 = !DIDerivedType(tag: DW_TAG_member, name: "b2", scope: !16, file: !1, line: 2, baseType: !20, size: 32) +!20 = !DIDerivedType(tag: DW_TAG_typedef, name: "__s1", file: !1, line: 1, baseType: !21) +!21 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "s1", file: !1, line: 1, size: 32, elements: !22) +!22 = !{!23, !24, !25, !26} +!23 = !DIDerivedType(tag: DW_TAG_member, name: "a1", scope: !21, file: !1, line: 1, baseType: !14, size: 7, flags: DIFlagBitField, extraData: i64 0) +!24 = !DIDerivedType(tag: DW_TAG_member, name: "a2", scope: !21, file: !1, line: 1, baseType: !14, size: 4, offset: 7, flags: DIFlagBitField, extraData: i64 0) +!25 = !DIDerivedType(tag: DW_TAG_member, name: "a3", scope: !21, file: !1, line: 1, baseType: !14, size: 5, offset: 11, flags: DIFlagBitField, extraData: i64 0) +!26 = !DIDerivedType(tag: DW_TAG_member, name: "a4", scope: !21, file: !1, line: 1, baseType: !14, size: 16, offset: 16, flags: DIFlagBitField, extraData: i64 0) +!27 = !{!28, !29, !30, !31, !32} +!28 = !DILocalVariable(name: "arg", arg: 1, scope: !11, file: !1, line: 4, type: !15) +!29 = !DILocalVariable(name: "r1", scope: !11, file: !1, line: 5, type: !4) +!30 = !DILocalVariable(name: "r2", scope: !11, file: !1, line: 6, type: !4) +!31 = !DILocalVariable(name: "r3", scope: !11, file: !1, line: 7, type: !4) +!32 = !DILocalVariable(name: "r4", scope: !11, file: !1, line: 8, type: !4) +!33 = !DILocation(line: 0, scope: !11) +!34 = !DILocation(line: 5, column: 52, scope: !11) +!35 = !DILocation(line: 5, column: 55, scope: !11) +!36 = !DILocation(line: 5, column: 17, scope: !11) +!37 = !DILocation(line: 6, column: 55, scope: !11) +!38 = !DILocation(line: 6, column: 17, scope: !11) +!39 = !DILocation(line: 7, column: 55, scope: !11) +!40 = !DILocation(line: 7, column: 17, scope: !11) +!41 = !DILocation(line: 8, column: 55, scope: !11) +!42 = !DILocation(line: 8, column: 17, scope: !11) +!43 = !DILocation(line: 10, column: 13, scope: !11) +!44 = !DILocation(line: 10, column: 18, scope: !11) +!45 = !DILocation(line: 10, column: 23, scope: !11) +!46 = !DILocation(line: 10, column: 3, scope: !11) diff --git a/llvm/test/CodeGen/SBF/CORE/intrinsic-fieldinfo-byte-size-2.ll b/llvm/test/CodeGen/SBF/CORE/intrinsic-fieldinfo-byte-size-2.ll new file mode 100644 index 0000000000000..4bb7dfe914595 --- /dev/null +++ b/llvm/test/CodeGen/SBF/CORE/intrinsic-fieldinfo-byte-size-2.ll @@ -0,0 +1,143 @@ +; RUN: opt -O2 %s | llvm-dis > %t1 +; RUN: llc -sbf-enable-btf-emission -filetype=asm -o - %t1 | FileCheck -check-prefixes=CHECK,CHECK-ALU64 %s +; RUN: llc -sbf-enable-btf-emission -mattr=+alu32 -filetype=asm -o - %t1 | FileCheck -check-prefixes=CHECK,CHECK-ALU32 %s +; Source code: +; typedef struct s1 { int a1; char a2; } __s1; +; union u1 { int b1; __s1 b2; }; +; enum { FIELD_BYTE_SIZE = 1, }; +; int test(union u1 *arg) { +; unsigned r1 = __builtin_preserve_field_info(arg->b2, FIELD_BYTE_SIZE); +; unsigned r2 = __builtin_preserve_field_info(arg->b2.a1, FIELD_BYTE_SIZE); +; unsigned r3 = __builtin_preserve_field_info(arg->b2.a2, FIELD_BYTE_SIZE); +; /* r1: 8, r2: 4, r3: 1 */ +; return r1 + r2 + r3; +; } +; Compilation flag: +; clang -target bpf -O2 -g -S -emit-llvm -Xclang -disable-llvm-passes test.c + +target triple = "sbf" + +%union.u1 = type { %struct.s1 } +%struct.s1 = type { i32, i8 } + +; Function Attrs: nounwind readnone +define dso_local i32 @test(%union.u1* %arg) local_unnamed_addr #0 !dbg !11 { +entry: + call void @llvm.dbg.value(metadata %union.u1* %arg, metadata !27, metadata !DIExpression()), !dbg !31 + %0 = tail call %union.u1* @llvm.preserve.union.access.index.p0s_union.u1s.p0s_union.u1s(%union.u1* %arg, i32 1), !dbg !32, !llvm.preserve.access.index !16 + %b2 = getelementptr inbounds %union.u1, %union.u1* %0, i64 0, i32 0, !dbg !32 + %1 = tail call i32 @llvm.bpf.preserve.field.info.p0s_struct.s1s(%struct.s1* %b2, i64 1), !dbg !33 + call void @llvm.dbg.value(metadata i32 %1, metadata !28, metadata !DIExpression()), !dbg !31 + %2 = tail call i32* @llvm.preserve.struct.access.index.p0i32.p0s_struct.s1s(%struct.s1* elementtype(%struct.s1) %b2, i32 0, i32 0), !dbg !34, !llvm.preserve.access.index !21 + %3 = tail call i32 @llvm.bpf.preserve.field.info.p0i32(i32* %2, i64 1), !dbg !35 + call void @llvm.dbg.value(metadata i32 %3, metadata !29, metadata !DIExpression()), !dbg !31 + %4 = tail call i8* @llvm.preserve.struct.access.index.p0i8.p0s_struct.s1s(%struct.s1* elementtype(%struct.s1) %b2, i32 1, i32 1), !dbg !36, !llvm.preserve.access.index !21 + %5 = tail call i32 @llvm.bpf.preserve.field.info.p0i8(i8* %4, i64 1), !dbg !37 + call void @llvm.dbg.value(metadata i32 %5, metadata !30, metadata !DIExpression()), !dbg !31 + %add = add i32 %3, %1, !dbg !38 + %add3 = add i32 %add, %5, !dbg !39 + ret i32 %add3, !dbg !40 +} + +; CHECK: mov64 r1, 8 +; CHECK: mov64 r0, 4 +; CHECK-ALU64: add64 r0, r1 +; CHECK-ALU32: add32 w0, w1 +; CHECK: mov64 r1, 1 +; CHECK-ALU64: add64 r0, r1 +; CHECK-ALU32: add32 w0, w1 +; CHECK: exit + +; CHECK: .long 1 # BTF_KIND_UNION(id = 2) +; CHECK: .ascii "u1" # string offset=1 +; CHECK: .ascii ".text" # string offset=42 +; CHECK: .ascii "0:1" # string offset=48 +; CHECK: .ascii "0:1:0" # string offset=89 +; CHECK: .ascii "0:1:1" # string offset=95 + +; CHECK: .long 16 # FieldReloc +; CHECK-NEXT: .long 42 # Field reloc section string offset=42 +; CHECK-NEXT: .long 3 +; CHECK-NEXT: .long .Ltmp{{[0-9]+}} +; CHECK-NEXT: .long 2 +; CHECK-NEXT: .long 48 +; CHECK-NEXT: .long 1 +; CHECK-NEXT: .long .Ltmp{{[0-9]+}} +; CHECK-NEXT: .long 2 +; CHECK-NEXT: .long 89 +; CHECK-NEXT: .long 1 +; CHECK-NEXT: .long .Ltmp{{[0-9]+}} +; CHECK-NEXT: .long 2 +; CHECK-NEXT: .long 95 +; CHECK-NEXT: .long 1 + +; Function Attrs: nounwind readnone +declare %union.u1* @llvm.preserve.union.access.index.p0s_union.u1s.p0s_union.u1s(%union.u1*, i32) #1 + +; Function Attrs: nounwind readnone +declare i32 @llvm.bpf.preserve.field.info.p0s_struct.s1s(%struct.s1*, i64) #1 + +; Function Attrs: nounwind readnone +declare i32* @llvm.preserve.struct.access.index.p0i32.p0s_struct.s1s(%struct.s1*, i32, i32) #1 + +; Function Attrs: nounwind readnone +declare i32 @llvm.bpf.preserve.field.info.p0i32(i32*, i64) #1 + +; Function Attrs: nounwind readnone +declare i8* @llvm.preserve.struct.access.index.p0i8.p0s_struct.s1s(%struct.s1*, i32, i32) #1 + +; Function Attrs: nounwind readnone +declare i32 @llvm.bpf.preserve.field.info.p0i8(i8*, i64) #1 + +; Function Attrs: nounwind readnone speculatable willreturn +declare void @llvm.dbg.value(metadata, metadata, metadata) #2 + +attributes #0 = { nounwind readnone "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" } +attributes #1 = { nounwind readnone } +attributes #2 = { nounwind readnone speculatable willreturn } + +!llvm.dbg.cu = !{!0} +!llvm.module.flags = !{!7, !8, !9} +!llvm.ident = !{!10} + +!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 10.0.0 (https://github.com/llvm/llvm-project.git 4a60741b74384f14b21fdc0131ede326438840ab)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, nameTableKind: None) +!1 = !DIFile(filename: "test.c", directory: "/tmp/home/yhs/work/tests/core") +!2 = !{!3} +!3 = !DICompositeType(tag: DW_TAG_enumeration_type, file: !1, line: 3, baseType: !4, size: 32, elements: !5) +!4 = !DIBasicType(name: "unsigned int", size: 32, encoding: DW_ATE_unsigned) +!5 = !{!6} +!6 = !DIEnumerator(name: "FIELD_BYTE_SIZE", value: 1, isUnsigned: true) +!7 = !{i32 2, !"Dwarf Version", i32 4} +!8 = !{i32 2, !"Debug Info Version", i32 3} +!9 = !{i32 1, !"wchar_size", i32 4} +!10 = !{!"clang version 10.0.0 (https://github.com/llvm/llvm-project.git 4a60741b74384f14b21fdc0131ede326438840ab)"} +!11 = distinct !DISubprogram(name: "test", scope: !1, file: !1, line: 4, type: !12, scopeLine: 4, flags: DIFlagPrototyped, isDefinition: true, isOptimized: true, unit: !0, retainedNodes: !26) +!12 = !DISubroutineType(types: !13) +!13 = !{!14, !15} +!14 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +!15 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !16, size: 64) +!16 = distinct !DICompositeType(tag: DW_TAG_union_type, name: "u1", file: !1, line: 2, size: 64, elements: !17) +!17 = !{!18, !19} +!18 = !DIDerivedType(tag: DW_TAG_member, name: "b1", scope: !16, file: !1, line: 2, baseType: !14, size: 32) +!19 = !DIDerivedType(tag: DW_TAG_member, name: "b2", scope: !16, file: !1, line: 2, baseType: !20, size: 64) +!20 = !DIDerivedType(tag: DW_TAG_typedef, name: "__s1", file: !1, line: 1, baseType: !21) +!21 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "s1", file: !1, line: 1, size: 64, elements: !22) +!22 = !{!23, !24} +!23 = !DIDerivedType(tag: DW_TAG_member, name: "a1", scope: !21, file: !1, line: 1, baseType: !14, size: 32) +!24 = !DIDerivedType(tag: DW_TAG_member, name: "a2", scope: !21, file: !1, line: 1, baseType: !25, size: 8, offset: 32) +!25 = !DIBasicType(name: "char", size: 8, encoding: DW_ATE_signed_char) +!26 = !{!27, !28, !29, !30} +!27 = !DILocalVariable(name: "arg", arg: 1, scope: !11, file: !1, line: 4, type: !15) +!28 = !DILocalVariable(name: "r1", scope: !11, file: !1, line: 5, type: !4) +!29 = !DILocalVariable(name: "r2", scope: !11, file: !1, line: 6, type: !4) +!30 = !DILocalVariable(name: "r3", scope: !11, file: !1, line: 7, type: !4) +!31 = !DILocation(line: 0, scope: !11) +!32 = !DILocation(line: 5, column: 52, scope: !11) +!33 = !DILocation(line: 5, column: 17, scope: !11) +!34 = !DILocation(line: 6, column: 55, scope: !11) +!35 = !DILocation(line: 6, column: 17, scope: !11) +!36 = !DILocation(line: 7, column: 55, scope: !11) +!37 = !DILocation(line: 7, column: 17, scope: !11) +!38 = !DILocation(line: 9, column: 13, scope: !11) +!39 = !DILocation(line: 9, column: 18, scope: !11) +!40 = !DILocation(line: 9, column: 3, scope: !11) diff --git a/llvm/test/CodeGen/SBF/CORE/intrinsic-fieldinfo-byte-size-3.ll b/llvm/test/CodeGen/SBF/CORE/intrinsic-fieldinfo-byte-size-3.ll new file mode 100644 index 0000000000000..c624fd2547615 --- /dev/null +++ b/llvm/test/CodeGen/SBF/CORE/intrinsic-fieldinfo-byte-size-3.ll @@ -0,0 +1,134 @@ +; RUN: opt -O2 %s | llvm-dis > %t1 +; RUN: llc -sbf-enable-btf-emission -filetype=asm -o - %t1 | FileCheck -check-prefixes=CHECK,CHECK-ALU64 %s +; RUN: llc -sbf-enable-btf-emission -mattr=+alu32 -filetype=asm -o - %t1 | FileCheck -check-prefixes=CHECK,CHECK-ALU32 %s +; Source code: +; typedef struct s1 { int a1[10][10]; } __s1; +; union u1 { int b1; __s1 b2; }; +; enum { FIELD_BYTE_SIZE = 1, }; +; int test(union u1 *arg) { +; unsigned r1 = __builtin_preserve_field_info(arg->b2.a1[5], FIELD_BYTE_SIZE); +; unsigned r2 = __builtin_preserve_field_info(arg->b2.a1[5][5], FIELD_BYTE_SIZE); +; /* r1: 40, r2: 4 */ +; return r1 + r2; +; } +; Compilation flag: +; clang -target bpf -O2 -g -S -emit-llvm -Xclang -disable-llvm-passes test.c + +target triple = "sbf" + +%union.u1 = type { %struct.s1 } +%struct.s1 = type { [10 x [10 x i32]] } + +; Function Attrs: nounwind readnone +define dso_local i32 @test(%union.u1* %arg) local_unnamed_addr #0 !dbg !18 { +entry: + call void @llvm.dbg.value(metadata %union.u1* %arg, metadata !31, metadata !DIExpression()), !dbg !34 + %0 = tail call %union.u1* @llvm.preserve.union.access.index.p0s_union.u1s.p0s_union.u1s(%union.u1* %arg, i32 1), !dbg !35, !llvm.preserve.access.index !22 + %b2 = getelementptr inbounds %union.u1, %union.u1* %0, i64 0, i32 0, !dbg !35 + %1 = tail call [10 x [10 x i32]]* @llvm.preserve.struct.access.index.p0a10a10i32.p0s_struct.s1s(%struct.s1* elementtype(%struct.s1) %b2, i32 0, i32 0), !dbg !36, !llvm.preserve.access.index !27 + %2 = tail call [10 x i32]* @llvm.preserve.array.access.index.p0a10i32.p0a10a10i32([10 x [10 x i32]]* elementtype([10 x [10 x i32]]) %1, i32 1, i32 5), !dbg !37, !llvm.preserve.access.index !8 + %3 = tail call i32 @llvm.bpf.preserve.field.info.p0a10i32([10 x i32]* %2, i64 1), !dbg !38 + call void @llvm.dbg.value(metadata i32 %3, metadata !32, metadata !DIExpression()), !dbg !34 + %4 = tail call i32* @llvm.preserve.array.access.index.p0i32.p0a10i32([10 x i32]* elementtype([10 x i32]) %2, i32 1, i32 5), !dbg !39, !llvm.preserve.access.index !12 + %5 = tail call i32 @llvm.bpf.preserve.field.info.p0i32(i32* %4, i64 1), !dbg !40 + call void @llvm.dbg.value(metadata i32 %5, metadata !33, metadata !DIExpression()), !dbg !34 + %add = add i32 %5, %3, !dbg !41 + ret i32 %add, !dbg !42 +} + +; CHECK: mov64 r1, 40 +; CHECK: mov64 r0, 4 +; CHECK-ALU64: add64 r0, r1 +; CHECK-ALU32: add32 w0, w1 +; CHECK: exit + +; CHECK: .long 1 # BTF_KIND_UNION(id = 2) +; CHECK: .ascii "u1" # string offset=1 +; CHECK: .ascii ".text" # string offset=54 +; CHECK: .ascii "0:1:0:5" # string offset=60 +; CHECK: .ascii "0:1:0:5:5" # string offset=105 + +; CHECK: .long 16 # FieldReloc +; CHECK-NEXT: .long 54 # Field reloc section string offset=54 +; CHECK-NEXT: .long 2 +; CHECK-NEXT: .long .Ltmp{{[0-9]+}} +; CHECK-NEXT: .long 2 +; CHECK-NEXT: .long 60 +; CHECK-NEXT: .long 1 +; CHECK-NEXT: .long .Ltmp{{[0-9]+}} +; CHECK-NEXT: .long 2 +; CHECK-NEXT: .long 105 +; CHECK-NEXT: .long 1 + +; Function Attrs: nounwind readnone +declare %union.u1* @llvm.preserve.union.access.index.p0s_union.u1s.p0s_union.u1s(%union.u1*, i32) #1 + +; Function Attrs: nounwind readnone +declare [10 x [10 x i32]]* @llvm.preserve.struct.access.index.p0a10a10i32.p0s_struct.s1s(%struct.s1*, i32, i32) #1 + +; Function Attrs: nounwind readnone +declare [10 x i32]* @llvm.preserve.array.access.index.p0a10i32.p0a10a10i32([10 x [10 x i32]]*, i32, i32) #1 + +; Function Attrs: nounwind readnone +declare i32 @llvm.bpf.preserve.field.info.p0a10i32([10 x i32]*, i64) #1 + +; Function Attrs: nounwind readnone +declare i32* @llvm.preserve.array.access.index.p0i32.p0a10i32([10 x i32]*, i32, i32) #1 + +; Function Attrs: nounwind readnone +declare i32 @llvm.bpf.preserve.field.info.p0i32(i32*, i64) #1 + +; Function Attrs: nounwind readnone speculatable willreturn +declare void @llvm.dbg.value(metadata, metadata, metadata) #2 + +attributes #0 = { nounwind readnone "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" } +attributes #1 = { nounwind readnone } +attributes #2 = { nounwind readnone speculatable willreturn } + +!llvm.dbg.cu = !{!0} +!llvm.module.flags = !{!14, !15, !16} +!llvm.ident = !{!17} + +!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 10.0.0 (https://github.com/llvm/llvm-project.git c1e02f16f1105ffaf1c35ee8bc38b7d6db5c6ea9)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, retainedTypes: !7, nameTableKind: None) +!1 = !DIFile(filename: "test.c", directory: "/tmp/home/yhs/work/tests/core") +!2 = !{!3} +!3 = !DICompositeType(tag: DW_TAG_enumeration_type, file: !1, line: 3, baseType: !4, size: 32, elements: !5) +!4 = !DIBasicType(name: "unsigned int", size: 32, encoding: DW_ATE_unsigned) +!5 = !{!6} +!6 = !DIEnumerator(name: "FIELD_BYTE_SIZE", value: 1, isUnsigned: true) +!7 = !{!8, !12} +!8 = !DICompositeType(tag: DW_TAG_array_type, baseType: !9, size: 3200, elements: !10) +!9 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +!10 = !{!11, !11} +!11 = !DISubrange(count: 10) +!12 = !DICompositeType(tag: DW_TAG_array_type, baseType: !9, size: 320, elements: !13) +!13 = !{!11} +!14 = !{i32 2, !"Dwarf Version", i32 4} +!15 = !{i32 2, !"Debug Info Version", i32 3} +!16 = !{i32 1, !"wchar_size", i32 4} +!17 = !{!"clang version 10.0.0 (https://github.com/llvm/llvm-project.git c1e02f16f1105ffaf1c35ee8bc38b7d6db5c6ea9)"} +!18 = distinct !DISubprogram(name: "test", scope: !1, file: !1, line: 4, type: !19, scopeLine: 4, flags: DIFlagPrototyped, isDefinition: true, isOptimized: true, unit: !0, retainedNodes: !30) +!19 = !DISubroutineType(types: !20) +!20 = !{!9, !21} +!21 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !22, size: 64) +!22 = distinct !DICompositeType(tag: DW_TAG_union_type, name: "u1", file: !1, line: 2, size: 3200, elements: !23) +!23 = !{!24, !25} +!24 = !DIDerivedType(tag: DW_TAG_member, name: "b1", scope: !22, file: !1, line: 2, baseType: !9, size: 32) +!25 = !DIDerivedType(tag: DW_TAG_member, name: "b2", scope: !22, file: !1, line: 2, baseType: !26, size: 3200) +!26 = !DIDerivedType(tag: DW_TAG_typedef, name: "__s1", file: !1, line: 1, baseType: !27) +!27 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "s1", file: !1, line: 1, size: 3200, elements: !28) +!28 = !{!29} +!29 = !DIDerivedType(tag: DW_TAG_member, name: "a1", scope: !27, file: !1, line: 1, baseType: !8, size: 3200) +!30 = !{!31, !32, !33} +!31 = !DILocalVariable(name: "arg", arg: 1, scope: !18, file: !1, line: 4, type: !21) +!32 = !DILocalVariable(name: "r1", scope: !18, file: !1, line: 5, type: !4) +!33 = !DILocalVariable(name: "r2", scope: !18, file: !1, line: 6, type: !4) +!34 = !DILocation(line: 0, scope: !18) +!35 = !DILocation(line: 5, column: 52, scope: !18) +!36 = !DILocation(line: 5, column: 55, scope: !18) +!37 = !DILocation(line: 5, column: 47, scope: !18) +!38 = !DILocation(line: 5, column: 17, scope: !18) +!39 = !DILocation(line: 6, column: 47, scope: !18) +!40 = !DILocation(line: 6, column: 17, scope: !18) +!41 = !DILocation(line: 8, column: 13, scope: !18) +!42 = !DILocation(line: 8, column: 3, scope: !18) diff --git a/llvm/test/CodeGen/SBF/CORE/intrinsic-fieldinfo-byte-size-4.ll b/llvm/test/CodeGen/SBF/CORE/intrinsic-fieldinfo-byte-size-4.ll new file mode 100644 index 0000000000000..6bc6e184d1124 --- /dev/null +++ b/llvm/test/CodeGen/SBF/CORE/intrinsic-fieldinfo-byte-size-4.ll @@ -0,0 +1,87 @@ +; RUN: opt -O2 %s | llvm-dis > %t1 +; RUN: llc -sbf-enable-btf-emission -filetype=asm -o - %t1 | FileCheck -check-prefixes=CHECK %s +; RUN: llc -sbf-enable-btf-emission -mattr=+alu32 -filetype=asm -o - %t1 | FileCheck -check-prefixes=CHECK %s +; Source code: +; typedef struct s1 { int a1; int a2:4; int a3;} __s1; +; enum { FIELD_BYTE_SIZE = 1, }; +; int test(__s1 *arg) { +; return __builtin_preserve_field_info(arg->a2, FIELD_BYTE_SIZE); +; } +; Compilation flag: +; clang -target bpf -O2 -g -S -emit-llvm -Xclang -disable-llvm-passes test.c + +target triple = "sbf" + +%struct.s1 = type { i32, i8, i32 } + +; Function Attrs: nounwind readnone +define dso_local i32 @test(%struct.s1* readnone %arg) local_unnamed_addr #0 !dbg !11 { +entry: + call void @llvm.dbg.value(metadata %struct.s1* %arg, metadata !23, metadata !DIExpression()), !dbg !24 + %0 = tail call i8* @llvm.preserve.struct.access.index.p0i8.p0s_struct.s1s(%struct.s1* elementtype(%struct.s1) %arg, i32 1, i32 1), !dbg !25, !llvm.preserve.access.index !17 + %1 = tail call i32 @llvm.bpf.preserve.field.info.p0i8(i8* %0, i64 1), !dbg !26 + ret i32 %1, !dbg !27 +} + +; CHECK: mov64 r0, 4 +; CHECK: exit + +; CHECK: .long 6 # BTF_KIND_STRUCT(id = 3) + +; CHECK: .ascii "s1" # string offset=6 +; CHECK: .ascii ".text" # string offset=31 +; CHECK: .ascii "0:1" # string offset=37 + +; CHECK: .long 16 # FieldReloc +; CHECK-NEXT: .long 31 # Field reloc section string offset=31 +; CHECK-NEXT: .long 1 +; CHECK-NEXT: .long .Ltmp{{[0-9]+}} +; CHECK-NEXT: .long 3 +; CHECK-NEXT: .long 37 +; CHECK-NEXT: .long 1 + +; Function Attrs: nounwind readnone +declare i8* @llvm.preserve.struct.access.index.p0i8.p0s_struct.s1s(%struct.s1*, i32, i32) #1 + +; Function Attrs: nounwind readnone +declare i32 @llvm.bpf.preserve.field.info.p0i8(i8*, i64) #1 + +; Function Attrs: nounwind readnone speculatable +declare void @llvm.dbg.value(metadata, metadata, metadata) #2 + +attributes #0 = { nounwind readnone "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" } +attributes #1 = { nounwind readnone } +attributes #2 = { nounwind readnone speculatable } + +!llvm.dbg.cu = !{!0} +!llvm.module.flags = !{!7, !8, !9} +!llvm.ident = !{!10} + +!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 10.0.0 (https://github.com/llvm/llvm-project.git 6c63b5d6a1cb84a75807804337c855a41c976260)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, nameTableKind: None) +!1 = !DIFile(filename: "test.c", directory: "/tmp/home/yhs/work/tests/core") +!2 = !{!3} +!3 = !DICompositeType(tag: DW_TAG_enumeration_type, file: !1, line: 2, baseType: !4, size: 32, elements: !5) +!4 = !DIBasicType(name: "unsigned int", size: 32, encoding: DW_ATE_unsigned) +!5 = !{!6} +!6 = !DIEnumerator(name: "FIELD_BYTE_SIZE", value: 1, isUnsigned: true) +!7 = !{i32 2, !"Dwarf Version", i32 4} +!8 = !{i32 2, !"Debug Info Version", i32 3} +!9 = !{i32 1, !"wchar_size", i32 4} +!10 = !{!"clang version 10.0.0 (https://github.com/llvm/llvm-project.git 6c63b5d6a1cb84a75807804337c855a41c976260)"} +!11 = distinct !DISubprogram(name: "test", scope: !1, file: !1, line: 3, type: !12, scopeLine: 3, flags: DIFlagPrototyped, isDefinition: true, isOptimized: true, unit: !0, retainedNodes: !22) +!12 = !DISubroutineType(types: !13) +!13 = !{!14, !15} +!14 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +!15 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !16, size: 64) +!16 = !DIDerivedType(tag: DW_TAG_typedef, name: "__s1", file: !1, line: 1, baseType: !17) +!17 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "s1", file: !1, line: 1, size: 96, elements: !18) +!18 = !{!19, !20, !21} +!19 = !DIDerivedType(tag: DW_TAG_member, name: "a1", scope: !17, file: !1, line: 1, baseType: !14, size: 32) +!20 = !DIDerivedType(tag: DW_TAG_member, name: "a2", scope: !17, file: !1, line: 1, baseType: !14, size: 4, offset: 32, flags: DIFlagBitField, extraData: i64 32) +!21 = !DIDerivedType(tag: DW_TAG_member, name: "a3", scope: !17, file: !1, line: 1, baseType: !14, size: 32, offset: 64) +!22 = !{!23} +!23 = !DILocalVariable(name: "arg", arg: 1, scope: !11, file: !1, line: 3, type: !15) +!24 = !DILocation(line: 0, scope: !11) +!25 = !DILocation(line: 4, column: 45, scope: !11) +!26 = !DILocation(line: 4, column: 10, scope: !11) +!27 = !DILocation(line: 4, column: 3, scope: !11) diff --git a/llvm/test/CodeGen/SBF/CORE/intrinsic-fieldinfo-existence-1.ll b/llvm/test/CodeGen/SBF/CORE/intrinsic-fieldinfo-existence-1.ll new file mode 100644 index 0000000000000..84a347eff5626 --- /dev/null +++ b/llvm/test/CodeGen/SBF/CORE/intrinsic-fieldinfo-existence-1.ll @@ -0,0 +1,168 @@ +; RUN: opt -O2 %s | llvm-dis > %t1 +; RUN: llc -sbf-enable-btf-emission -filetype=asm -o - %t1 | FileCheck -check-prefixes=CHECK,CHECK-ALU64 %s +; RUN: llc -sbf-enable-btf-emission -mattr=+alu32 -filetype=asm -o - %t1 | FileCheck -check-prefixes=CHECK,CHECK-ALU32 %s +; Source code: +; typedef unsigned __uint; +; struct s1 { int a1; __uint a2:9; __uint a3:4; }; +; union u1 { int b1; __uint b2:9; __uint b3:4; }; +; enum { FIELD_EXISTENCE = 2, }; +; int test(struct s1 *arg1, union u1 *arg2) { +; unsigned r1 = __builtin_preserve_field_info(arg1->a1, FIELD_EXISTENCE); +; unsigned r2 = __builtin_preserve_field_info(arg1->a3, FIELD_EXISTENCE); +; unsigned r3 = __builtin_preserve_field_info(arg2->b1, FIELD_EXISTENCE); +; unsigned r4 = __builtin_preserve_field_info(arg2->b3, FIELD_EXISTENCE); +; return r1 + r2 + r3 + r4; +; } +; Compilation flag: +; clang -target bpf -O2 -g -S -emit-llvm -Xclang -disable-llvm-passes test.c + +target triple = "sbf" + +%struct.s1 = type { i32, i16 } +%union.u1 = type { i32 } + +; Function Attrs: nounwind readnone +define dso_local i32 @test(%struct.s1* %arg1, %union.u1* %arg2) local_unnamed_addr #0 !dbg !11 { +entry: + call void @llvm.dbg.value(metadata %struct.s1* %arg1, metadata !29, metadata !DIExpression()), !dbg !35 + call void @llvm.dbg.value(metadata %union.u1* %arg2, metadata !30, metadata !DIExpression()), !dbg !35 + %0 = tail call i32* @llvm.preserve.struct.access.index.p0i32.p0s_struct.s1s(%struct.s1* elementtype(%struct.s1) %arg1, i32 0, i32 0), !dbg !36, !llvm.preserve.access.index !16 + %1 = tail call i32 @llvm.bpf.preserve.field.info.p0i32(i32* %0, i64 2), !dbg !37 + call void @llvm.dbg.value(metadata i32 %1, metadata !31, metadata !DIExpression()), !dbg !35 + %2 = tail call i16* @llvm.preserve.struct.access.index.p0i16.p0s_struct.s1s(%struct.s1* elementtype(%struct.s1) %arg1, i32 1, i32 2), !dbg !38, !llvm.preserve.access.index !16 + %3 = tail call i32 @llvm.bpf.preserve.field.info.p0i16(i16* %2, i64 2), !dbg !39 + call void @llvm.dbg.value(metadata i32 %3, metadata !32, metadata !DIExpression()), !dbg !35 + %4 = tail call %union.u1* @llvm.preserve.union.access.index.p0s_union.u1s.p0s_union.u1s(%union.u1* %arg2, i32 0), !dbg !40, !llvm.preserve.access.index !23 + %b1 = getelementptr inbounds %union.u1, %union.u1* %4, i64 0, i32 0, !dbg !40 + %5 = tail call i32 @llvm.bpf.preserve.field.info.p0i32(i32* %b1, i64 2), !dbg !41 + call void @llvm.dbg.value(metadata i32 %5, metadata !33, metadata !DIExpression()), !dbg !35 + %6 = tail call i32* @llvm.preserve.struct.access.index.p0i32.p0s_union.u1s(%union.u1* elementtype(%union.u1) %arg2, i32 0, i32 2), !dbg !42, !llvm.preserve.access.index !23 + %7 = bitcast i32* %6 to i8*, !dbg !42 + %8 = tail call i32 @llvm.bpf.preserve.field.info.p0i8(i8* %7, i64 2), !dbg !43 + call void @llvm.dbg.value(metadata i32 %8, metadata !34, metadata !DIExpression()), !dbg !35 + %add = add i32 %3, %1, !dbg !44 + %add1 = add i32 %add, %5, !dbg !45 + %add2 = add i32 %add1, %8, !dbg !46 + ret i32 %add2, !dbg !47 +} + +; CHECK: mov64 r1, 1 +; CHECK: mov64 r0, 1 +; CHECK-ALU64: add64 r0, r1 +; CHECK-ALU32: add32 w0, w1 +; CHECK: mov64 r1, 1 +; CHECK-ALU64: add64 r0, r1 +; CHECK-ALU32: add32 w0, w1 +; CHECK: mov64 r1, 1 +; CHECK-ALU64: add64 r0, r1 +; CHECK-ALU32: add32 w0, w1 +; CHECK: exit + +; CHECK: .long 1 # BTF_KIND_STRUCT(id = 2) +; CHECK: .long 37 # BTF_KIND_UNION(id = 7) +; CHECK: .ascii "s1" # string offset=1 +; CHECK: .ascii "u1" # string offset=37 +; CHECK: .ascii ".text" # string offset=64 +; CHECK: .ascii "0:0" # string offset=70 +; CHECK: .ascii "0:2" # string offset=111 + +; CHECK: .long 16 # FieldReloc +; CHECK-NEXT: .long 64 # Field reloc section string offset=64 +; CHECK-NEXT: .long 4 +; CHECK-NEXT: .long .Ltmp{{[0-9]+}} +; CHECK-NEXT: .long 2 +; CHECK-NEXT: .long 70 +; CHECK-NEXT: .long 2 +; CHECK-NEXT: .long .Ltmp{{[0-9]+}} +; CHECK-NEXT: .long 2 +; CHECK-NEXT: .long 111 +; CHECK-NEXT: .long 2 +; CHECK-NEXT: .long .Ltmp{{[0-9]+}} +; CHECK-NEXT: .long 7 +; CHECK-NEXT: .long 70 +; CHECK-NEXT: .long 2 +; CHECK-NEXT: .long .Ltmp{{[0-9]+}} +; CHECK-NEXT: .long 7 +; CHECK-NEXT: .long 111 +; CHECK-NEXT: .long 2 + +; Function Attrs: nounwind readnone +declare i32* @llvm.preserve.struct.access.index.p0i32.p0s_struct.s1s(%struct.s1*, i32, i32) #1 + +; Function Attrs: nounwind readnone +declare i32 @llvm.bpf.preserve.field.info.p0i32(i32*, i64) #1 + +; Function Attrs: nounwind readnone +declare i16* @llvm.preserve.struct.access.index.p0i16.p0s_struct.s1s(%struct.s1*, i32, i32) #1 + +; Function Attrs: nounwind readnone +declare i32 @llvm.bpf.preserve.field.info.p0i16(i16*, i64) #1 + +; Function Attrs: nounwind readnone +declare %union.u1* @llvm.preserve.union.access.index.p0s_union.u1s.p0s_union.u1s(%union.u1*, i32) #1 + +; Function Attrs: nounwind readnone +declare i32* @llvm.preserve.struct.access.index.p0i32.p0s_union.u1s(%union.u1*, i32, i32) #1 + +; Function Attrs: nounwind readnone +declare i32 @llvm.bpf.preserve.field.info.p0i8(i8*, i64) #1 + +; Function Attrs: nounwind readnone speculatable willreturn +declare void @llvm.dbg.value(metadata, metadata, metadata) #2 + +attributes #0 = { nounwind readnone "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" } +attributes #1 = { nounwind readnone } +attributes #2 = { nounwind readnone speculatable willreturn } + +!llvm.dbg.cu = !{!0} +!llvm.module.flags = !{!7, !8, !9} +!llvm.ident = !{!10} + +!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 10.0.0 (https://github.com/llvm/llvm-project.git 4a60741b74384f14b21fdc0131ede326438840ab)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, nameTableKind: None) +!1 = !DIFile(filename: "test.c", directory: "/tmp/home/yhs/work/tests/core") +!2 = !{!3} +!3 = !DICompositeType(tag: DW_TAG_enumeration_type, file: !1, line: 4, baseType: !4, size: 32, elements: !5) +!4 = !DIBasicType(name: "unsigned int", size: 32, encoding: DW_ATE_unsigned) +!5 = !{!6} +!6 = !DIEnumerator(name: "FIELD_EXISTENCE", value: 2, isUnsigned: true) +!7 = !{i32 2, !"Dwarf Version", i32 4} +!8 = !{i32 2, !"Debug Info Version", i32 3} +!9 = !{i32 1, !"wchar_size", i32 4} +!10 = !{!"clang version 10.0.0 (https://github.com/llvm/llvm-project.git 4a60741b74384f14b21fdc0131ede326438840ab)"} +!11 = distinct !DISubprogram(name: "test", scope: !1, file: !1, line: 5, type: !12, scopeLine: 5, flags: DIFlagPrototyped, isDefinition: true, isOptimized: true, unit: !0, retainedNodes: !28) +!12 = !DISubroutineType(types: !13) +!13 = !{!14, !15, !22} +!14 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +!15 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !16, size: 64) +!16 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "s1", file: !1, line: 2, size: 64, elements: !17) +!17 = !{!18, !19, !21} +!18 = !DIDerivedType(tag: DW_TAG_member, name: "a1", scope: !16, file: !1, line: 2, baseType: !14, size: 32) +!19 = !DIDerivedType(tag: DW_TAG_member, name: "a2", scope: !16, file: !1, line: 2, baseType: !20, size: 9, offset: 32, flags: DIFlagBitField, extraData: i64 32) +!20 = !DIDerivedType(tag: DW_TAG_typedef, name: "__uint", file: !1, line: 1, baseType: !4) +!21 = !DIDerivedType(tag: DW_TAG_member, name: "a3", scope: !16, file: !1, line: 2, baseType: !20, size: 4, offset: 41, flags: DIFlagBitField, extraData: i64 32) +!22 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !23, size: 64) +!23 = distinct !DICompositeType(tag: DW_TAG_union_type, name: "u1", file: !1, line: 3, size: 32, elements: !24) +!24 = !{!25, !26, !27} +!25 = !DIDerivedType(tag: DW_TAG_member, name: "b1", scope: !23, file: !1, line: 3, baseType: !14, size: 32) +!26 = !DIDerivedType(tag: DW_TAG_member, name: "b2", scope: !23, file: !1, line: 3, baseType: !20, size: 9, flags: DIFlagBitField, extraData: i64 0) +!27 = !DIDerivedType(tag: DW_TAG_member, name: "b3", scope: !23, file: !1, line: 3, baseType: !20, size: 4, flags: DIFlagBitField, extraData: i64 0) +!28 = !{!29, !30, !31, !32, !33, !34} +!29 = !DILocalVariable(name: "arg1", arg: 1, scope: !11, file: !1, line: 5, type: !15) +!30 = !DILocalVariable(name: "arg2", arg: 2, scope: !11, file: !1, line: 5, type: !22) +!31 = !DILocalVariable(name: "r1", scope: !11, file: !1, line: 6, type: !4) +!32 = !DILocalVariable(name: "r2", scope: !11, file: !1, line: 7, type: !4) +!33 = !DILocalVariable(name: "r3", scope: !11, file: !1, line: 8, type: !4) +!34 = !DILocalVariable(name: "r4", scope: !11, file: !1, line: 9, type: !4) +!35 = !DILocation(line: 0, scope: !11) +!36 = !DILocation(line: 6, column: 53, scope: !11) +!37 = !DILocation(line: 6, column: 17, scope: !11) +!38 = !DILocation(line: 7, column: 53, scope: !11) +!39 = !DILocation(line: 7, column: 17, scope: !11) +!40 = !DILocation(line: 8, column: 53, scope: !11) +!41 = !DILocation(line: 8, column: 17, scope: !11) +!42 = !DILocation(line: 9, column: 53, scope: !11) +!43 = !DILocation(line: 9, column: 17, scope: !11) +!44 = !DILocation(line: 10, column: 13, scope: !11) +!45 = !DILocation(line: 10, column: 18, scope: !11) +!46 = !DILocation(line: 10, column: 23, scope: !11) +!47 = !DILocation(line: 10, column: 3, scope: !11) diff --git a/llvm/test/CodeGen/SBF/CORE/intrinsic-fieldinfo-existence-2.ll b/llvm/test/CodeGen/SBF/CORE/intrinsic-fieldinfo-existence-2.ll new file mode 100644 index 0000000000000..f79d02795da83 --- /dev/null +++ b/llvm/test/CodeGen/SBF/CORE/intrinsic-fieldinfo-existence-2.ll @@ -0,0 +1,125 @@ +; RUN: opt -O2 %s | llvm-dis > %t1 +; RUN: llc -sbf-enable-btf-emission -filetype=asm -o - %t1 | FileCheck -check-prefixes=CHECK,CHECK-ALU64 %s +; RUN: llc -sbf-enable-btf-emission -mattr=+alu32 -filetype=asm -o - %t1 | FileCheck -check-prefixes=CHECK,CHECK-ALU32 %s +; Source code: +; typedef unsigned __uint; +; struct s1 { int a1; __uint a2:9; __uint a3:4; }; +; union u1 { int b1; struct s1 b2; }; +; enum { FIELD_EXISTENCE = 2, }; +; int test(union u1 *arg) { +; unsigned r1 = __builtin_preserve_field_info(arg->b2.a1, FIELD_EXISTENCE); +; unsigned r2 = __builtin_preserve_field_info(arg->b2.a3, FIELD_EXISTENCE); +; return r1 + r2; +; } +; Compilation flag: +; clang -target bpf -O2 -g -S -emit-llvm -Xclang -disable-llvm-passes test.c + +target triple = "sbf" + +%union.u1 = type { %struct.s1 } +%struct.s1 = type { i32, i16 } + +; Function Attrs: nounwind readnone +define dso_local i32 @test(%union.u1* %arg) local_unnamed_addr #0 !dbg !11 { +entry: + call void @llvm.dbg.value(metadata %union.u1* %arg, metadata !27, metadata !DIExpression()), !dbg !30 + %0 = tail call %union.u1* @llvm.preserve.union.access.index.p0s_union.u1s.p0s_union.u1s(%union.u1* %arg, i32 1), !dbg !31, !llvm.preserve.access.index !16 + %b2 = getelementptr inbounds %union.u1, %union.u1* %0, i64 0, i32 0, !dbg !31 + %1 = tail call i32* @llvm.preserve.struct.access.index.p0i32.p0s_struct.s1s(%struct.s1* elementtype(%struct.s1) %b2, i32 0, i32 0), !dbg !32, !llvm.preserve.access.index !20 + %2 = tail call i32 @llvm.bpf.preserve.field.info.p0i32(i32* %1, i64 2), !dbg !33 + call void @llvm.dbg.value(metadata i32 %2, metadata !28, metadata !DIExpression()), !dbg !30 + %3 = tail call i16* @llvm.preserve.struct.access.index.p0i16.p0s_struct.s1s(%struct.s1* elementtype(%struct.s1) %b2, i32 1, i32 2), !dbg !34, !llvm.preserve.access.index !20 + %4 = tail call i32 @llvm.bpf.preserve.field.info.p0i16(i16* %3, i64 2), !dbg !35 + call void @llvm.dbg.value(metadata i32 %4, metadata !29, metadata !DIExpression()), !dbg !30 + %add = add i32 %4, %2, !dbg !36 + ret i32 %add, !dbg !37 +} + +; CHECK: mov64 r1, 1 +; CHECK: mov64 r0, 1 +; CHECK-ALU64: add64 r0, r1 +; CHECK-ALU32: add32 w0, w1 +; CHECK: exit + +; CHECK: .long 1 # BTF_KIND_UNION(id = 2) +; CHECK: .ascii "u1" # string offset=1 +; CHECK: .ascii ".text" # string offset=55 +; CHECK: .ascii "0:1:0" # string offset=61 +; CHECK: .ascii "0:1:2" # string offset=104 + +; CHECK: .long 16 # FieldReloc +; CHECK-NEXT: .long 55 # Field reloc section string offset=55 +; CHECK-NEXT: .long 2 +; CHECK-NEXT: .long .Ltmp{{[0-9]+}} +; CHECK-NEXT: .long 2 +; CHECK-NEXT: .long 61 +; CHECK-NEXT: .long 2 +; CHECK-NEXT: .long .Ltmp{{[0-9]+}} +; CHECK-NEXT: .long 2 +; CHECK-NEXT: .long 104 +; CHECK-NEXT: .long 2 + +; Function Attrs: nounwind readnone +declare %union.u1* @llvm.preserve.union.access.index.p0s_union.u1s.p0s_union.u1s(%union.u1*, i32) #1 + +; Function Attrs: nounwind readnone +declare i32* @llvm.preserve.struct.access.index.p0i32.p0s_struct.s1s(%struct.s1*, i32, i32) #1 + +; Function Attrs: nounwind readnone +declare i32 @llvm.bpf.preserve.field.info.p0i32(i32*, i64) #1 + +; Function Attrs: nounwind readnone +declare i16* @llvm.preserve.struct.access.index.p0i16.p0s_struct.s1s(%struct.s1*, i32, i32) #1 + +; Function Attrs: nounwind readnone +declare i32 @llvm.bpf.preserve.field.info.p0i16(i16*, i64) #1 + +; Function Attrs: nounwind readnone speculatable willreturn +declare void @llvm.dbg.value(metadata, metadata, metadata) #2 + +attributes #0 = { nounwind readnone "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" } +attributes #1 = { nounwind readnone } +attributes #2 = { nounwind readnone speculatable willreturn } + +!llvm.dbg.cu = !{!0} +!llvm.module.flags = !{!7, !8, !9} +!llvm.ident = !{!10} + +!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 10.0.0 (https://github.com/llvm/llvm-project.git 4a60741b74384f14b21fdc0131ede326438840ab)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, nameTableKind: None) +!1 = !DIFile(filename: "test.c", directory: "/tmp/home/yhs/work/tests/core") +!2 = !{!3} +!3 = !DICompositeType(tag: DW_TAG_enumeration_type, file: !1, line: 4, baseType: !4, size: 32, elements: !5) +!4 = !DIBasicType(name: "unsigned int", size: 32, encoding: DW_ATE_unsigned) +!5 = !{!6} +!6 = !DIEnumerator(name: "FIELD_EXISTENCE", value: 2, isUnsigned: true) +!7 = !{i32 2, !"Dwarf Version", i32 4} +!8 = !{i32 2, !"Debug Info Version", i32 3} +!9 = !{i32 1, !"wchar_size", i32 4} +!10 = !{!"clang version 10.0.0 (https://github.com/llvm/llvm-project.git 4a60741b74384f14b21fdc0131ede326438840ab)"} +!11 = distinct !DISubprogram(name: "test", scope: !1, file: !1, line: 5, type: !12, scopeLine: 5, flags: DIFlagPrototyped, isDefinition: true, isOptimized: true, unit: !0, retainedNodes: !26) +!12 = !DISubroutineType(types: !13) +!13 = !{!14, !15} +!14 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +!15 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !16, size: 64) +!16 = distinct !DICompositeType(tag: DW_TAG_union_type, name: "u1", file: !1, line: 3, size: 64, elements: !17) +!17 = !{!18, !19} +!18 = !DIDerivedType(tag: DW_TAG_member, name: "b1", scope: !16, file: !1, line: 3, baseType: !14, size: 32) +!19 = !DIDerivedType(tag: DW_TAG_member, name: "b2", scope: !16, file: !1, line: 3, baseType: !20, size: 64) +!20 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "s1", file: !1, line: 2, size: 64, elements: !21) +!21 = !{!22, !23, !25} +!22 = !DIDerivedType(tag: DW_TAG_member, name: "a1", scope: !20, file: !1, line: 2, baseType: !14, size: 32) +!23 = !DIDerivedType(tag: DW_TAG_member, name: "a2", scope: !20, file: !1, line: 2, baseType: !24, size: 9, offset: 32, flags: DIFlagBitField, extraData: i64 32) +!24 = !DIDerivedType(tag: DW_TAG_typedef, name: "__uint", file: !1, line: 1, baseType: !4) +!25 = !DIDerivedType(tag: DW_TAG_member, name: "a3", scope: !20, file: !1, line: 2, baseType: !24, size: 4, offset: 41, flags: DIFlagBitField, extraData: i64 32) +!26 = !{!27, !28, !29} +!27 = !DILocalVariable(name: "arg", arg: 1, scope: !11, file: !1, line: 5, type: !15) +!28 = !DILocalVariable(name: "r1", scope: !11, file: !1, line: 6, type: !4) +!29 = !DILocalVariable(name: "r2", scope: !11, file: !1, line: 7, type: !4) +!30 = !DILocation(line: 0, scope: !11) +!31 = !DILocation(line: 6, column: 52, scope: !11) +!32 = !DILocation(line: 6, column: 55, scope: !11) +!33 = !DILocation(line: 6, column: 17, scope: !11) +!34 = !DILocation(line: 7, column: 55, scope: !11) +!35 = !DILocation(line: 7, column: 17, scope: !11) +!36 = !DILocation(line: 8, column: 13, scope: !11) +!37 = !DILocation(line: 8, column: 3, scope: !11) diff --git a/llvm/test/CodeGen/SBF/CORE/intrinsic-fieldinfo-existence-3.ll b/llvm/test/CodeGen/SBF/CORE/intrinsic-fieldinfo-existence-3.ll new file mode 100644 index 0000000000000..c50d135479b47 --- /dev/null +++ b/llvm/test/CodeGen/SBF/CORE/intrinsic-fieldinfo-existence-3.ll @@ -0,0 +1,133 @@ +; RUN: opt -O2 %s | llvm-dis > %t1 +; RUN: llc -sbf-enable-btf-emission -filetype=asm -o - %t1 | FileCheck -check-prefixes=CHECK,CHECK-ALU64 %s +; RUN: llc -sbf-enable-btf-emission -mattr=+alu32 -filetype=asm -o - %t1 | FileCheck -check-prefixes=CHECK,CHECK-ALU32 %s +; Source code: +; typedef struct s1 { int a1[10][10]; } __s1; +; union u1 { int b1; __s1 b2; }; +; enum { FIELD_EXISTENCE = 2, }; +; int test(union u1 *arg) { +; unsigned r1 = __builtin_preserve_field_info(arg->b2.a1[5], FIELD_EXISTENCE); +; unsigned r2 = __builtin_preserve_field_info(arg->b2.a1[5][5], FIELD_EXISTENCE); +; return r1 + r2; +; } +; Compilation flag: +; clang -target bpf -O2 -g -S -emit-llvm -Xclang -disable-llvm-passes test.c + +target triple = "sbf" + +%union.u1 = type { %struct.s1 } +%struct.s1 = type { [10 x [10 x i32]] } + +; Function Attrs: nounwind readnone +define dso_local i32 @test(%union.u1* %arg) local_unnamed_addr #0 !dbg !18 { +entry: + call void @llvm.dbg.value(metadata %union.u1* %arg, metadata !31, metadata !DIExpression()), !dbg !34 + %0 = tail call %union.u1* @llvm.preserve.union.access.index.p0s_union.u1s.p0s_union.u1s(%union.u1* %arg, i32 1), !dbg !35, !llvm.preserve.access.index !22 + %b2 = getelementptr inbounds %union.u1, %union.u1* %0, i64 0, i32 0, !dbg !35 + %1 = tail call [10 x [10 x i32]]* @llvm.preserve.struct.access.index.p0a10a10i32.p0s_struct.s1s(%struct.s1* elementtype(%struct.s1) %b2, i32 0, i32 0), !dbg !36, !llvm.preserve.access.index !27 + %2 = tail call [10 x i32]* @llvm.preserve.array.access.index.p0a10i32.p0a10a10i32([10 x [10 x i32]]* elementtype([10 x [10 x i32]]) %1, i32 1, i32 5), !dbg !37, !llvm.preserve.access.index !8 + %3 = tail call i32 @llvm.bpf.preserve.field.info.p0a10i32([10 x i32]* %2, i64 2), !dbg !38 + call void @llvm.dbg.value(metadata i32 %3, metadata !32, metadata !DIExpression()), !dbg !34 + %4 = tail call i32* @llvm.preserve.array.access.index.p0i32.p0a10i32([10 x i32]* elementtype([10 x i32]) %2, i32 1, i32 5), !dbg !39, !llvm.preserve.access.index !12 + %5 = tail call i32 @llvm.bpf.preserve.field.info.p0i32(i32* %4, i64 2), !dbg !40 + call void @llvm.dbg.value(metadata i32 %5, metadata !33, metadata !DIExpression()), !dbg !34 + %add = add i32 %5, %3, !dbg !41 + ret i32 %add, !dbg !42 +} + +; CHECK: mov64 r1, 1 +; CHECK: mov64 r0, 1 +; CHECK-ALU64: add64 r0, r1 +; CHECK-ALU32: add32 w0, w1 +; CHECK: exit + +; CHECK: .long 1 # BTF_KIND_UNION(id = 2) +; CHECK: .ascii "u1" # string offset=1 +; CHECK: .ascii ".text" # string offset=54 +; CHECK: .ascii "0:1:0:5" # string offset=60 +; CHECK: .ascii "0:1:0:5:5" # string offset=105 + +; CHECK: .long 16 # FieldReloc +; CHECK-NEXT: .long 54 # Field reloc section string offset=54 +; CHECK-NEXT: .long 2 +; CHECK-NEXT: .long .Ltmp{{[0-9]+}} +; CHECK-NEXT: .long 2 +; CHECK-NEXT: .long 60 +; CHECK-NEXT: .long 2 +; CHECK-NEXT: .long .Ltmp{{[0-9]+}} +; CHECK-NEXT: .long 2 +; CHECK-NEXT: .long 105 +; CHECK-NEXT: .long 2 + +; Function Attrs: nounwind readnone +declare %union.u1* @llvm.preserve.union.access.index.p0s_union.u1s.p0s_union.u1s(%union.u1*, i32) #1 + +; Function Attrs: nounwind readnone +declare [10 x [10 x i32]]* @llvm.preserve.struct.access.index.p0a10a10i32.p0s_struct.s1s(%struct.s1*, i32, i32) #1 + +; Function Attrs: nounwind readnone +declare [10 x i32]* @llvm.preserve.array.access.index.p0a10i32.p0a10a10i32([10 x [10 x i32]]*, i32, i32) #1 + +; Function Attrs: nounwind readnone +declare i32 @llvm.bpf.preserve.field.info.p0a10i32([10 x i32]*, i64) #1 + +; Function Attrs: nounwind readnone +declare i32* @llvm.preserve.array.access.index.p0i32.p0a10i32([10 x i32]*, i32, i32) #1 + +; Function Attrs: nounwind readnone +declare i32 @llvm.bpf.preserve.field.info.p0i32(i32*, i64) #1 + +; Function Attrs: nounwind readnone speculatable willreturn +declare void @llvm.dbg.value(metadata, metadata, metadata) #2 + +attributes #0 = { nounwind readnone "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" } +attributes #1 = { nounwind readnone } +attributes #2 = { nounwind readnone speculatable willreturn } + +!llvm.dbg.cu = !{!0} +!llvm.module.flags = !{!14, !15, !16} +!llvm.ident = !{!17} + +!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 10.0.0 (https://github.com/llvm/llvm-project.git c1e02f16f1105ffaf1c35ee8bc38b7d6db5c6ea9)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, retainedTypes: !7, nameTableKind: None) +!1 = !DIFile(filename: "test.c", directory: "/tmp/home/yhs/work/tests/core") +!2 = !{!3} +!3 = !DICompositeType(tag: DW_TAG_enumeration_type, file: !1, line: 3, baseType: !4, size: 32, elements: !5) +!4 = !DIBasicType(name: "unsigned int", size: 32, encoding: DW_ATE_unsigned) +!5 = !{!6} +!6 = !DIEnumerator(name: "FIELD_EXISTENCE", value: 2, isUnsigned: true) +!7 = !{!8, !12} +!8 = !DICompositeType(tag: DW_TAG_array_type, baseType: !9, size: 3200, elements: !10) +!9 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +!10 = !{!11, !11} +!11 = !DISubrange(count: 10) +!12 = !DICompositeType(tag: DW_TAG_array_type, baseType: !9, size: 320, elements: !13) +!13 = !{!11} +!14 = !{i32 2, !"Dwarf Version", i32 4} +!15 = !{i32 2, !"Debug Info Version", i32 3} +!16 = !{i32 1, !"wchar_size", i32 4} +!17 = !{!"clang version 10.0.0 (https://github.com/llvm/llvm-project.git c1e02f16f1105ffaf1c35ee8bc38b7d6db5c6ea9)"} +!18 = distinct !DISubprogram(name: "test", scope: !1, file: !1, line: 4, type: !19, scopeLine: 4, flags: DIFlagPrototyped, isDefinition: true, isOptimized: true, unit: !0, retainedNodes: !30) +!19 = !DISubroutineType(types: !20) +!20 = !{!9, !21} +!21 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !22, size: 64) +!22 = distinct !DICompositeType(tag: DW_TAG_union_type, name: "u1", file: !1, line: 2, size: 3200, elements: !23) +!23 = !{!24, !25} +!24 = !DIDerivedType(tag: DW_TAG_member, name: "b1", scope: !22, file: !1, line: 2, baseType: !9, size: 32) +!25 = !DIDerivedType(tag: DW_TAG_member, name: "b2", scope: !22, file: !1, line: 2, baseType: !26, size: 3200) +!26 = !DIDerivedType(tag: DW_TAG_typedef, name: "__s1", file: !1, line: 1, baseType: !27) +!27 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "s1", file: !1, line: 1, size: 3200, elements: !28) +!28 = !{!29} +!29 = !DIDerivedType(tag: DW_TAG_member, name: "a1", scope: !27, file: !1, line: 1, baseType: !8, size: 3200) +!30 = !{!31, !32, !33} +!31 = !DILocalVariable(name: "arg", arg: 1, scope: !18, file: !1, line: 4, type: !21) +!32 = !DILocalVariable(name: "r1", scope: !18, file: !1, line: 5, type: !4) +!33 = !DILocalVariable(name: "r2", scope: !18, file: !1, line: 6, type: !4) +!34 = !DILocation(line: 0, scope: !18) +!35 = !DILocation(line: 5, column: 52, scope: !18) +!36 = !DILocation(line: 5, column: 55, scope: !18) +!37 = !DILocation(line: 5, column: 47, scope: !18) +!38 = !DILocation(line: 5, column: 17, scope: !18) +!39 = !DILocation(line: 6, column: 47, scope: !18) +!40 = !DILocation(line: 6, column: 17, scope: !18) +!41 = !DILocation(line: 7, column: 13, scope: !18) +!42 = !DILocation(line: 7, column: 3, scope: !18) diff --git a/llvm/test/CodeGen/SBF/CORE/intrinsic-fieldinfo-existence-4.ll b/llvm/test/CodeGen/SBF/CORE/intrinsic-fieldinfo-existence-4.ll new file mode 100644 index 0000000000000..4e9a018302676 --- /dev/null +++ b/llvm/test/CodeGen/SBF/CORE/intrinsic-fieldinfo-existence-4.ll @@ -0,0 +1,109 @@ +; RUN: opt -O2 -mtriple=sbf %s | llvm-dis > %t1 +; RUN: llc -sbf-enable-btf-emission -filetype=asm -o - %t1 | FileCheck %s +; RUN: llc -sbf-enable-btf-emission -mattr=+alu32 -filetype=asm -o - %t1 | FileCheck %s +; Source code: +; #define BPF_FIELD_EXISTS 2 +; unsigned test1() { +; struct t { +; int val; +; } bar; +; return __builtin_preserve_field_info((&bar)[1], BPF_FIELD_EXISTS); +; } +; Compilation flag: +; clang -target bpf -O2 -g -S -emit-llvm -Xclang -disable-llvm-passes test.c + +%struct.t = type { i32 } + +; Function Attrs: nounwind +define dso_local i32 @test1() #0 !dbg !6 { +entry: + %bar = alloca %struct.t, align 4 + %0 = bitcast %struct.t* %bar to i8*, !dbg !20 + call void @llvm.lifetime.start.p0i8(i64 4, i8* %0) #5, !dbg !20 + call void @llvm.dbg.declare(metadata %struct.t* %bar, metadata !11, metadata !DIExpression()), !dbg !21 + %1 = call %struct.t* @llvm.preserve.array.access.index.p0s_struct.ts.p0s_struct.ts(%struct.t* elementtype(%struct.t) %bar, i32 0, i32 1), !dbg !22, !llvm.preserve.access.index !4 + %2 = call i32 @llvm.bpf.preserve.field.info.p0s_struct.ts(%struct.t* %1, i64 2), !dbg !23 + %3 = bitcast %struct.t* %bar to i8*, !dbg !24 + call void @llvm.lifetime.end.p0i8(i64 4, i8* %3) #5, !dbg !24 + ret i32 %2, !dbg !25 +} + +; CHECK: mov64 r0, 1 +; CHECK-NEXT: exit + +; CHECK: .long 26 # BTF_KIND_STRUCT(id = 4) +; CHECK-NEXT: .long 67108865 # 0x4000001 +; CHECK-NEXT: .long 4 +; CHECK-NEXT: .long 28 +; CHECK-NEXT: .long 5 +; CHECK-NEXT: .long 0 # 0x0 +; CHECK-NEXT: .long 32 # BTF_KIND_INT(id = 5) +; CHECK-NEXT: .long 16777216 # 0x1000000 +; CHECK-NEXT: .long 4 +; CHECK-NEXT: .long 16777248 # 0x1000020 + +; CHECK: .byte 116 # string offset=26 +; CHECK: .ascii "val" # string offset=28 +; CHECK: .ascii "int" # string offset=32 +; CHECK: .byte 49 # string offset=36 + +; CHECK: .long 16 # FieldReloc +; CHECK-NEXT: .long {{[0-9]+}} # Field reloc section string +; CHECK-NEXT: .long 1 +; CHECK-NEXT: .long .Ltmp{{[0-9]+}} +; CHECK-NEXT: .long 4 +; CHECK-NEXT: .long 36 +; CHECK-NEXT: .long 2 + +; Function Attrs: argmemonly nofree nosync nounwind willreturn +declare void @llvm.lifetime.start.p0i8(i64 immarg, i8* nocapture) #1 + +; Function Attrs: nofree nosync nounwind readnone speculatable willreturn +declare void @llvm.dbg.declare(metadata, metadata, metadata) #2 + +; Function Attrs: nofree nosync nounwind readnone willreturn +declare %struct.t* @llvm.preserve.array.access.index.p0s_struct.ts.p0s_struct.ts(%struct.t*, i32 immarg, i32 immarg) #3 + +; Function Attrs: nounwind readnone +declare i32 @llvm.bpf.preserve.field.info.p0s_struct.ts(%struct.t*, i64 immarg) #4 + +; Function Attrs: argmemonly nofree nosync nounwind willreturn +declare void @llvm.lifetime.end.p0i8(i64 immarg, i8* nocapture) #1 + +attributes #0 = { nounwind "frame-pointer"="all" "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" } +attributes #1 = { argmemonly nofree nosync nounwind willreturn } +attributes #2 = { nofree nosync nounwind readnone speculatable willreturn } +attributes #3 = { nofree nosync nounwind readnone willreturn } +attributes #4 = { nounwind readnone } +attributes #5 = { nounwind } + +!llvm.dbg.cu = !{!0} +!llvm.module.flags = !{!15, !16, !17, !18} +!llvm.ident = !{!19} + +!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 13.0.0 (https://github.com/llvm/llvm-project.git 2e0ee68dc85c0a2b7e65e489a60ab363393b06a8)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, retainedTypes: !3, splitDebugInlining: false, nameTableKind: None) +!1 = !DIFile(filename: "test.c", directory: "/tmp/home/yhs/work/tests/core") +!2 = !{} +!3 = !{!4} +!4 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !5, size: 64) +!5 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "t", scope: !6, file: !1, line: 3, size: 32, elements: !12) +!6 = distinct !DISubprogram(name: "test1", scope: !1, file: !1, line: 2, type: !7, scopeLine: 2, flags: DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !10) +!7 = !DISubroutineType(types: !8) +!8 = !{!9} +!9 = !DIBasicType(name: "unsigned int", size: 32, encoding: DW_ATE_unsigned) +!10 = !{!11} +!11 = !DILocalVariable(name: "bar", scope: !6, file: !1, line: 5, type: !5) +!12 = !{!13} +!13 = !DIDerivedType(tag: DW_TAG_member, name: "val", scope: !5, file: !1, line: 4, baseType: !14, size: 32) +!14 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +!15 = !{i32 7, !"Dwarf Version", i32 4} +!16 = !{i32 2, !"Debug Info Version", i32 3} +!17 = !{i32 1, !"wchar_size", i32 4} +!18 = !{i32 7, !"frame-pointer", i32 2} +!19 = !{!"clang version 13.0.0 (https://github.com/llvm/llvm-project.git 2e0ee68dc85c0a2b7e65e489a60ab363393b06a8)"} +!20 = !DILocation(line: 3, column: 3, scope: !6) +!21 = !DILocation(line: 5, column: 5, scope: !6) +!22 = !DILocation(line: 6, column: 40, scope: !6) +!23 = !DILocation(line: 6, column: 10, scope: !6) +!24 = !DILocation(line: 7, column: 1, scope: !6) +!25 = !DILocation(line: 6, column: 3, scope: !6) diff --git a/llvm/test/CodeGen/SBF/CORE/intrinsic-fieldinfo-lshift-1.ll b/llvm/test/CodeGen/SBF/CORE/intrinsic-fieldinfo-lshift-1.ll new file mode 100644 index 0000000000000..9396868d18f94 --- /dev/null +++ b/llvm/test/CodeGen/SBF/CORE/intrinsic-fieldinfo-lshift-1.ll @@ -0,0 +1,155 @@ +; RUN: opt -O2 %s | llvm-dis > %t1 +; RUN: llc -sbf-enable-btf-emission -filetype=asm -o - %t1 | FileCheck -check-prefixes=CHECK,CHECK-EL,CHECK-ALU64 %s +; RUN: llc -sbf-enable-btf-emission -mattr=+alu32 -filetype=asm -o - %t1 | FileCheck -check-prefixes=CHECK,CHECK-EL,CHECK-ALU32 %s +; Source code: +; typedef struct s1 { int a1:7; int a2:4; int a3:5; int a4:16;} __s1; +; union u1 { int b1; __s1 b2; }; +; enum { FIELD_LSHIFT_U64 = 4, }; +; int test(union u1 *arg) { +; unsigned r1 = __builtin_preserve_field_info(arg->b2.a1, FIELD_LSHIFT_U64); +; unsigned r2 = __builtin_preserve_field_info(arg->b2.a2, FIELD_LSHIFT_U64); +; unsigned r3 = __builtin_preserve_field_info(arg->b2.a3, FIELD_LSHIFT_U64); +; unsigned r4 = __builtin_preserve_field_info(arg->b2.a4, FIELD_LSHIFT_U64); +; /* big endian: r1: 32, r2: 39, r3: 43, r4: 48 */ +; /* little endian: r1: 57, r2: 53, r3: 48, r4: 32 */ +; return r1 + r2 + r3 + r4; +; } +; Compilation flag: +; clang -target bpfel -O2 -g -S -emit-llvm -Xclang -disable-llvm-passes test.c + +target triple = "sbf" + +%union.u1 = type { i32 } +%struct.s1 = type { i32 } + +; Function Attrs: nounwind readnone +define dso_local i32 @test(%union.u1* %arg) local_unnamed_addr #0 !dbg !11 { +entry: + call void @llvm.dbg.value(metadata %union.u1* %arg, metadata !28, metadata !DIExpression()), !dbg !33 + %0 = tail call %union.u1* @llvm.preserve.union.access.index.p0s_union.u1s.p0s_union.u1s(%union.u1* %arg, i32 1), !dbg !34, !llvm.preserve.access.index !16 + %b2 = bitcast %union.u1* %0 to %struct.s1*, !dbg !34 + %1 = tail call i32* @llvm.preserve.struct.access.index.p0i32.p0s_struct.s1s(%struct.s1* elementtype(%struct.s1) %b2, i32 0, i32 0), !dbg !35, !llvm.preserve.access.index !21 + %2 = tail call i32 @llvm.bpf.preserve.field.info.p0i32(i32* %1, i64 4), !dbg !36 + call void @llvm.dbg.value(metadata i32 %2, metadata !29, metadata !DIExpression()), !dbg !33 + %3 = tail call i32* @llvm.preserve.struct.access.index.p0i32.p0s_struct.s1s(%struct.s1* elementtype(%struct.s1) %b2, i32 0, i32 1), !dbg !37, !llvm.preserve.access.index !21 + %4 = tail call i32 @llvm.bpf.preserve.field.info.p0i32(i32* %3, i64 4), !dbg !38 + call void @llvm.dbg.value(metadata i32 %4, metadata !30, metadata !DIExpression()), !dbg !33 + %5 = tail call i32* @llvm.preserve.struct.access.index.p0i32.p0s_struct.s1s(%struct.s1* elementtype(%struct.s1) %b2, i32 0, i32 2), !dbg !39, !llvm.preserve.access.index !21 + %6 = tail call i32 @llvm.bpf.preserve.field.info.p0i32(i32* %5, i64 4), !dbg !40 + call void @llvm.dbg.value(metadata i32 %6, metadata !31, metadata !DIExpression()), !dbg !33 + %7 = tail call i32* @llvm.preserve.struct.access.index.p0i32.p0s_struct.s1s(%struct.s1* elementtype(%struct.s1) %b2, i32 0, i32 3), !dbg !41, !llvm.preserve.access.index !21 + %8 = tail call i32 @llvm.bpf.preserve.field.info.p0i32(i32* %7, i64 4), !dbg !42 + call void @llvm.dbg.value(metadata i32 %8, metadata !32, metadata !DIExpression()), !dbg !33 + %add = add i32 %4, %2, !dbg !43 + %add4 = add i32 %add, %6, !dbg !44 + %add5 = add i32 %add4, %8, !dbg !45 + ret i32 %add5, !dbg !46 +} + +; CHECK-EL: mov64 r1, 57 +; CHECK-EL: mov64 r0, 53 +; CHECK-ALU64: add64 r0, r1 +; CHECK-ALU32: add32 w0, w1 +; CHECK-EL: mov64 r1, 48 +; CHECK-ALU64: add64 r0, r1 +; CHECK-ALU32: add32 w0, w1 +; CHECK-EL: mov64 r1, 32 +; CHECK-ALU64: add64 r0, r1 +; CHECK-ALU32: add32 w0, w1 +; CHECK: exit + +; CHECK: .long 1 # BTF_KIND_UNION(id = 2) +; CHECK: .ascii "u1" # string offset=1 +; CHECK: .ascii ".text" # string offset=43 +; CHECK: .ascii "0:1:0" # string offset=49 +; CHECK: .ascii "0:1:1" # string offset=92 +; CHECK: .ascii "0:1:2" # string offset=98 +; CHECK: .ascii "0:1:3" # string offset=104 + +; CHECK: .long 16 # FieldReloc +; CHECK-NEXT: .long 43 # Field reloc section string offset=43 +; CHECK-NEXT: .long 4 +; CHECK-NEXT: .long .Ltmp{{[0-9]+}} +; CHECK-NEXT: .long 2 +; CHECK-NEXT: .long 49 +; CHECK-NEXT: .long 4 +; CHECK-NEXT: .long .Ltmp{{[0-9]+}} +; CHECK-NEXT: .long 2 +; CHECK-NEXT: .long 92 +; CHECK-NEXT: .long 4 +; CHECK-NEXT: .long .Ltmp{{[0-9]+}} +; CHECK-NEXT: .long 2 +; CHECK-NEXT: .long 98 +; CHECK-NEXT: .long 4 +; CHECK-NEXT: .long .Ltmp{{[0-9]+}} +; CHECK-NEXT: .long 2 +; CHECK-NEXT: .long 104 +; CHECK-NEXT: .long 4 + +; Function Attrs: nounwind readnone +declare %union.u1* @llvm.preserve.union.access.index.p0s_union.u1s.p0s_union.u1s(%union.u1*, i32) #1 + +; Function Attrs: nounwind readnone +declare i32* @llvm.preserve.struct.access.index.p0i32.p0s_struct.s1s(%struct.s1*, i32, i32) #1 + +; Function Attrs: nounwind readnone +declare i32 @llvm.bpf.preserve.field.info.p0i32(i32*, i64) #1 + +; Function Attrs: nounwind readnone speculatable willreturn +declare void @llvm.dbg.value(metadata, metadata, metadata) #2 + +attributes #0 = { nounwind readnone "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" } +attributes #1 = { nounwind readnone } +attributes #2 = { nounwind readnone speculatable willreturn } + +!llvm.dbg.cu = !{!0} +!llvm.module.flags = !{!7, !8, !9} +!llvm.ident = !{!10} + +!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 10.0.0 (https://github.com/llvm/llvm-project.git 5635073377f153f7f2ff9b34c77af3c79885ff4a)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, nameTableKind: None) +!1 = !DIFile(filename: "test.c", directory: "/tmp/home/yhs/work/tests/core") +!2 = !{!3} +!3 = !DICompositeType(tag: DW_TAG_enumeration_type, file: !1, line: 3, baseType: !4, size: 32, elements: !5) +!4 = !DIBasicType(name: "unsigned int", size: 32, encoding: DW_ATE_unsigned) +!5 = !{!6} +!6 = !DIEnumerator(name: "FIELD_LSHIFT_U64", value: 4, isUnsigned: true) +!7 = !{i32 2, !"Dwarf Version", i32 4} +!8 = !{i32 2, !"Debug Info Version", i32 3} +!9 = !{i32 1, !"wchar_size", i32 4} +!10 = !{!"clang version 10.0.0 (https://github.com/llvm/llvm-project.git 5635073377f153f7f2ff9b34c77af3c79885ff4a)"} +!11 = distinct !DISubprogram(name: "test", scope: !1, file: !1, line: 4, type: !12, scopeLine: 4, flags: DIFlagPrototyped, isDefinition: true, isOptimized: true, unit: !0, retainedNodes: !27) +!12 = !DISubroutineType(types: !13) +!13 = !{!14, !15} +!14 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +!15 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !16, size: 64) +!16 = distinct !DICompositeType(tag: DW_TAG_union_type, name: "u1", file: !1, line: 2, size: 32, elements: !17) +!17 = !{!18, !19} +!18 = !DIDerivedType(tag: DW_TAG_member, name: "b1", scope: !16, file: !1, line: 2, baseType: !14, size: 32) +!19 = !DIDerivedType(tag: DW_TAG_member, name: "b2", scope: !16, file: !1, line: 2, baseType: !20, size: 32) +!20 = !DIDerivedType(tag: DW_TAG_typedef, name: "__s1", file: !1, line: 1, baseType: !21) +!21 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "s1", file: !1, line: 1, size: 32, elements: !22) +!22 = !{!23, !24, !25, !26} +!23 = !DIDerivedType(tag: DW_TAG_member, name: "a1", scope: !21, file: !1, line: 1, baseType: !14, size: 7, flags: DIFlagBitField, extraData: i64 0) +!24 = !DIDerivedType(tag: DW_TAG_member, name: "a2", scope: !21, file: !1, line: 1, baseType: !14, size: 4, offset: 7, flags: DIFlagBitField, extraData: i64 0) +!25 = !DIDerivedType(tag: DW_TAG_member, name: "a3", scope: !21, file: !1, line: 1, baseType: !14, size: 5, offset: 11, flags: DIFlagBitField, extraData: i64 0) +!26 = !DIDerivedType(tag: DW_TAG_member, name: "a4", scope: !21, file: !1, line: 1, baseType: !14, size: 16, offset: 16, flags: DIFlagBitField, extraData: i64 0) +!27 = !{!28, !29, !30, !31, !32} +!28 = !DILocalVariable(name: "arg", arg: 1, scope: !11, file: !1, line: 4, type: !15) +!29 = !DILocalVariable(name: "r1", scope: !11, file: !1, line: 5, type: !4) +!30 = !DILocalVariable(name: "r2", scope: !11, file: !1, line: 6, type: !4) +!31 = !DILocalVariable(name: "r3", scope: !11, file: !1, line: 7, type: !4) +!32 = !DILocalVariable(name: "r4", scope: !11, file: !1, line: 8, type: !4) +!33 = !DILocation(line: 0, scope: !11) +!34 = !DILocation(line: 5, column: 52, scope: !11) +!35 = !DILocation(line: 5, column: 55, scope: !11) +!36 = !DILocation(line: 5, column: 17, scope: !11) +!37 = !DILocation(line: 6, column: 55, scope: !11) +!38 = !DILocation(line: 6, column: 17, scope: !11) +!39 = !DILocation(line: 7, column: 55, scope: !11) +!40 = !DILocation(line: 7, column: 17, scope: !11) +!41 = !DILocation(line: 8, column: 55, scope: !11) +!42 = !DILocation(line: 8, column: 17, scope: !11) +!43 = !DILocation(line: 11, column: 13, scope: !11) +!44 = !DILocation(line: 11, column: 18, scope: !11) +!45 = !DILocation(line: 11, column: 23, scope: !11) +!46 = !DILocation(line: 11, column: 3, scope: !11) diff --git a/llvm/test/CodeGen/SBF/CORE/intrinsic-fieldinfo-lshift-2.ll b/llvm/test/CodeGen/SBF/CORE/intrinsic-fieldinfo-lshift-2.ll new file mode 100644 index 0000000000000..a6395bbcac14e --- /dev/null +++ b/llvm/test/CodeGen/SBF/CORE/intrinsic-fieldinfo-lshift-2.ll @@ -0,0 +1,126 @@ +; RUN: opt -O2 %s | llvm-dis > %t1 +; RUN: llc -sbf-enable-btf-emission -filetype=asm -o - %t1 | FileCheck -check-prefixes=CHECK,CHECK-ALU64 %s +; RUN: llc -sbf-enable-btf-emission -mattr=+alu32 -filetype=asm -o - %t1 | FileCheck -check-prefixes=CHECK,CHECK-ALU32 %s +; Source code: +; typedef struct s1 { int a1; short a2; } __s1; +; union u1 { int b1; __s1 b2; }; +; enum { FIELD_LSHIFT_U64 = 4, }; +; int test(union u1 *arg) { +; unsigned r1 = __builtin_preserve_field_info(arg->b2.a1, FIELD_LSHIFT_U64); +; unsigned r2 = __builtin_preserve_field_info(arg->b2.a2, FIELD_LSHIFT_U64); +; /* big endian: r1: 32, r2: 48 */ +; /* little endian: r1: 32, r2: 48 */ +; return r1 + r2; +; } +; Compilation flag: +; clang -target bpf -O2 -g -S -emit-llvm -Xclang -disable-llvm-passes test.c + +target triple = "sbf" + +%union.u1 = type { %struct.s1 } +%struct.s1 = type { i32, i16 } + +; Function Attrs: nounwind readnone +define dso_local i32 @test(%union.u1* %arg) local_unnamed_addr #0 !dbg !11 { +entry: + call void @llvm.dbg.value(metadata %union.u1* %arg, metadata !27, metadata !DIExpression()), !dbg !30 + %0 = tail call %union.u1* @llvm.preserve.union.access.index.p0s_union.u1s.p0s_union.u1s(%union.u1* %arg, i32 1), !dbg !31, !llvm.preserve.access.index !16 + %b2 = getelementptr %union.u1, %union.u1* %0, i64 0, i32 0, !dbg !31 + %1 = tail call i32* @llvm.preserve.struct.access.index.p0i32.p0s_struct.s1s(%struct.s1* elementtype(%struct.s1) %b2, i32 0, i32 0), !dbg !32, !llvm.preserve.access.index !21 + %2 = tail call i32 @llvm.bpf.preserve.field.info.p0i32(i32* %1, i64 4), !dbg !33 + call void @llvm.dbg.value(metadata i32 %2, metadata !28, metadata !DIExpression()), !dbg !30 + %3 = tail call i16* @llvm.preserve.struct.access.index.p0i16.p0s_struct.s1s(%struct.s1* elementtype(%struct.s1) %b2, i32 1, i32 1), !dbg !34, !llvm.preserve.access.index !21 + %4 = tail call i32 @llvm.bpf.preserve.field.info.p0i16(i16* %3, i64 4), !dbg !35 + call void @llvm.dbg.value(metadata i32 %4, metadata !29, metadata !DIExpression()), !dbg !30 + %add = add i32 %4, %2, !dbg !36 + ret i32 %add, !dbg !37 +} + +; CHECK: mov64 r1, 32 +; CHECK: mov64 r0, 48 +; CHECK-ALU64: add64 r0, r1 +; CHECK-ALU32: add32 w0, w1 +; CHECK: exit + +; CHECK: .long 1 # BTF_KIND_UNION(id = 2) +; CHECK: .ascii "u1" # string offset=1 +; CHECK: .ascii ".text" # string offset=43 +; CHECK: .ascii "0:1:0" # string offset=49 +; CHECK: .ascii "0:1:1" # string offset=92 + +; CHECK: .long 16 # FieldReloc +; CHECK-NEXT: .long 43 # Field reloc section string offset=43 +; CHECK-NEXT: .long 2 +; CHECK-NEXT: .long .Ltmp{{[0-9]+}} +; CHECK-NEXT: .long 2 +; CHECK-NEXT: .long 49 +; CHECK-NEXT: .long 4 +; CHECK-NEXT: .long .Ltmp{{[0-9]+}} +; CHECK-NEXT: .long 2 +; CHECK-NEXT: .long 92 +; CHECK-NEXT: .long 4 + +; Function Attrs: nounwind readnone +declare %union.u1* @llvm.preserve.union.access.index.p0s_union.u1s.p0s_union.u1s(%union.u1*, i32) #1 + +; Function Attrs: nounwind readnone +declare i32* @llvm.preserve.struct.access.index.p0i32.p0s_struct.s1s(%struct.s1*, i32, i32) #1 + +; Function Attrs: nounwind readnone +declare i32 @llvm.bpf.preserve.field.info.p0i32(i32*, i64) #1 + +; Function Attrs: nounwind readnone +declare i16* @llvm.preserve.struct.access.index.p0i16.p0s_struct.s1s(%struct.s1*, i32, i32) #1 + +; Function Attrs: nounwind readnone +declare i32 @llvm.bpf.preserve.field.info.p0i16(i16*, i64) #1 + +; Function Attrs: nounwind readnone speculatable willreturn +declare void @llvm.dbg.value(metadata, metadata, metadata) #2 + +attributes #0 = { nounwind readnone "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" } +attributes #1 = { nounwind readnone } +attributes #2 = { nounwind readnone speculatable willreturn } + +!llvm.dbg.cu = !{!0} +!llvm.module.flags = !{!7, !8, !9} +!llvm.ident = !{!10} + +!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 10.0.0 (https://github.com/llvm/llvm-project.git 5635073377f153f7f2ff9b34c77af3c79885ff4a)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, nameTableKind: None) +!1 = !DIFile(filename: "test.c", directory: "/tmp/home/yhs/work/tests/core") +!2 = !{!3} +!3 = !DICompositeType(tag: DW_TAG_enumeration_type, file: !1, line: 3, baseType: !4, size: 32, elements: !5) +!4 = !DIBasicType(name: "unsigned int", size: 32, encoding: DW_ATE_unsigned) +!5 = !{!6} +!6 = !DIEnumerator(name: "FIELD_LSHIFT_U64", value: 4, isUnsigned: true) +!7 = !{i32 2, !"Dwarf Version", i32 4} +!8 = !{i32 2, !"Debug Info Version", i32 3} +!9 = !{i32 1, !"wchar_size", i32 4} +!10 = !{!"clang version 10.0.0 (https://github.com/llvm/llvm-project.git 5635073377f153f7f2ff9b34c77af3c79885ff4a)"} +!11 = distinct !DISubprogram(name: "test", scope: !1, file: !1, line: 4, type: !12, scopeLine: 4, flags: DIFlagPrototyped, isDefinition: true, isOptimized: true, unit: !0, retainedNodes: !26) +!12 = !DISubroutineType(types: !13) +!13 = !{!14, !15} +!14 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +!15 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !16, size: 64) +!16 = distinct !DICompositeType(tag: DW_TAG_union_type, name: "u1", file: !1, line: 2, size: 64, elements: !17) +!17 = !{!18, !19} +!18 = !DIDerivedType(tag: DW_TAG_member, name: "b1", scope: !16, file: !1, line: 2, baseType: !14, size: 32) +!19 = !DIDerivedType(tag: DW_TAG_member, name: "b2", scope: !16, file: !1, line: 2, baseType: !20, size: 64) +!20 = !DIDerivedType(tag: DW_TAG_typedef, name: "__s1", file: !1, line: 1, baseType: !21) +!21 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "s1", file: !1, line: 1, size: 64, elements: !22) +!22 = !{!23, !24} +!23 = !DIDerivedType(tag: DW_TAG_member, name: "a1", scope: !21, file: !1, line: 1, baseType: !14, size: 32) +!24 = !DIDerivedType(tag: DW_TAG_member, name: "a2", scope: !21, file: !1, line: 1, baseType: !25, size: 16, offset: 32) +!25 = !DIBasicType(name: "short", size: 16, encoding: DW_ATE_signed) +!26 = !{!27, !28, !29} +!27 = !DILocalVariable(name: "arg", arg: 1, scope: !11, file: !1, line: 4, type: !15) +!28 = !DILocalVariable(name: "r1", scope: !11, file: !1, line: 5, type: !4) +!29 = !DILocalVariable(name: "r2", scope: !11, file: !1, line: 6, type: !4) +!30 = !DILocation(line: 0, scope: !11) +!31 = !DILocation(line: 5, column: 52, scope: !11) +!32 = !DILocation(line: 5, column: 55, scope: !11) +!33 = !DILocation(line: 5, column: 17, scope: !11) +!34 = !DILocation(line: 6, column: 55, scope: !11) +!35 = !DILocation(line: 6, column: 17, scope: !11) +!36 = !DILocation(line: 9, column: 13, scope: !11) +!37 = !DILocation(line: 9, column: 3, scope: !11) diff --git a/llvm/test/CodeGen/SBF/CORE/intrinsic-fieldinfo-rshift-1.ll b/llvm/test/CodeGen/SBF/CORE/intrinsic-fieldinfo-rshift-1.ll new file mode 100644 index 0000000000000..18dcfced25e66 --- /dev/null +++ b/llvm/test/CodeGen/SBF/CORE/intrinsic-fieldinfo-rshift-1.ll @@ -0,0 +1,154 @@ +; RUN: opt -O2 %s | llvm-dis > %t1 +; RUN: llc -sbf-enable-btf-emission -filetype=asm -o - %t1 | FileCheck -check-prefixes=CHECK,CHECK-ALU64 %s +; RUN: llc -sbf-enable-btf-emission -mattr=+alu32 -filetype=asm -o - %t1 | FileCheck -check-prefixes=CHECK,CHECK-ALU32 %s +; Source code: +; typedef struct s1 { int a1:7; int a2:4; int a3:5; int a4:16;} __s1; +; union u1 { int b1; __s1 b2; }; +; enum { FIELD_RSHIFT_U64 = 5, }; +; int test(union u1 *arg) { +; unsigned r1 = __builtin_preserve_field_info(arg->b2.a1, FIELD_RSHIFT_U64); +; unsigned r2 = __builtin_preserve_field_info(arg->b2.a2, FIELD_RSHIFT_U64); +; unsigned r3 = __builtin_preserve_field_info(arg->b2.a3, FIELD_RSHIFT_U64); +; unsigned r4 = __builtin_preserve_field_info(arg->b2.a4, FIELD_RSHIFT_U64); +; /* r1: 57, r2: 60, r3: 59, r4: 48 */ +; return r1 + r2 + r3 + r4; +; } +; Compilation flag: +; clang -target bpf -O2 -g -S -emit-llvm -Xclang -disable-llvm-passes test.c + +target triple = "sbf" + +%union.u1 = type { i32 } +%struct.s1 = type { i32 } + +; Function Attrs: nounwind readnone +define dso_local i32 @test(%union.u1* %arg) local_unnamed_addr #0 !dbg !11 { +entry: + call void @llvm.dbg.value(metadata %union.u1* %arg, metadata !28, metadata !DIExpression()), !dbg !33 + %0 = tail call %union.u1* @llvm.preserve.union.access.index.p0s_union.u1s.p0s_union.u1s(%union.u1* %arg, i32 1), !dbg !34, !llvm.preserve.access.index !16 + %b2 = bitcast %union.u1* %0 to %struct.s1*, !dbg !34 + %1 = tail call i32* @llvm.preserve.struct.access.index.p0i32.p0s_struct.s1s(%struct.s1* elementtype(%struct.s1) %b2, i32 0, i32 0), !dbg !35, !llvm.preserve.access.index !21 + %2 = tail call i32 @llvm.bpf.preserve.field.info.p0i32(i32* %1, i64 5), !dbg !36 + call void @llvm.dbg.value(metadata i32 %2, metadata !29, metadata !DIExpression()), !dbg !33 + %3 = tail call i32* @llvm.preserve.struct.access.index.p0i32.p0s_struct.s1s(%struct.s1* elementtype(%struct.s1) %b2, i32 0, i32 1), !dbg !37, !llvm.preserve.access.index !21 + %4 = tail call i32 @llvm.bpf.preserve.field.info.p0i32(i32* %3, i64 5), !dbg !38 + call void @llvm.dbg.value(metadata i32 %4, metadata !30, metadata !DIExpression()), !dbg !33 + %5 = tail call i32* @llvm.preserve.struct.access.index.p0i32.p0s_struct.s1s(%struct.s1* elementtype(%struct.s1) %b2, i32 0, i32 2), !dbg !39, !llvm.preserve.access.index !21 + %6 = tail call i32 @llvm.bpf.preserve.field.info.p0i32(i32* %5, i64 5), !dbg !40 + call void @llvm.dbg.value(metadata i32 %6, metadata !31, metadata !DIExpression()), !dbg !33 + %7 = tail call i32* @llvm.preserve.struct.access.index.p0i32.p0s_struct.s1s(%struct.s1* elementtype(%struct.s1) %b2, i32 0, i32 3), !dbg !41, !llvm.preserve.access.index !21 + %8 = tail call i32 @llvm.bpf.preserve.field.info.p0i32(i32* %7, i64 5), !dbg !42 + call void @llvm.dbg.value(metadata i32 %8, metadata !32, metadata !DIExpression()), !dbg !33 + %add = add i32 %4, %2, !dbg !43 + %add4 = add i32 %add, %6, !dbg !44 + %add5 = add i32 %add4, %8, !dbg !45 + ret i32 %add5, !dbg !46 +} + +; CHECK: mov64 r1, 57 +; CHECK: mov64 r0, 60 +; CHECK-ALU64: add64 r0, r1 +; CHECK-ALU32: add32 w0, w1 +; CHECK: mov64 r1, 59 +; CHECK-ALU64: add64 r0, r1 +; CHECK-ALU32: add32 w0, w1 +; CHECK: mov64 r1, 48 +; CHECK-ALU64: add64 r0, r1 +; CHECK-ALU32: add32 w0, w1 +; CHECK: exit + +; CHECK: .long 1 # BTF_KIND_UNION(id = 2) +; CHECK: .ascii "u1" # string offset=1 +; CHECK: .ascii ".text" # string offset=43 +; CHECK: .ascii "0:1:0" # string offset=49 +; CHECK: .ascii "0:1:1" # string offset=92 +; CHECK: .ascii "0:1:2" # string offset=98 +; CHECK: .ascii "0:1:3" # string offset=104 + +; CHECK: .long 16 # FieldReloc +; CHECK-NEXT: .long 43 # Field reloc section string offset=43 +; CHECK-NEXT: .long 4 +; CHECK-NEXT: .long .Ltmp{{[0-9]+}} +; CHECK-NEXT: .long 2 +; CHECK-NEXT: .long 49 +; CHECK-NEXT: .long 5 +; CHECK-NEXT: .long .Ltmp{{[0-9]+}} +; CHECK-NEXT: .long 2 +; CHECK-NEXT: .long 92 +; CHECK-NEXT: .long 5 +; CHECK-NEXT: .long .Ltmp{{[0-9]+}} +; CHECK-NEXT: .long 2 +; CHECK-NEXT: .long 98 +; CHECK-NEXT: .long 5 +; CHECK-NEXT: .long .Ltmp{{[0-9]+}} +; CHECK-NEXT: .long 2 +; CHECK-NEXT: .long 104 +; CHECK-NEXT: .long 5 + +; Function Attrs: nounwind readnone +declare %union.u1* @llvm.preserve.union.access.index.p0s_union.u1s.p0s_union.u1s(%union.u1*, i32) #1 + +; Function Attrs: nounwind readnone +declare i32* @llvm.preserve.struct.access.index.p0i32.p0s_struct.s1s(%struct.s1*, i32, i32) #1 + +; Function Attrs: nounwind readnone +declare i32 @llvm.bpf.preserve.field.info.p0i32(i32*, i64) #1 + +; Function Attrs: nounwind readnone speculatable willreturn +declare void @llvm.dbg.value(metadata, metadata, metadata) #2 + +attributes #0 = { nounwind readnone "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" } +attributes #1 = { nounwind readnone } +attributes #2 = { nounwind readnone speculatable willreturn } + +!llvm.dbg.cu = !{!0} +!llvm.module.flags = !{!7, !8, !9} +!llvm.ident = !{!10} + +!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 10.0.0 (https://github.com/llvm/llvm-project.git 4a60741b74384f14b21fdc0131ede326438840ab)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, nameTableKind: None) +!1 = !DIFile(filename: "test.c", directory: "/tmp/home/yhs/work/tests/core") +!2 = !{!3} +!3 = !DICompositeType(tag: DW_TAG_enumeration_type, file: !1, line: 3, baseType: !4, size: 32, elements: !5) +!4 = !DIBasicType(name: "unsigned int", size: 32, encoding: DW_ATE_unsigned) +!5 = !{!6} +!6 = !DIEnumerator(name: "FIELD_RSHIFT_U64", value: 5, isUnsigned: true) +!7 = !{i32 2, !"Dwarf Version", i32 4} +!8 = !{i32 2, !"Debug Info Version", i32 3} +!9 = !{i32 1, !"wchar_size", i32 4} +!10 = !{!"clang version 10.0.0 (https://github.com/llvm/llvm-project.git 4a60741b74384f14b21fdc0131ede326438840ab)"} +!11 = distinct !DISubprogram(name: "test", scope: !1, file: !1, line: 4, type: !12, scopeLine: 4, flags: DIFlagPrototyped, isDefinition: true, isOptimized: true, unit: !0, retainedNodes: !27) +!12 = !DISubroutineType(types: !13) +!13 = !{!14, !15} +!14 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +!15 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !16, size: 64) +!16 = distinct !DICompositeType(tag: DW_TAG_union_type, name: "u1", file: !1, line: 2, size: 32, elements: !17) +!17 = !{!18, !19} +!18 = !DIDerivedType(tag: DW_TAG_member, name: "b1", scope: !16, file: !1, line: 2, baseType: !14, size: 32) +!19 = !DIDerivedType(tag: DW_TAG_member, name: "b2", scope: !16, file: !1, line: 2, baseType: !20, size: 32) +!20 = !DIDerivedType(tag: DW_TAG_typedef, name: "__s1", file: !1, line: 1, baseType: !21) +!21 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "s1", file: !1, line: 1, size: 32, elements: !22) +!22 = !{!23, !24, !25, !26} +!23 = !DIDerivedType(tag: DW_TAG_member, name: "a1", scope: !21, file: !1, line: 1, baseType: !14, size: 7, flags: DIFlagBitField, extraData: i64 0) +!24 = !DIDerivedType(tag: DW_TAG_member, name: "a2", scope: !21, file: !1, line: 1, baseType: !14, size: 4, offset: 7, flags: DIFlagBitField, extraData: i64 0) +!25 = !DIDerivedType(tag: DW_TAG_member, name: "a3", scope: !21, file: !1, line: 1, baseType: !14, size: 5, offset: 11, flags: DIFlagBitField, extraData: i64 0) +!26 = !DIDerivedType(tag: DW_TAG_member, name: "a4", scope: !21, file: !1, line: 1, baseType: !14, size: 16, offset: 16, flags: DIFlagBitField, extraData: i64 0) +!27 = !{!28, !29, !30, !31, !32} +!28 = !DILocalVariable(name: "arg", arg: 1, scope: !11, file: !1, line: 4, type: !15) +!29 = !DILocalVariable(name: "r1", scope: !11, file: !1, line: 5, type: !4) +!30 = !DILocalVariable(name: "r2", scope: !11, file: !1, line: 6, type: !4) +!31 = !DILocalVariable(name: "r3", scope: !11, file: !1, line: 7, type: !4) +!32 = !DILocalVariable(name: "r4", scope: !11, file: !1, line: 8, type: !4) +!33 = !DILocation(line: 0, scope: !11) +!34 = !DILocation(line: 5, column: 52, scope: !11) +!35 = !DILocation(line: 5, column: 55, scope: !11) +!36 = !DILocation(line: 5, column: 17, scope: !11) +!37 = !DILocation(line: 6, column: 55, scope: !11) +!38 = !DILocation(line: 6, column: 17, scope: !11) +!39 = !DILocation(line: 7, column: 55, scope: !11) +!40 = !DILocation(line: 7, column: 17, scope: !11) +!41 = !DILocation(line: 8, column: 55, scope: !11) +!42 = !DILocation(line: 8, column: 17, scope: !11) +!43 = !DILocation(line: 10, column: 13, scope: !11) +!44 = !DILocation(line: 10, column: 18, scope: !11) +!45 = !DILocation(line: 10, column: 23, scope: !11) +!46 = !DILocation(line: 10, column: 3, scope: !11) diff --git a/llvm/test/CodeGen/SBF/CORE/intrinsic-fieldinfo-rshift-2.ll b/llvm/test/CodeGen/SBF/CORE/intrinsic-fieldinfo-rshift-2.ll new file mode 100644 index 0000000000000..f09d71daef90d --- /dev/null +++ b/llvm/test/CodeGen/SBF/CORE/intrinsic-fieldinfo-rshift-2.ll @@ -0,0 +1,125 @@ +; RUN: opt -O2 %s | llvm-dis > %t1 +; RUN: llc -sbf-enable-btf-emission -filetype=asm -o - %t1 | FileCheck -check-prefixes=CHECK,CHECK-ALU64 %s +; RUN: llc -sbf-enable-btf-emission -mattr=+alu32 -filetype=asm -o - %t1 | FileCheck -check-prefixes=CHECK,CHECK-ALU32 %s +; Source code: +; typedef struct s1 { int a1; char a2; } __s1; +; union u1 { int b1; __s1 b2; }; +; enum { FIELD_RSHIFT_U64 = 5, }; +; int test(union u1 *arg) { +; unsigned r1 = __builtin_preserve_field_info(arg->b2.a1, FIELD_RSHIFT_U64); +; unsigned r2 = __builtin_preserve_field_info(arg->b2.a2, FIELD_RSHIFT_U64); +; /* r1: 32, r2: 56 */ +; return r1 + r2; +; } +; Compilation flag: +; clang -target bpf -O2 -g -S -emit-llvm -Xclang -disable-llvm-passes test.c + +target triple = "sbf" + +%union.u1 = type { %struct.s1 } +%struct.s1 = type { i32, i8 } + +; Function Attrs: nounwind readnone +define dso_local i32 @test(%union.u1* %arg) local_unnamed_addr #0 !dbg !11 { +entry: + call void @llvm.dbg.value(metadata %union.u1* %arg, metadata !27, metadata !DIExpression()), !dbg !30 + %0 = tail call %union.u1* @llvm.preserve.union.access.index.p0s_union.u1s.p0s_union.u1s(%union.u1* %arg, i32 1), !dbg !31, !llvm.preserve.access.index !16 + %b2 = getelementptr inbounds %union.u1, %union.u1* %0, i64 0, i32 0, !dbg !31 + %1 = tail call i32* @llvm.preserve.struct.access.index.p0i32.p0s_struct.s1s(%struct.s1* elementtype(%struct.s1) %b2, i32 0, i32 0), !dbg !32, !llvm.preserve.access.index !21 + %2 = tail call i32 @llvm.bpf.preserve.field.info.p0i32(i32* %1, i64 5), !dbg !33 + call void @llvm.dbg.value(metadata i32 %2, metadata !28, metadata !DIExpression()), !dbg !30 + %3 = tail call i8* @llvm.preserve.struct.access.index.p0i8.p0s_struct.s1s(%struct.s1* elementtype(%struct.s1) %b2, i32 1, i32 1), !dbg !34, !llvm.preserve.access.index !21 + %4 = tail call i32 @llvm.bpf.preserve.field.info.p0i8(i8* %3, i64 5), !dbg !35 + call void @llvm.dbg.value(metadata i32 %4, metadata !29, metadata !DIExpression()), !dbg !30 + %add = add i32 %4, %2, !dbg !36 + ret i32 %add, !dbg !37 +} + +; CHECK: mov64 r1, 32 +; CHECK: mov64 r0, 56 +; CHECK-ALU64: add64 r0, r1 +; CHECK-ALU32: add32 w0, w1 +; CHECK: exit + +; CHECK: .long 1 # BTF_KIND_UNION(id = 2) +; CHECK: .ascii "u1" # string offset=1 +; CHECK: .ascii ".text" # string offset=42 +; CHECK: .ascii "0:1:0" # string offset=48 +; CHECK: .ascii "0:1:1" # string offset=91 + +; CHECK: .long 16 # FieldReloc +; CHECK-NEXT: .long 42 # Field reloc section string offset=42 +; CHECK-NEXT: .long 2 +; CHECK-NEXT: .long .Ltmp{{[0-9]+}} +; CHECK-NEXT: .long 2 +; CHECK-NEXT: .long 48 +; CHECK-NEXT: .long 5 +; CHECK-NEXT: .long .Ltmp{{[0-9]+}} +; CHECK-NEXT: .long 2 +; CHECK-NEXT: .long 91 +; CHECK-NEXT: .long 5 + +; Function Attrs: nounwind readnone +declare %union.u1* @llvm.preserve.union.access.index.p0s_union.u1s.p0s_union.u1s(%union.u1*, i32) #1 + +; Function Attrs: nounwind readnone +declare i32* @llvm.preserve.struct.access.index.p0i32.p0s_struct.s1s(%struct.s1*, i32, i32) #1 + +; Function Attrs: nounwind readnone +declare i32 @llvm.bpf.preserve.field.info.p0i32(i32*, i64) #1 + +; Function Attrs: nounwind readnone +declare i8* @llvm.preserve.struct.access.index.p0i8.p0s_struct.s1s(%struct.s1*, i32, i32) #1 + +; Function Attrs: nounwind readnone +declare i32 @llvm.bpf.preserve.field.info.p0i8(i8*, i64) #1 + +; Function Attrs: nounwind readnone speculatable willreturn +declare void @llvm.dbg.value(metadata, metadata, metadata) #2 + +attributes #0 = { nounwind readnone "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" } +attributes #1 = { nounwind readnone } +attributes #2 = { nounwind readnone speculatable willreturn } + +!llvm.dbg.cu = !{!0} +!llvm.module.flags = !{!7, !8, !9} +!llvm.ident = !{!10} + +!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 10.0.0 (https://github.com/llvm/llvm-project.git 4a60741b74384f14b21fdc0131ede326438840ab)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, nameTableKind: None) +!1 = !DIFile(filename: "test.c", directory: "/tmp/home/yhs/work/tests/core") +!2 = !{!3} +!3 = !DICompositeType(tag: DW_TAG_enumeration_type, file: !1, line: 3, baseType: !4, size: 32, elements: !5) +!4 = !DIBasicType(name: "unsigned int", size: 32, encoding: DW_ATE_unsigned) +!5 = !{!6} +!6 = !DIEnumerator(name: "FIELD_RSHIFT_U64", value: 5, isUnsigned: true) +!7 = !{i32 2, !"Dwarf Version", i32 4} +!8 = !{i32 2, !"Debug Info Version", i32 3} +!9 = !{i32 1, !"wchar_size", i32 4} +!10 = !{!"clang version 10.0.0 (https://github.com/llvm/llvm-project.git 4a60741b74384f14b21fdc0131ede326438840ab)"} +!11 = distinct !DISubprogram(name: "test", scope: !1, file: !1, line: 4, type: !12, scopeLine: 4, flags: DIFlagPrototyped, isDefinition: true, isOptimized: true, unit: !0, retainedNodes: !26) +!12 = !DISubroutineType(types: !13) +!13 = !{!14, !15} +!14 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +!15 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !16, size: 64) +!16 = distinct !DICompositeType(tag: DW_TAG_union_type, name: "u1", file: !1, line: 2, size: 64, elements: !17) +!17 = !{!18, !19} +!18 = !DIDerivedType(tag: DW_TAG_member, name: "b1", scope: !16, file: !1, line: 2, baseType: !14, size: 32) +!19 = !DIDerivedType(tag: DW_TAG_member, name: "b2", scope: !16, file: !1, line: 2, baseType: !20, size: 64) +!20 = !DIDerivedType(tag: DW_TAG_typedef, name: "__s1", file: !1, line: 1, baseType: !21) +!21 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "s1", file: !1, line: 1, size: 64, elements: !22) +!22 = !{!23, !24} +!23 = !DIDerivedType(tag: DW_TAG_member, name: "a1", scope: !21, file: !1, line: 1, baseType: !14, size: 32) +!24 = !DIDerivedType(tag: DW_TAG_member, name: "a2", scope: !21, file: !1, line: 1, baseType: !25, size: 8, offset: 32) +!25 = !DIBasicType(name: "char", size: 8, encoding: DW_ATE_signed_char) +!26 = !{!27, !28, !29} +!27 = !DILocalVariable(name: "arg", arg: 1, scope: !11, file: !1, line: 4, type: !15) +!28 = !DILocalVariable(name: "r1", scope: !11, file: !1, line: 5, type: !4) +!29 = !DILocalVariable(name: "r2", scope: !11, file: !1, line: 6, type: !4) +!30 = !DILocation(line: 0, scope: !11) +!31 = !DILocation(line: 5, column: 52, scope: !11) +!32 = !DILocation(line: 5, column: 55, scope: !11) +!33 = !DILocation(line: 5, column: 17, scope: !11) +!34 = !DILocation(line: 6, column: 55, scope: !11) +!35 = !DILocation(line: 6, column: 17, scope: !11) +!36 = !DILocation(line: 8, column: 13, scope: !11) +!37 = !DILocation(line: 8, column: 3, scope: !11) diff --git a/llvm/test/CodeGen/SBF/CORE/intrinsic-fieldinfo-rshift-3.ll b/llvm/test/CodeGen/SBF/CORE/intrinsic-fieldinfo-rshift-3.ll new file mode 100644 index 0000000000000..5d2cdf5604395 --- /dev/null +++ b/llvm/test/CodeGen/SBF/CORE/intrinsic-fieldinfo-rshift-3.ll @@ -0,0 +1,135 @@ +; RUN: opt -O2 %s | llvm-dis > %t1 +; RUN: llc -sbf-enable-btf-emission -filetype=asm -o - %t1 | FileCheck -check-prefixes=CHECK,CHECK-ALU64 %s +; RUN: llc -sbf-enable-btf-emission -mattr=+alu32 -filetype=asm -o - %t1 | FileCheck -check-prefixes=CHECK,CHECK-ALU32 %s +; Source code: +; typedef struct s1 { char a1 [5][5]; } __s1; +; union u1 { int b1; __s1 b2; }; +; enum { FIELD_RSHIFT_U64 = 5, }; +; int test(union u1 *arg) { +; unsigned r1 = __builtin_preserve_field_info(arg->b2.a1[3], FIELD_RSHIFT_U64); +; unsigned r2 = __builtin_preserve_field_info(arg->b2.a1[3][3], FIELD_RSHIFT_U64); +; /* r1 : 24, r2 : 56 */ +; return r1 + r2; +; } +; Compilation flag: +; clang -target bpf -O2 -g -S -emit-llvm -Xclang -disable-llvm-passes test.c + +target triple = "sbf" + +%union.u1 = type { i32, [24 x i8] } +%struct.s1 = type { [5 x [5 x i8]] } + +; Function Attrs: nounwind readnone +define dso_local i32 @test(%union.u1* %arg) local_unnamed_addr #0 !dbg !18 { +entry: + call void @llvm.dbg.value(metadata %union.u1* %arg, metadata !32, metadata !DIExpression()), !dbg !35 + %0 = tail call %union.u1* @llvm.preserve.union.access.index.p0s_union.u1s.p0s_union.u1s(%union.u1* %arg, i32 1), !dbg !36, !llvm.preserve.access.index !23 + %b2 = bitcast %union.u1* %0 to %struct.s1*, !dbg !36 + %1 = tail call [5 x [5 x i8]]* @llvm.preserve.struct.access.index.p0a5a5i8.p0s_struct.s1s(%struct.s1* elementtype(%struct.s1) %b2, i32 0, i32 0), !dbg !37, !llvm.preserve.access.index !28 + %2 = tail call [5 x i8]* @llvm.preserve.array.access.index.p0a5i8.p0a5a5i8([5 x [5 x i8]]* elementtype([5 x [5 x i8]]) %1, i32 1, i32 3), !dbg !38, !llvm.preserve.access.index !8 + %3 = tail call i32 @llvm.bpf.preserve.field.info.p0a5i8([5 x i8]* %2, i64 5), !dbg !39 + call void @llvm.dbg.value(metadata i32 %3, metadata !33, metadata !DIExpression()), !dbg !35 + %4 = tail call i8* @llvm.preserve.array.access.index.p0i8.p0a5i8([5 x i8]* elementtype([5 x i8]) %2, i32 1, i32 3), !dbg !40, !llvm.preserve.access.index !12 + %5 = tail call i32 @llvm.bpf.preserve.field.info.p0i8(i8* %4, i64 5), !dbg !41 + call void @llvm.dbg.value(metadata i32 %5, metadata !34, metadata !DIExpression()), !dbg !35 + %add = add i32 %5, %3, !dbg !42 + ret i32 %add, !dbg !43 +} + +; CHECK: mov64 r1, 24 +; CHECK: mov64 r0, 56 +; CHECK-ALU64: add64 r0, r1 +; CHECK-ALU32: add32 w0, w1 +; CHECK: exit + +; CHECK: .long 1 # BTF_KIND_UNION(id = 2) +; CHECK: .ascii "u1" # string offset=1 +; CHECK: .ascii ".text" # string offset=59 +; CHECK: .ascii "0:1:0:3" # string offset=65 +; CHECK: .ascii "0:1:0:3:3" # string offset=110 + +; CHECK: .long 16 # FieldReloc +; CHECK-NEXT: .long 59 # Field reloc section string offset=59 +; CHECK-NEXT: .long 2 +; CHECK-NEXT: .long .Ltmp{{[0-9]+}} +; CHECK-NEXT: .long 2 +; CHECK-NEXT: .long 65 +; CHECK-NEXT: .long 5 +; CHECK-NEXT: .long .Ltmp{{[0-9]+}} +; CHECK-NEXT: .long 2 +; CHECK-NEXT: .long 110 +; CHECK-NEXT: .long 5 + +; Function Attrs: nounwind readnone +declare %union.u1* @llvm.preserve.union.access.index.p0s_union.u1s.p0s_union.u1s(%union.u1*, i32) #1 + +; Function Attrs: nounwind readnone +declare [5 x [5 x i8]]* @llvm.preserve.struct.access.index.p0a5a5i8.p0s_struct.s1s(%struct.s1*, i32, i32) #1 + +; Function Attrs: nounwind readnone +declare [5 x i8]* @llvm.preserve.array.access.index.p0a5i8.p0a5a5i8([5 x [5 x i8]]*, i32, i32) #1 + +; Function Attrs: nounwind readnone +declare i32 @llvm.bpf.preserve.field.info.p0a5i8([5 x i8]*, i64) #1 + +; Function Attrs: nounwind readnone +declare i8* @llvm.preserve.array.access.index.p0i8.p0a5i8([5 x i8]*, i32, i32) #1 + +; Function Attrs: nounwind readnone +declare i32 @llvm.bpf.preserve.field.info.p0i8(i8*, i64) #1 + +; Function Attrs: nounwind readnone speculatable willreturn +declare void @llvm.dbg.value(metadata, metadata, metadata) #2 + +attributes #0 = { nounwind readnone "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" } +attributes #1 = { nounwind readnone } +attributes #2 = { nounwind readnone speculatable willreturn } + +!llvm.dbg.cu = !{!0} +!llvm.module.flags = !{!14, !15, !16} +!llvm.ident = !{!17} + +!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 10.0.0 (https://github.com/llvm/llvm-project.git c1e02f16f1105ffaf1c35ee8bc38b7d6db5c6ea9)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, retainedTypes: !7, nameTableKind: None) +!1 = !DIFile(filename: "test.c", directory: "/tmp/home/yhs/work/tests/core") +!2 = !{!3} +!3 = !DICompositeType(tag: DW_TAG_enumeration_type, file: !1, line: 3, baseType: !4, size: 32, elements: !5) +!4 = !DIBasicType(name: "unsigned int", size: 32, encoding: DW_ATE_unsigned) +!5 = !{!6} +!6 = !DIEnumerator(name: "FIELD_RSHIFT_U64", value: 5, isUnsigned: true) +!7 = !{!8, !12} +!8 = !DICompositeType(tag: DW_TAG_array_type, baseType: !9, size: 200, elements: !10) +!9 = !DIBasicType(name: "char", size: 8, encoding: DW_ATE_signed_char) +!10 = !{!11, !11} +!11 = !DISubrange(count: 5) +!12 = !DICompositeType(tag: DW_TAG_array_type, baseType: !9, size: 40, elements: !13) +!13 = !{!11} +!14 = !{i32 2, !"Dwarf Version", i32 4} +!15 = !{i32 2, !"Debug Info Version", i32 3} +!16 = !{i32 1, !"wchar_size", i32 4} +!17 = !{!"clang version 10.0.0 (https://github.com/llvm/llvm-project.git c1e02f16f1105ffaf1c35ee8bc38b7d6db5c6ea9)"} +!18 = distinct !DISubprogram(name: "test", scope: !1, file: !1, line: 4, type: !19, scopeLine: 4, flags: DIFlagPrototyped, isDefinition: true, isOptimized: true, unit: !0, retainedNodes: !31) +!19 = !DISubroutineType(types: !20) +!20 = !{!21, !22} +!21 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +!22 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !23, size: 64) +!23 = distinct !DICompositeType(tag: DW_TAG_union_type, name: "u1", file: !1, line: 2, size: 224, elements: !24) +!24 = !{!25, !26} +!25 = !DIDerivedType(tag: DW_TAG_member, name: "b1", scope: !23, file: !1, line: 2, baseType: !21, size: 32) +!26 = !DIDerivedType(tag: DW_TAG_member, name: "b2", scope: !23, file: !1, line: 2, baseType: !27, size: 200) +!27 = !DIDerivedType(tag: DW_TAG_typedef, name: "__s1", file: !1, line: 1, baseType: !28) +!28 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "s1", file: !1, line: 1, size: 200, elements: !29) +!29 = !{!30} +!30 = !DIDerivedType(tag: DW_TAG_member, name: "a1", scope: !28, file: !1, line: 1, baseType: !8, size: 200) +!31 = !{!32, !33, !34} +!32 = !DILocalVariable(name: "arg", arg: 1, scope: !18, file: !1, line: 4, type: !22) +!33 = !DILocalVariable(name: "r1", scope: !18, file: !1, line: 5, type: !4) +!34 = !DILocalVariable(name: "r2", scope: !18, file: !1, line: 6, type: !4) +!35 = !DILocation(line: 0, scope: !18) +!36 = !DILocation(line: 5, column: 52, scope: !18) +!37 = !DILocation(line: 5, column: 55, scope: !18) +!38 = !DILocation(line: 5, column: 47, scope: !18) +!39 = !DILocation(line: 5, column: 17, scope: !18) +!40 = !DILocation(line: 6, column: 47, scope: !18) +!41 = !DILocation(line: 6, column: 17, scope: !18) +!42 = !DILocation(line: 8, column: 13, scope: !18) +!43 = !DILocation(line: 8, column: 3, scope: !18) diff --git a/llvm/test/CodeGen/SBF/CORE/intrinsic-fieldinfo-signedness-1.ll b/llvm/test/CodeGen/SBF/CORE/intrinsic-fieldinfo-signedness-1.ll new file mode 100644 index 0000000000000..1479fdabb3b9f --- /dev/null +++ b/llvm/test/CodeGen/SBF/CORE/intrinsic-fieldinfo-signedness-1.ll @@ -0,0 +1,168 @@ +; RUN: opt -O2 %s | llvm-dis > %t1 +; RUN: llc -sbf-enable-btf-emission -filetype=asm -o - %t1 | FileCheck -check-prefixes=CHECK,CHECK-ALU64 %s +; RUN: llc -sbf-enable-btf-emission -mattr=+alu32 -filetype=asm -o - %t1 | FileCheck -check-prefixes=CHECK,CHECK-ALU32 %s +; Source code: +; typedef unsigned __uint; +; struct s1 { int a1; __uint a2:9; __uint a3:4; }; +; union u1 { int b1; __uint b2:9; __uint b3:4; }; +; enum { FIELD_SIGNEDNESS = 3, }; +; int test(struct s1 *arg1, union u1 *arg2) { +; unsigned r1 = __builtin_preserve_field_info(arg1->a1, FIELD_SIGNEDNESS); +; unsigned r2 = __builtin_preserve_field_info(arg1->a3, FIELD_SIGNEDNESS); +; unsigned r3 = __builtin_preserve_field_info(arg2->b1, FIELD_SIGNEDNESS); +; unsigned r4 = __builtin_preserve_field_info(arg2->b3, FIELD_SIGNEDNESS); +; return r1 + r2 + r3 + r4; +; } +; Compilation flag: +; clang -target bpf -O2 -g -S -emit-llvm -Xclang -disable-llvm-passes test.c + +target triple = "sbf" + +%struct.s1 = type { i32, i16 } +%union.u1 = type { i32 } + +; Function Attrs: nounwind readnone +define dso_local i32 @test(%struct.s1* %arg1, %union.u1* %arg2) local_unnamed_addr #0 !dbg !11 { +entry: + call void @llvm.dbg.value(metadata %struct.s1* %arg1, metadata !29, metadata !DIExpression()), !dbg !35 + call void @llvm.dbg.value(metadata %union.u1* %arg2, metadata !30, metadata !DIExpression()), !dbg !35 + %0 = tail call i32* @llvm.preserve.struct.access.index.p0i32.p0s_struct.s1s(%struct.s1* elementtype(%struct.s1) %arg1, i32 0, i32 0), !dbg !36, !llvm.preserve.access.index !16 + %1 = tail call i32 @llvm.bpf.preserve.field.info.p0i32(i32* %0, i64 3), !dbg !37 + call void @llvm.dbg.value(metadata i32 %1, metadata !31, metadata !DIExpression()), !dbg !35 + %2 = tail call i16* @llvm.preserve.struct.access.index.p0i16.p0s_struct.s1s(%struct.s1* elementtype(%struct.s1) %arg1, i32 1, i32 2), !dbg !38, !llvm.preserve.access.index !16 + %3 = tail call i32 @llvm.bpf.preserve.field.info.p0i16(i16* %2, i64 3), !dbg !39 + call void @llvm.dbg.value(metadata i32 %3, metadata !32, metadata !DIExpression()), !dbg !35 + %4 = tail call %union.u1* @llvm.preserve.union.access.index.p0s_union.u1s.p0s_union.u1s(%union.u1* %arg2, i32 0), !dbg !40, !llvm.preserve.access.index !23 + %b1 = getelementptr inbounds %union.u1, %union.u1* %4, i64 0, i32 0, !dbg !40 + %5 = tail call i32 @llvm.bpf.preserve.field.info.p0i32(i32* %b1, i64 3), !dbg !41 + call void @llvm.dbg.value(metadata i32 %5, metadata !33, metadata !DIExpression()), !dbg !35 + %6 = tail call i32* @llvm.preserve.struct.access.index.p0i32.p0s_union.u1s(%union.u1* elementtype(%union.u1) %arg2, i32 0, i32 2), !dbg !42, !llvm.preserve.access.index !23 + %7 = bitcast i32* %6 to i8*, !dbg !42 + %8 = tail call i32 @llvm.bpf.preserve.field.info.p0i8(i8* %7, i64 3), !dbg !43 + call void @llvm.dbg.value(metadata i32 %8, metadata !34, metadata !DIExpression()), !dbg !35 + %add = add i32 %3, %1, !dbg !44 + %add1 = add i32 %add, %5, !dbg !45 + %add2 = add i32 %add1, %8, !dbg !46 + ret i32 %add2, !dbg !47 +} + +; CHECK: mov64 r1, 1 +; CHECK: mov64 r0, 0 +; CHECK-ALU64: add64 r0, r1 +; CHECK-ALU32: add32 w0, w1 +; CHECK: mov64 r1, 1 +; CHECK-ALU64: add64 r0, r1 +; CHECK-ALU32: add32 w0, w1 +; CHECK: mov64 r1, 0 +; CHECK-ALU64: add64 r0, r1 +; CHECK-ALU32: add32 w0, w1 +; CHECK: exit + +; CHECK: .long 1 # BTF_KIND_STRUCT(id = 2) +; CHECK: .long 37 # BTF_KIND_UNION(id = 7) +; CHECK: .ascii "s1" # string offset=1 +; CHECK: .ascii "u1" # string offset=37 +; CHECK: .ascii ".text" # string offset=64 +; CHECK: .ascii "0:0" # string offset=70 +; CHECK: .ascii "0:2" # string offset=111 + +; CHECK: .long 16 # FieldReloc +; CHECK-NEXT: .long 64 # Field reloc section string offset=64 +; CHECK-NEXT: .long 4 +; CHECK-NEXT: .long .Ltmp{{[0-9]+}} +; CHECK-NEXT: .long 2 +; CHECK-NEXT: .long 70 +; CHECK-NEXT: .long 3 +; CHECK-NEXT: .long .Ltmp{{[0-9]+}} +; CHECK-NEXT: .long 2 +; CHECK-NEXT: .long 111 +; CHECK-NEXT: .long 3 +; CHECK-NEXT: .long .Ltmp{{[0-9]+}} +; CHECK-NEXT: .long 7 +; CHECK-NEXT: .long 70 +; CHECK-NEXT: .long 3 +; CHECK-NEXT: .long .Ltmp{{[0-9]+}} +; CHECK-NEXT: .long 7 +; CHECK-NEXT: .long 111 +; CHECK-NEXT: .long 3 + +; Function Attrs: nounwind readnone +declare i32* @llvm.preserve.struct.access.index.p0i32.p0s_struct.s1s(%struct.s1*, i32, i32) #1 + +; Function Attrs: nounwind readnone +declare i32 @llvm.bpf.preserve.field.info.p0i32(i32*, i64) #1 + +; Function Attrs: nounwind readnone +declare i16* @llvm.preserve.struct.access.index.p0i16.p0s_struct.s1s(%struct.s1*, i32, i32) #1 + +; Function Attrs: nounwind readnone +declare i32 @llvm.bpf.preserve.field.info.p0i16(i16*, i64) #1 + +; Function Attrs: nounwind readnone +declare %union.u1* @llvm.preserve.union.access.index.p0s_union.u1s.p0s_union.u1s(%union.u1*, i32) #1 + +; Function Attrs: nounwind readnone +declare i32* @llvm.preserve.struct.access.index.p0i32.p0s_union.u1s(%union.u1*, i32, i32) #1 + +; Function Attrs: nounwind readnone +declare i32 @llvm.bpf.preserve.field.info.p0i8(i8*, i64) #1 + +; Function Attrs: nounwind readnone speculatable willreturn +declare void @llvm.dbg.value(metadata, metadata, metadata) #2 + +attributes #0 = { nounwind readnone "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" } +attributes #1 = { nounwind readnone } +attributes #2 = { nounwind readnone speculatable willreturn } + +!llvm.dbg.cu = !{!0} +!llvm.module.flags = !{!7, !8, !9} +!llvm.ident = !{!10} + +!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 10.0.0 (https://github.com/llvm/llvm-project.git 4a60741b74384f14b21fdc0131ede326438840ab)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, nameTableKind: None) +!1 = !DIFile(filename: "test.c", directory: "/tmp/home/yhs/work/tests/core") +!2 = !{!3} +!3 = !DICompositeType(tag: DW_TAG_enumeration_type, file: !1, line: 4, baseType: !4, size: 32, elements: !5) +!4 = !DIBasicType(name: "unsigned int", size: 32, encoding: DW_ATE_unsigned) +!5 = !{!6} +!6 = !DIEnumerator(name: "FIELD_SIGNEDNESS", value: 3, isUnsigned: true) +!7 = !{i32 2, !"Dwarf Version", i32 4} +!8 = !{i32 2, !"Debug Info Version", i32 3} +!9 = !{i32 1, !"wchar_size", i32 4} +!10 = !{!"clang version 10.0.0 (https://github.com/llvm/llvm-project.git 4a60741b74384f14b21fdc0131ede326438840ab)"} +!11 = distinct !DISubprogram(name: "test", scope: !1, file: !1, line: 5, type: !12, scopeLine: 5, flags: DIFlagPrototyped, isDefinition: true, isOptimized: true, unit: !0, retainedNodes: !28) +!12 = !DISubroutineType(types: !13) +!13 = !{!14, !15, !22} +!14 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +!15 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !16, size: 64) +!16 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "s1", file: !1, line: 2, size: 64, elements: !17) +!17 = !{!18, !19, !21} +!18 = !DIDerivedType(tag: DW_TAG_member, name: "a1", scope: !16, file: !1, line: 2, baseType: !14, size: 32) +!19 = !DIDerivedType(tag: DW_TAG_member, name: "a2", scope: !16, file: !1, line: 2, baseType: !20, size: 9, offset: 32, flags: DIFlagBitField, extraData: i64 32) +!20 = !DIDerivedType(tag: DW_TAG_typedef, name: "__uint", file: !1, line: 1, baseType: !4) +!21 = !DIDerivedType(tag: DW_TAG_member, name: "a3", scope: !16, file: !1, line: 2, baseType: !20, size: 4, offset: 41, flags: DIFlagBitField, extraData: i64 32) +!22 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !23, size: 64) +!23 = distinct !DICompositeType(tag: DW_TAG_union_type, name: "u1", file: !1, line: 3, size: 32, elements: !24) +!24 = !{!25, !26, !27} +!25 = !DIDerivedType(tag: DW_TAG_member, name: "b1", scope: !23, file: !1, line: 3, baseType: !14, size: 32) +!26 = !DIDerivedType(tag: DW_TAG_member, name: "b2", scope: !23, file: !1, line: 3, baseType: !20, size: 9, flags: DIFlagBitField, extraData: i64 0) +!27 = !DIDerivedType(tag: DW_TAG_member, name: "b3", scope: !23, file: !1, line: 3, baseType: !20, size: 4, flags: DIFlagBitField, extraData: i64 0) +!28 = !{!29, !30, !31, !32, !33, !34} +!29 = !DILocalVariable(name: "arg1", arg: 1, scope: !11, file: !1, line: 5, type: !15) +!30 = !DILocalVariable(name: "arg2", arg: 2, scope: !11, file: !1, line: 5, type: !22) +!31 = !DILocalVariable(name: "r1", scope: !11, file: !1, line: 6, type: !4) +!32 = !DILocalVariable(name: "r2", scope: !11, file: !1, line: 7, type: !4) +!33 = !DILocalVariable(name: "r3", scope: !11, file: !1, line: 8, type: !4) +!34 = !DILocalVariable(name: "r4", scope: !11, file: !1, line: 9, type: !4) +!35 = !DILocation(line: 0, scope: !11) +!36 = !DILocation(line: 6, column: 53, scope: !11) +!37 = !DILocation(line: 6, column: 17, scope: !11) +!38 = !DILocation(line: 7, column: 53, scope: !11) +!39 = !DILocation(line: 7, column: 17, scope: !11) +!40 = !DILocation(line: 8, column: 53, scope: !11) +!41 = !DILocation(line: 8, column: 17, scope: !11) +!42 = !DILocation(line: 9, column: 53, scope: !11) +!43 = !DILocation(line: 9, column: 17, scope: !11) +!44 = !DILocation(line: 10, column: 13, scope: !11) +!45 = !DILocation(line: 10, column: 18, scope: !11) +!46 = !DILocation(line: 10, column: 23, scope: !11) +!47 = !DILocation(line: 10, column: 3, scope: !11) diff --git a/llvm/test/CodeGen/SBF/CORE/intrinsic-fieldinfo-signedness-2.ll b/llvm/test/CodeGen/SBF/CORE/intrinsic-fieldinfo-signedness-2.ll new file mode 100644 index 0000000000000..5b9373e4407af --- /dev/null +++ b/llvm/test/CodeGen/SBF/CORE/intrinsic-fieldinfo-signedness-2.ll @@ -0,0 +1,156 @@ +; RUN: opt -O2 %s | llvm-dis > %t1 +; RUN: llc -sbf-enable-btf-emission -filetype=asm -o - %t1 | FileCheck -check-prefixes=CHECK,CHECK-ALU64 %s +; RUN: llc -sbf-enable-btf-emission -mattr=+alu32 -filetype=asm -o - %t1 | FileCheck -check-prefixes=CHECK,CHECK-ALU32 %s +; Source code: +; enum A { AA = -1, AB = 0, }; /* signed */ +; enum B { BA = 0, BB = 1, }; /* unsigned */ +; typedef enum A __A; +; typedef enum B __B; +; typedef int __int; /* signed */ +; struct s1 { __A a1; __B a2:9; __int a3:4; }; +; union u1 { int b1; struct s1 b2; }; +; enum { FIELD_SIGNEDNESS = 3, }; +; int test(union u1 *arg) { +; unsigned r1 = __builtin_preserve_field_info(arg->b2.a1, FIELD_SIGNEDNESS); +; unsigned r2 = __builtin_preserve_field_info(arg->b2.a2, FIELD_SIGNEDNESS); +; unsigned r3 = __builtin_preserve_field_info(arg->b2.a3, FIELD_SIGNEDNESS); +; return r1 + r2 + r3; +; } +; Compilation flag: +; clang -target bpf -O2 -g -S -emit-llvm -Xclang -disable-llvm-passes test.c + +target triple = "sbf" + +%union.u1 = type { %struct.s1 } +%struct.s1 = type { i32, i16 } + +; Function Attrs: nounwind readnone +define dso_local i32 @test(%union.u1* %arg) local_unnamed_addr #0 !dbg !20 { +entry: + call void @llvm.dbg.value(metadata %union.u1* %arg, metadata !37, metadata !DIExpression()), !dbg !41 + %0 = tail call %union.u1* @llvm.preserve.union.access.index.p0s_union.u1s.p0s_union.u1s(%union.u1* %arg, i32 1), !dbg !42, !llvm.preserve.access.index !24 + %b2 = getelementptr inbounds %union.u1, %union.u1* %0, i64 0, i32 0, !dbg !42 + %1 = tail call i32* @llvm.preserve.struct.access.index.p0i32.p0s_struct.s1s(%struct.s1* elementtype(%struct.s1) %b2, i32 0, i32 0), !dbg !43, !llvm.preserve.access.index !28 + %2 = tail call i32 @llvm.bpf.preserve.field.info.p0i32(i32* %1, i64 3), !dbg !44 + call void @llvm.dbg.value(metadata i32 %2, metadata !38, metadata !DIExpression()), !dbg !41 + %3 = tail call i16* @llvm.preserve.struct.access.index.p0i16.p0s_struct.s1s(%struct.s1* elementtype(%struct.s1) %b2, i32 1, i32 1), !dbg !45, !llvm.preserve.access.index !28 + %4 = tail call i32 @llvm.bpf.preserve.field.info.p0i16(i16* %3, i64 3), !dbg !46 + call void @llvm.dbg.value(metadata i32 %4, metadata !39, metadata !DIExpression()), !dbg !41 + %5 = tail call i16* @llvm.preserve.struct.access.index.p0i16.p0s_struct.s1s(%struct.s1* elementtype(%struct.s1) %b2, i32 1, i32 2), !dbg !47, !llvm.preserve.access.index !28 + %6 = tail call i32 @llvm.bpf.preserve.field.info.p0i16(i16* %5, i64 3), !dbg !48 + call void @llvm.dbg.value(metadata i32 %6, metadata !40, metadata !DIExpression()), !dbg !41 + %add = add i32 %4, %2, !dbg !49 + %add3 = add i32 %add, %6, !dbg !50 + ret i32 %add3, !dbg !51 +} + +; CHECK: mov64 r1, 1 +; CHECK: mov64 r0, 0 +; CHECK-ALU64: add64 r0, r1 +; CHECK-ALU32: add32 w0, w1 +; CHECK: mov64 r1, 1 +; CHECK-ALU64: add64 r0, r1 +; CHECK-ALU32: add32 w0, w1 +; CHECK: exit + +; CHECK: .long 1 # BTF_KIND_UNION(id = 2) +; CHECK: .ascii "u1" # string offset=1 +; CHECK: .ascii ".text" # string offset=65 +; CHECK: .ascii "0:1:0" # string offset=71 +; CHECK: .ascii "0:1:1" # string offset=114 +; CHECK: .ascii "0:1:2" # string offset=120 + +; CHECK: .long 16 # FieldReloc +; CHECK-NEXT: .long 65 # Field reloc section string offset=65 +; CHECK-NEXT: .long 3 +; CHECK-NEXT: .long .Ltmp{{[0-9]+}} +; CHECK-NEXT: .long 2 +; CHECK-NEXT: .long 71 +; CHECK-NEXT: .long 3 +; CHECK-NEXT: .long .Ltmp{{[0-9]+}} +; CHECK-NEXT: .long 2 +; CHECK-NEXT: .long 114 +; CHECK-NEXT: .long 3 +; CHECK-NEXT: .long .Ltmp{{[0-9]+}} +; CHECK-NEXT: .long 2 +; CHECK-NEXT: .long 120 +; CHECK-NEXT: .long 3 + +; Function Attrs: nounwind readnone +declare %union.u1* @llvm.preserve.union.access.index.p0s_union.u1s.p0s_union.u1s(%union.u1*, i32) #1 + +; Function Attrs: nounwind readnone +declare i32* @llvm.preserve.struct.access.index.p0i32.p0s_struct.s1s(%struct.s1*, i32, i32) #1 + +; Function Attrs: nounwind readnone +declare i32 @llvm.bpf.preserve.field.info.p0i32(i32*, i64) #1 + +; Function Attrs: nounwind readnone +declare i16* @llvm.preserve.struct.access.index.p0i16.p0s_struct.s1s(%struct.s1*, i32, i32) #1 + +; Function Attrs: nounwind readnone +declare i32 @llvm.bpf.preserve.field.info.p0i16(i16*, i64) #1 + +; Function Attrs: nounwind readnone speculatable willreturn +declare void @llvm.dbg.value(metadata, metadata, metadata) #2 + +attributes #0 = { nounwind readnone "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" } +attributes #1 = { nounwind readnone } +attributes #2 = { nounwind readnone speculatable willreturn } + +!llvm.dbg.cu = !{!0} +!llvm.module.flags = !{!16, !17, !18} +!llvm.ident = !{!19} + +!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 10.0.0 (https://github.com/llvm/llvm-project.git 4a60741b74384f14b21fdc0131ede326438840ab)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, nameTableKind: None) +!1 = !DIFile(filename: "test.c", directory: "/tmp/home/yhs/work/tests/core") +!2 = !{!3, !8, !13} +!3 = !DICompositeType(tag: DW_TAG_enumeration_type, name: "A", file: !1, line: 1, baseType: !4, size: 32, elements: !5) +!4 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +!5 = !{!6, !7} +!6 = !DIEnumerator(name: "AA", value: -1) +!7 = !DIEnumerator(name: "AB", value: 0) +!8 = !DICompositeType(tag: DW_TAG_enumeration_type, name: "B", file: !1, line: 2, baseType: !9, size: 32, elements: !10) +!9 = !DIBasicType(name: "unsigned int", size: 32, encoding: DW_ATE_unsigned) +!10 = !{!11, !12} +!11 = !DIEnumerator(name: "BA", value: 0, isUnsigned: true) +!12 = !DIEnumerator(name: "BB", value: 1, isUnsigned: true) +!13 = !DICompositeType(tag: DW_TAG_enumeration_type, file: !1, line: 8, baseType: !9, size: 32, elements: !14) +!14 = !{!15} +!15 = !DIEnumerator(name: "FIELD_SIGNEDNESS", value: 3, isUnsigned: true) +!16 = !{i32 2, !"Dwarf Version", i32 4} +!17 = !{i32 2, !"Debug Info Version", i32 3} +!18 = !{i32 1, !"wchar_size", i32 4} +!19 = !{!"clang version 10.0.0 (https://github.com/llvm/llvm-project.git 4a60741b74384f14b21fdc0131ede326438840ab)"} +!20 = distinct !DISubprogram(name: "test", scope: !1, file: !1, line: 9, type: !21, scopeLine: 9, flags: DIFlagPrototyped, isDefinition: true, isOptimized: true, unit: !0, retainedNodes: !36) +!21 = !DISubroutineType(types: !22) +!22 = !{!4, !23} +!23 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !24, size: 64) +!24 = distinct !DICompositeType(tag: DW_TAG_union_type, name: "u1", file: !1, line: 7, size: 64, elements: !25) +!25 = !{!26, !27} +!26 = !DIDerivedType(tag: DW_TAG_member, name: "b1", scope: !24, file: !1, line: 7, baseType: !4, size: 32) +!27 = !DIDerivedType(tag: DW_TAG_member, name: "b2", scope: !24, file: !1, line: 7, baseType: !28, size: 64) +!28 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "s1", file: !1, line: 6, size: 64, elements: !29) +!29 = !{!30, !32, !34} +!30 = !DIDerivedType(tag: DW_TAG_member, name: "a1", scope: !28, file: !1, line: 6, baseType: !31, size: 32) +!31 = !DIDerivedType(tag: DW_TAG_typedef, name: "__A", file: !1, line: 3, baseType: !3) +!32 = !DIDerivedType(tag: DW_TAG_member, name: "a2", scope: !28, file: !1, line: 6, baseType: !33, size: 9, offset: 32, flags: DIFlagBitField, extraData: i64 32) +!33 = !DIDerivedType(tag: DW_TAG_typedef, name: "__B", file: !1, line: 4, baseType: !8) +!34 = !DIDerivedType(tag: DW_TAG_member, name: "a3", scope: !28, file: !1, line: 6, baseType: !35, size: 4, offset: 41, flags: DIFlagBitField, extraData: i64 32) +!35 = !DIDerivedType(tag: DW_TAG_typedef, name: "__int", file: !1, line: 5, baseType: !4) +!36 = !{!37, !38, !39, !40} +!37 = !DILocalVariable(name: "arg", arg: 1, scope: !20, file: !1, line: 9, type: !23) +!38 = !DILocalVariable(name: "r1", scope: !20, file: !1, line: 10, type: !9) +!39 = !DILocalVariable(name: "r2", scope: !20, file: !1, line: 11, type: !9) +!40 = !DILocalVariable(name: "r3", scope: !20, file: !1, line: 12, type: !9) +!41 = !DILocation(line: 0, scope: !20) +!42 = !DILocation(line: 10, column: 52, scope: !20) +!43 = !DILocation(line: 10, column: 55, scope: !20) +!44 = !DILocation(line: 10, column: 17, scope: !20) +!45 = !DILocation(line: 11, column: 55, scope: !20) +!46 = !DILocation(line: 11, column: 17, scope: !20) +!47 = !DILocation(line: 12, column: 55, scope: !20) +!48 = !DILocation(line: 12, column: 17, scope: !20) +!49 = !DILocation(line: 13, column: 13, scope: !20) +!50 = !DILocation(line: 13, column: 18, scope: !20) +!51 = !DILocation(line: 13, column: 3, scope: !20) diff --git a/llvm/test/CodeGen/SBF/CORE/intrinsic-fieldinfo-signedness-3.ll b/llvm/test/CodeGen/SBF/CORE/intrinsic-fieldinfo-signedness-3.ll new file mode 100644 index 0000000000000..9c6a8a9ba3110 --- /dev/null +++ b/llvm/test/CodeGen/SBF/CORE/intrinsic-fieldinfo-signedness-3.ll @@ -0,0 +1,153 @@ +; RUN: opt -O2 %s | llvm-dis > %t1 +; RUN: llc -sbf-enable-btf-emission -filetype=asm -o - %t1 | FileCheck -check-prefixes=CHECK,CHECK-ALU64 %s +; RUN: llc -sbf-enable-btf-emission -mattr=+alu32 -filetype=asm -o - %t1 | FileCheck -check-prefixes=CHECK,CHECK-ALU32 %s +; Source code: +; enum A { AA = -1, AB = 0, }; +; enum B { BA = 0, BB = 1, }; +; typedef enum A __A; +; typedef enum B __B; +; typedef struct s1 { __A a1[10]; __B a2[10][10]; } __s1; +; union u1 { int b1; __s1 b2; }; +; enum { FIELD_SIGNEDNESS = 3, }; +; int test(union u1 *arg) { +; unsigned r1 = __builtin_preserve_field_info(arg->b2.a1[5], FIELD_SIGNEDNESS); +; unsigned r2 = __builtin_preserve_field_info(arg->b2.a2[5][5], FIELD_SIGNEDNESS); +; /* r1 : 1, r2 : 0 */ +; return r1 + r2; +; } +; Compilation flag: +; clang -target bpf -O2 -g -S -emit-llvm -Xclang -disable-llvm-passes test.c + +target triple = "sbf" + +%union.u1 = type { %struct.s1 } +%struct.s1 = type { [10 x i32], [10 x [10 x i32]] } + +; Function Attrs: nounwind readnone +define dso_local i32 @test(%union.u1* %arg) local_unnamed_addr #0 !dbg !29 { +entry: + call void @llvm.dbg.value(metadata %union.u1* %arg, metadata !43, metadata !DIExpression()), !dbg !46 + %0 = tail call %union.u1* @llvm.preserve.union.access.index.p0s_union.u1s.p0s_union.u1s(%union.u1* %arg, i32 1), !dbg !47, !llvm.preserve.access.index !33 + %b2 = getelementptr inbounds %union.u1, %union.u1* %0, i64 0, i32 0, !dbg !47 + %1 = tail call [10 x i32]* @llvm.preserve.struct.access.index.p0a10i32.p0s_struct.s1s(%struct.s1* elementtype(%struct.s1) %b2, i32 0, i32 0), !dbg !48, !llvm.preserve.access.index !38 + %2 = tail call i32* @llvm.preserve.array.access.index.p0i32.p0a10i32([10 x i32]* elementtype([10 x i32]) %1, i32 1, i32 5), !dbg !49, !llvm.preserve.access.index !17 + %3 = tail call i32 @llvm.bpf.preserve.field.info.p0i32(i32* %2, i64 3), !dbg !50 + call void @llvm.dbg.value(metadata i32 %3, metadata !44, metadata !DIExpression()), !dbg !46 + %4 = tail call [10 x [10 x i32]]* @llvm.preserve.struct.access.index.p0a10a10i32.p0s_struct.s1s(%struct.s1* elementtype(%struct.s1) %b2, i32 1, i32 1), !dbg !51, !llvm.preserve.access.index !38 + %5 = tail call [10 x i32]* @llvm.preserve.array.access.index.p0a10i32.p0a10a10i32([10 x [10 x i32]]* elementtype([10 x [10 x i32]]) %4, i32 1, i32 5), !dbg !52, !llvm.preserve.access.index !21 + %6 = tail call i32* @llvm.preserve.array.access.index.p0i32.p0a10i32([10 x i32]* elementtype([10 x i32]) %5, i32 1, i32 5), !dbg !52, !llvm.preserve.access.index !24 + %7 = tail call i32 @llvm.bpf.preserve.field.info.p0i32(i32* %6, i64 3), !dbg !53 + call void @llvm.dbg.value(metadata i32 %7, metadata !45, metadata !DIExpression()), !dbg !46 + %add = add i32 %7, %3, !dbg !54 + ret i32 %add, !dbg !55 +} + +; CHECK: mov64 r1, 1 +; CHECK: mov64 r0, 0 +; CHECK-ALU64: add64 r0, r1 +; CHECK-ALU32: add32 w0, w1 +; CHECK: exit + +; CHECK: .long 1 # BTF_KIND_UNION(id = 2) +; CHECK: .ascii "u1" # string offset=1 +; CHECK: .ascii ".text" # string offset=81 +; CHECK: .ascii "0:1:0:5" # string offset=87 +; CHECK: .ascii "0:1:1:5:5" # string offset=132 + +; CHECK: .long 16 # FieldReloc +; CHECK-NEXT: .long 81 # Field reloc section string offset=81 +; CHECK-NEXT: .long 2 +; CHECK-NEXT: .long .Ltmp{{[0-9]+}} +; CHECK-NEXT: .long 2 +; CHECK-NEXT: .long 87 +; CHECK-NEXT: .long 3 +; CHECK-NEXT: .long .Ltmp{{[0-9]+}} +; CHECK-NEXT: .long 2 +; CHECK-NEXT: .long 132 +; CHECK-NEXT: .long 3 + +; Function Attrs: nounwind readnone +declare %union.u1* @llvm.preserve.union.access.index.p0s_union.u1s.p0s_union.u1s(%union.u1*, i32) #1 + +; Function Attrs: nounwind readnone +declare [10 x i32]* @llvm.preserve.struct.access.index.p0a10i32.p0s_struct.s1s(%struct.s1*, i32, i32) #1 + +; Function Attrs: nounwind readnone +declare i32* @llvm.preserve.array.access.index.p0i32.p0a10i32([10 x i32]*, i32, i32) #1 + +; Function Attrs: nounwind readnone +declare i32 @llvm.bpf.preserve.field.info.p0i32(i32*, i64) #1 + +; Function Attrs: nounwind readnone +declare [10 x [10 x i32]]* @llvm.preserve.struct.access.index.p0a10a10i32.p0s_struct.s1s(%struct.s1*, i32, i32) #1 + +; Function Attrs: nounwind readnone +declare [10 x i32]* @llvm.preserve.array.access.index.p0a10i32.p0a10a10i32([10 x [10 x i32]]*, i32, i32) #1 + +; Function Attrs: nounwind readnone speculatable willreturn +declare void @llvm.dbg.value(metadata, metadata, metadata) #2 + +attributes #0 = { nounwind readnone "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" } +attributes #1 = { nounwind readnone } +attributes #2 = { nounwind readnone speculatable willreturn } + +!llvm.dbg.cu = !{!0} +!llvm.module.flags = !{!25, !26, !27} +!llvm.ident = !{!28} + +!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 10.0.0 (https://github.com/llvm/llvm-project.git c1e02f16f1105ffaf1c35ee8bc38b7d6db5c6ea9)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, retainedTypes: !16, nameTableKind: None) +!1 = !DIFile(filename: "test.c", directory: "/tmp/home/yhs/work/tests/core") +!2 = !{!3, !8, !13} +!3 = !DICompositeType(tag: DW_TAG_enumeration_type, name: "A", file: !1, line: 1, baseType: !4, size: 32, elements: !5) +!4 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +!5 = !{!6, !7} +!6 = !DIEnumerator(name: "AA", value: -1) +!7 = !DIEnumerator(name: "AB", value: 0) +!8 = !DICompositeType(tag: DW_TAG_enumeration_type, name: "B", file: !1, line: 2, baseType: !9, size: 32, elements: !10) +!9 = !DIBasicType(name: "unsigned int", size: 32, encoding: DW_ATE_unsigned) +!10 = !{!11, !12} +!11 = !DIEnumerator(name: "BA", value: 0, isUnsigned: true) +!12 = !DIEnumerator(name: "BB", value: 1, isUnsigned: true) +!13 = !DICompositeType(tag: DW_TAG_enumeration_type, file: !1, line: 7, baseType: !9, size: 32, elements: !14) +!14 = !{!15} +!15 = !DIEnumerator(name: "FIELD_SIGNEDNESS", value: 3, isUnsigned: true) +!16 = !{!17, !21, !24} +!17 = !DICompositeType(tag: DW_TAG_array_type, baseType: !18, size: 320, elements: !19) +!18 = !DIDerivedType(tag: DW_TAG_typedef, name: "__A", file: !1, line: 3, baseType: !3) +!19 = !{!20} +!20 = !DISubrange(count: 10) +!21 = !DICompositeType(tag: DW_TAG_array_type, baseType: !22, size: 3200, elements: !23) +!22 = !DIDerivedType(tag: DW_TAG_typedef, name: "__B", file: !1, line: 4, baseType: !8) +!23 = !{!20, !20} +!24 = !DICompositeType(tag: DW_TAG_array_type, baseType: !22, size: 320, elements: !19) +!25 = !{i32 2, !"Dwarf Version", i32 4} +!26 = !{i32 2, !"Debug Info Version", i32 3} +!27 = !{i32 1, !"wchar_size", i32 4} +!28 = !{!"clang version 10.0.0 (https://github.com/llvm/llvm-project.git c1e02f16f1105ffaf1c35ee8bc38b7d6db5c6ea9)"} +!29 = distinct !DISubprogram(name: "test", scope: !1, file: !1, line: 8, type: !30, scopeLine: 8, flags: DIFlagPrototyped, isDefinition: true, isOptimized: true, unit: !0, retainedNodes: !42) +!30 = !DISubroutineType(types: !31) +!31 = !{!4, !32} +!32 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !33, size: 64) +!33 = distinct !DICompositeType(tag: DW_TAG_union_type, name: "u1", file: !1, line: 6, size: 3520, elements: !34) +!34 = !{!35, !36} +!35 = !DIDerivedType(tag: DW_TAG_member, name: "b1", scope: !33, file: !1, line: 6, baseType: !4, size: 32) +!36 = !DIDerivedType(tag: DW_TAG_member, name: "b2", scope: !33, file: !1, line: 6, baseType: !37, size: 3520) +!37 = !DIDerivedType(tag: DW_TAG_typedef, name: "__s1", file: !1, line: 5, baseType: !38) +!38 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "s1", file: !1, line: 5, size: 3520, elements: !39) +!39 = !{!40, !41} +!40 = !DIDerivedType(tag: DW_TAG_member, name: "a1", scope: !38, file: !1, line: 5, baseType: !17, size: 320) +!41 = !DIDerivedType(tag: DW_TAG_member, name: "a2", scope: !38, file: !1, line: 5, baseType: !21, size: 3200, offset: 320) +!42 = !{!43, !44, !45} +!43 = !DILocalVariable(name: "arg", arg: 1, scope: !29, file: !1, line: 8, type: !32) +!44 = !DILocalVariable(name: "r1", scope: !29, file: !1, line: 9, type: !9) +!45 = !DILocalVariable(name: "r2", scope: !29, file: !1, line: 10, type: !9) +!46 = !DILocation(line: 0, scope: !29) +!47 = !DILocation(line: 9, column: 52, scope: !29) +!48 = !DILocation(line: 9, column: 55, scope: !29) +!49 = !DILocation(line: 9, column: 47, scope: !29) +!50 = !DILocation(line: 9, column: 17, scope: !29) +!51 = !DILocation(line: 10, column: 55, scope: !29) +!52 = !DILocation(line: 10, column: 47, scope: !29) +!53 = !DILocation(line: 10, column: 17, scope: !29) +!54 = !DILocation(line: 12, column: 13, scope: !29) +!55 = !DILocation(line: 12, column: 3, scope: !29) diff --git a/llvm/test/CodeGen/SBF/CORE/intrinsic-struct.ll b/llvm/test/CodeGen/SBF/CORE/intrinsic-struct.ll new file mode 100644 index 0000000000000..c9418a85b71d8 --- /dev/null +++ b/llvm/test/CodeGen/SBF/CORE/intrinsic-struct.ll @@ -0,0 +1,82 @@ +; RUN: opt -O2 %s | llvm-dis > %t1 +; RUN: llc -sbf-enable-btf-emission -filetype=asm -o - %t1 | FileCheck %s +; RUN: llc -sbf-enable-btf-emission -mattr=+alu32 -filetype=asm -o - %t1 | FileCheck %s +; +; Source code: +; struct s { int a; int b; }; +; #define _(x) (__builtin_preserve_access_index(x)) +; int get_value(const void *addr); +; int test(struct s *arg) { return get_value(_(&arg->b)); } +; Compiler flag to generate IR: +; clang -target bpf -S -O2 -g -emit-llvm -Xclang -disable-llvm-passes test.c + +target triple = "sbf" + +%struct.s = type { i32, i32 } + +; Function Attrs: nounwind +define dso_local i32 @test(%struct.s* %arg) local_unnamed_addr #0 !dbg !7 { +entry: + call void @llvm.dbg.value(metadata %struct.s* %arg, metadata !17, metadata !DIExpression()), !dbg !18 + %0 = tail call i32* @llvm.preserve.struct.access.index.p0i32.p0s_struct.ss(%struct.s* elementtype(%struct.s) %arg, i32 1, i32 1), !dbg !19, !llvm.preserve.access.index !12 + %1 = bitcast i32* %0 to i8*, !dbg !19 + %call = tail call i32 @get_value(i8* %1) #4, !dbg !20 + ret i32 %call, !dbg !21 +} + +; CHECK-LABEL: test +; CHECK: [[RELOC:.Ltmp[0-9]+]] +; CHECK: mov64 r2, 4 +; CHECK: add64 r1, r2 +; CHECK: call get_value +; CHECK: exit +; +; CHECK: .section .BTF.ext,"",@progbits +; CHECK: .long 16 # FieldReloc +; CHECK-NEXT: .long 20 # Field reloc section string offset=20 +; CHECK-NEXT: .long 1 +; CHECK-NEXT: .long [[RELOC]] +; CHECK-NEXT: .long 2 +; CHECK-NEXT: .long 26 +; CHECK-NEXT: .long 0 + +declare dso_local i32 @get_value(i8*) local_unnamed_addr #1 + +; Function Attrs: nounwind readnone +declare i32* @llvm.preserve.struct.access.index.p0i32.p0s_struct.ss(%struct.s*, i32 immarg, i32 immarg) #2 + +; Function Attrs: nounwind readnone speculatable +declare void @llvm.dbg.value(metadata, metadata, metadata) #3 + +attributes #0 = { nounwind "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "frame-pointer"="all" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" } +attributes #1 = { "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "frame-pointer"="all" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" } +attributes #2 = { nounwind readnone } +attributes #3 = { nounwind readnone speculatable } +attributes #4 = { nounwind } + +!llvm.dbg.cu = !{!0} +!llvm.module.flags = !{!3, !4, !5} +!llvm.ident = !{!6} + +!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 9.0.0 (trunk 365789)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, nameTableKind: None) +!1 = !DIFile(filename: "test.c", directory: "/tmp/home/yhs/work/tests/core") +!2 = !{} +!3 = !{i32 2, !"Dwarf Version", i32 4} +!4 = !{i32 2, !"Debug Info Version", i32 3} +!5 = !{i32 1, !"wchar_size", i32 4} +!6 = !{!"clang version 9.0.0 (trunk 365789)"} +!7 = distinct !DISubprogram(name: "test", scope: !1, file: !1, line: 4, type: !8, scopeLine: 4, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !16) +!8 = !DISubroutineType(types: !9) +!9 = !{!10, !11} +!10 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +!11 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !12, size: 64) +!12 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "s", file: !1, line: 1, size: 64, elements: !13) +!13 = !{!14, !15} +!14 = !DIDerivedType(tag: DW_TAG_member, name: "a", scope: !12, file: !1, line: 1, baseType: !10, size: 32) +!15 = !DIDerivedType(tag: DW_TAG_member, name: "b", scope: !12, file: !1, line: 1, baseType: !10, size: 32, offset: 32) +!16 = !{!17} +!17 = !DILocalVariable(name: "arg", arg: 1, scope: !7, file: !1, line: 4, type: !11) +!18 = !DILocation(line: 0, scope: !7) +!19 = !DILocation(line: 4, column: 44, scope: !7) +!20 = !DILocation(line: 4, column: 34, scope: !7) +!21 = !DILocation(line: 4, column: 27, scope: !7) diff --git a/llvm/test/CodeGen/SBF/CORE/intrinsic-typeinfo-enum-value-opaque-pointer.ll b/llvm/test/CodeGen/SBF/CORE/intrinsic-typeinfo-enum-value-opaque-pointer.ll new file mode 100644 index 0000000000000..ff5eed7fb2155 --- /dev/null +++ b/llvm/test/CodeGen/SBF/CORE/intrinsic-typeinfo-enum-value-opaque-pointer.ll @@ -0,0 +1,103 @@ +; RUN: opt -O2 %s | llvm-dis > %t1 +; RUN: llc -sbf-enable-btf-emission -filetype=asm -o - %t1 | FileCheck %s +; RUN: llc -sbf-enable-btf-emission -mattr=+alu32 -filetype=asm -o - %t1 | FileCheck %s +; +; Source: +; enum AA { VAL1 = -100, VAL2 = 0xffff8000 }; +; typedef enum { VAL10 = 0xffffFFFF80000000 } __BB; +; int test() { +; return __builtin_preserve_enum_value(*(enum AA *)VAL1, 0) + +; __builtin_preserve_enum_value(*(enum AA *)VAL2, 1) + +; __builtin_preserve_enum_value(*(__BB *)VAL10, 1); +; } +; Compiler flag to generate IR: +; clang -target bpf -S -O2 -g -emit-llvm -Xclang -disable-llvm-passes t1.c + +target triple = "sbf" + +@0 = private unnamed_addr constant [10 x i8] c"VAL1:-100\00", align 1 +@1 = private unnamed_addr constant [16 x i8] c"VAL2:4294934528\00", align 1 +@2 = private unnamed_addr constant [18 x i8] c"VAL10:-2147483648\00", align 1 + +; Function Attrs: nounwind +define dso_local i32 @test() #0 !dbg !19 { +entry: + %0 = call i64 @llvm.bpf.preserve.enum.value(i32 0, ptr @0, i64 0), !dbg !24, !llvm.preserve.access.index !3 + %1 = call i64 @llvm.bpf.preserve.enum.value(i32 1, ptr @1, i64 1), !dbg !25, !llvm.preserve.access.index !3 + %add = add i64 %0, %1, !dbg !26 + %2 = call i64 @llvm.bpf.preserve.enum.value(i32 2, ptr @2, i64 1), !dbg !27, !llvm.preserve.access.index !13 + %add1 = add i64 %add, %2, !dbg !28 + %conv = trunc i64 %add1 to i32, !dbg !24 + ret i32 %conv, !dbg !29 +} + +; CHECK: lddw r{{[0-9]+}}, 1 +; CHECK: lddw r{{[0-9]+}}, 4294934528 +; CHECK: lddw r{{[0-9]+}}, -2147483648 +; CHECK: exit + +; CHECK: .long 16 # BTF_KIND_ENUM64(id = 4) +; CHECK: .long 57 # BTF_KIND_TYPEDEF(id = 5) + +; CHECK: .ascii ".text" # string offset=10 +; CHECK: .ascii "AA" # string offset=16 +; CHECK: .byte 48 # string offset=29 +; CHECK: .byte 49 # string offset=55 +; CHECK: .ascii "__BB" # string offset=57 + +; CHECK: .long 16 # FieldReloc +; CHECK-NEXT: .long 10 # Field reloc section string offset=10 +; CHECK-NEXT: .long 3 +; CHECK-NEXT: .long .Ltmp{{[0-9]+}} +; CHECK-NEXT: .long 4 +; CHECK-NEXT: .long 29 +; CHECK-NEXT: .long 10 +; CHECK-NEXT: .long .Ltmp{{[0-9]+}} +; CHECK-NEXT: .long 4 +; CHECK-NEXT: .long 55 +; CHECK-NEXT: .long 11 +; CHECK-NEXT: .long .Ltmp{{[0-9]+}} +; CHECK-NEXT: .long 5 +; CHECK-NEXT: .long 29 +; CHECK-NEXT: .long 11 + +; Function Attrs: nounwind readnone +declare i64 @llvm.bpf.preserve.enum.value(i32, ptr, i64) #1 + +attributes #0 = { nounwind "frame-pointer"="all" "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" } +attributes #1 = { nounwind readnone } + +!llvm.dbg.cu = !{!0} +!llvm.module.flags = !{!14, !15, !16, !17} +!llvm.ident = !{!18} + +!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 15.0.0 (https://github.com/llvm/llvm-project.git 1218d7e1cf1284666cd7403ea021e40b3b40e92b)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, retainedTypes: !12, splitDebugInlining: false, nameTableKind: None) +!1 = !DIFile(filename: "t1.c", directory: "/tmp/home/yhs/tmp1", checksumkind: CSK_MD5, checksum: "e1a546573a450dae0abedfbf6bebcba9") +!2 = !{!3, !8} +!3 = !DICompositeType(tag: DW_TAG_enumeration_type, name: "AA", file: !1, line: 1, baseType: !4, size: 64, elements: !5) +!4 = !DIBasicType(name: "long", size: 64, encoding: DW_ATE_signed) +!5 = !{!6, !7} +!6 = !DIEnumerator(name: "VAL1", value: -100) +!7 = !DIEnumerator(name: "VAL2", value: 4294934528) +!8 = !DICompositeType(tag: DW_TAG_enumeration_type, file: !1, line: 2, baseType: !9, size: 64, elements: !10) +!9 = !DIBasicType(name: "unsigned long", size: 64, encoding: DW_ATE_unsigned) +!10 = !{!11} +!11 = !DIEnumerator(name: "VAL10", value: 18446744071562067968, isUnsigned: true) +!12 = !{!13} +!13 = !DIDerivedType(tag: DW_TAG_typedef, name: "__BB", file: !1, line: 2, baseType: !8) +!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, !"frame-pointer", i32 2} +!18 = !{!"clang version 15.0.0 (https://github.com/llvm/llvm-project.git 1218d7e1cf1284666cd7403ea021e40b3b40e92b)"} +!19 = distinct !DISubprogram(name: "test", scope: !1, file: !1, line: 3, type: !20, scopeLine: 3, flags: DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !23) +!20 = !DISubroutineType(types: !21) +!21 = !{!22} +!22 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +!23 = !{} +!24 = !DILocation(line: 4, column: 10, scope: !19) +!25 = !DILocation(line: 5, column: 10, scope: !19) +!26 = !DILocation(line: 4, column: 61, scope: !19) +!27 = !DILocation(line: 6, column: 10, scope: !19) +!28 = !DILocation(line: 5, column: 61, scope: !19) +!29 = !DILocation(line: 4, column: 3, scope: !19) diff --git a/llvm/test/CodeGen/SBF/CORE/intrinsic-typeinfo-enum-value.ll b/llvm/test/CodeGen/SBF/CORE/intrinsic-typeinfo-enum-value.ll new file mode 100644 index 0000000000000..6ac2c7aef33e7 --- /dev/null +++ b/llvm/test/CodeGen/SBF/CORE/intrinsic-typeinfo-enum-value.ll @@ -0,0 +1,121 @@ +; RUN: opt -O2 %s | llvm-dis > %t1 +; RUN: llc -sbf-enable-btf-emission -filetype=asm -o - %t1 | FileCheck %s +; RUN: llc -sbf-enable-btf-emission -mattr=+alu32 -filetype=asm -o - %t1 | FileCheck %s +; +; Source: +; enum AA { VAL1 = -100, VAL2 = 0xffff8000 }; +; typedef enum { VAL10 = 0xffffFFFF80000000 } __BB; +; int test() { +; return __builtin_preserve_enum_value(*(enum AA *)VAL1, 0) + +; __builtin_preserve_enum_value(*(enum AA *)VAL2, 1) + +; __builtin_preserve_enum_value(*(__BB *)VAL10, 1); +; } +; Compiler flag to generate IR: +; clang -target bpf -S -O2 -g -emit-llvm -Xclang -disable-llvm-passes t1.c + +target triple = "sbf" + +@0 = private unnamed_addr constant [10 x i8] c"VAL1:-100\00", align 1 +@1 = private unnamed_addr constant [16 x i8] c"VAL2:4294934528\00", align 1 +@2 = private unnamed_addr constant [18 x i8] c"VAL10:-2147483648\00", align 1 + +; Function Attrs: nounwind readnone +define dso_local i32 @test() local_unnamed_addr #0 !dbg !18 { +entry: + %0 = tail call i64 @llvm.bpf.preserve.enum.value(i32 0, i8* getelementptr inbounds ([10 x i8], [10 x i8]* @0, i64 0, i64 0), i64 0), !dbg !23, !llvm.preserve.access.index !3 + %1 = tail call i64 @llvm.bpf.preserve.enum.value(i32 1, i8* getelementptr inbounds ([16 x i8], [16 x i8]* @1, i64 0, i64 0), i64 1), !dbg !24, !llvm.preserve.access.index !3 + %add = add i64 %1, %0, !dbg !25 + %2 = tail call i64 @llvm.bpf.preserve.enum.value(i32 2, i8* getelementptr inbounds ([18 x i8], [18 x i8]* @2, i64 0, i64 0), i64 1), !dbg !26, !llvm.preserve.access.index !13 + %add1 = add i64 %add, %2, !dbg !27 + %conv = trunc i64 %add1 to i32, !dbg !23 + ret i32 %conv, !dbg !28 +} + +; CHECK: lddw r{{[0-9]+}}, 1 +; CHECK: lddw r{{[0-9]+}}, 4294934528 +; CHECK: lddw r{{[0-9]+}}, -2147483648 +; CHECK: exit + +; CHECK: .long 16 # BTF_KIND_ENUM64(id = 4) +; CHECK-NEXT: .long 2466250754 # 0x93000002 +; CHECK-NEXT: .long 8 +; CHECK-NEXT: .long 19 +; CHECK-NEXT: .long 4294967196 # 0xffffff9c +; CHECK-NEXT: .long 4294967295 # 0xffffffff +; CHECK-NEXT: .long 24 +; CHECK-NEXT: .long 4294934528 # 0xffff8000 +; CHECK-NEXT: .long 0 # 0x0 +; CHECK-NEXT: .long 57 # BTF_KIND_TYPEDEF(id = 5) +; CHECK-NEXT: .long 134217728 # 0x8000000 +; CHECK-NEXT: .long 6 +; CHECK-NEXT: .long 0 # BTF_KIND_ENUM64(id = 6) +; CHECK-NEXT: .long 318767105 # 0x13000001 +; CHECK-NEXT: .long 8 +; CHECK-NEXT: .long 62 +; CHECK-NEXT: .long 2147483648 # 0x80000000 +; CHECK-NEXT: .long 4294967295 # 0xffffffff + +; CHECK: .ascii ".text" # string offset=10 +; CHECK: .ascii "AA" # string offset=16 +; CHECK: .ascii "VAL1" # string offset=19 +; CHECK: .ascii "VAL2" # string offset=24 +; CHECK: .byte 48 # string offset=29 +; CHECK: .byte 49 # string offset=55 +; CHECK: .ascii "__BB" # string offset=57 +; CHECK: .ascii "VAL10" # string offset=62 + +; CHECK: .long 16 # FieldReloc +; CHECK-NEXT: .long 10 # Field reloc section string offset=10 +; CHECK-NEXT: .long 3 +; CHECK-NEXT: .long .Ltmp{{[0-9]+}} +; CHECK-NEXT: .long 4 +; CHECK-NEXT: .long 29 +; CHECK-NEXT: .long 10 +; CHECK-NEXT: .long .Ltmp{{[0-9]+}} +; CHECK-NEXT: .long 4 +; CHECK-NEXT: .long 55 +; CHECK-NEXT: .long 11 +; CHECK-NEXT: .long .Ltmp{{[0-9]+}} +; CHECK-NEXT: .long 5 +; CHECK-NEXT: .long 29 +; CHECK-NEXT: .long 11 + +; Function Attrs: nounwind readnone +declare i64 @llvm.bpf.preserve.enum.value(i32, i8*, i64) #1 + +attributes #0 = { nounwind readnone "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" } +attributes #1 = { nounwind readnone } + +!llvm.dbg.cu = !{!0} +!llvm.module.flags = !{!14, !15, !16} +!llvm.ident = !{!17} + +!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 12.0.0 (https://github.com/llvm/llvm-project.git d8b1394a0f4bbf57c254f69f8d3aa5381a89b5cd)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, retainedTypes: !12, splitDebugInlining: false, nameTableKind: None) +!1 = !DIFile(filename: "t1.c", directory: "/tmp/home/yhs/tmp1") +!2 = !{!3, !8} +!3 = !DICompositeType(tag: DW_TAG_enumeration_type, name: "AA", file: !1, line: 1, baseType: !4, size: 64, elements: !5) +!4 = !DIBasicType(name: "long int", size: 64, encoding: DW_ATE_signed) +!5 = !{!6, !7} +!6 = !DIEnumerator(name: "VAL1", value: -100) +!7 = !DIEnumerator(name: "VAL2", value: 4294934528) +!8 = !DICompositeType(tag: DW_TAG_enumeration_type, file: !1, line: 2, baseType: !9, size: 64, elements: !10) +!9 = !DIBasicType(name: "long unsigned int", size: 64, encoding: DW_ATE_unsigned) +!10 = !{!11} +!11 = !DIEnumerator(name: "VAL10", value: 18446744071562067968, isUnsigned: true) +!12 = !{!13} +!13 = !DIDerivedType(tag: DW_TAG_typedef, name: "__BB", file: !1, line: 2, baseType: !8) +!14 = !{i32 7, !"Dwarf Version", i32 4} +!15 = !{i32 2, !"Debug Info Version", i32 3} +!16 = !{i32 1, !"wchar_size", i32 4} +!17 = !{!"clang version 12.0.0 (https://github.com/llvm/llvm-project.git d8b1394a0f4bbf57c254f69f8d3aa5381a89b5cd)"} +!18 = distinct !DISubprogram(name: "test", scope: !1, file: !1, line: 3, type: !19, scopeLine: 3, flags: DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !22) +!19 = !DISubroutineType(types: !20) +!20 = !{!21} +!21 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +!22 = !{} +!23 = !DILocation(line: 4, column: 10, scope: !18) +!24 = !DILocation(line: 5, column: 10, scope: !18) +!25 = !DILocation(line: 4, column: 61, scope: !18) +!26 = !DILocation(line: 6, column: 10, scope: !18) +!27 = !DILocation(line: 5, column: 61, scope: !18) +!28 = !DILocation(line: 4, column: 3, scope: !18) diff --git a/llvm/test/CodeGen/SBF/CORE/intrinsic-typeinfo-type-exist.ll b/llvm/test/CodeGen/SBF/CORE/intrinsic-typeinfo-type-exist.ll new file mode 100644 index 0000000000000..236118864f856 --- /dev/null +++ b/llvm/test/CodeGen/SBF/CORE/intrinsic-typeinfo-type-exist.ll @@ -0,0 +1,101 @@ +; RUN: opt -O2 %s | llvm-dis > %t1 +; RUN: llc -sbf-enable-btf-emission -filetype=asm -o - %t1 | FileCheck %s +; RUN: llc -sbf-enable-btf-emission -mattr=+alu32 -filetype=asm -o - %t1 | FileCheck %s +; +; Source: +; enum AA { VAL = 100 }; +; typedef int (*func_t)(void); +; struct s2 { int a[10]; }; +; int test() { +; return __builtin_preserve_type_info(*(func_t *)0, 0) + +; __builtin_preserve_type_info(*(struct s2 *)0, 0) + +; __builtin_preserve_type_info(*(enum AA *)0, 0); +; } +; Compiler flag to generate IR: +; clang -target bpf -S -O2 -g -emit-llvm -Xclang -disable-llvm-passes t1.c + +target triple = "sbf" + +; Function Attrs: nounwind readnone +define dso_local i32 @test() local_unnamed_addr #0 !dbg !17 { +entry: + %0 = tail call i32 @llvm.bpf.preserve.type.info(i32 0, i64 0), !dbg !19, !llvm.preserve.access.index !8 + %1 = tail call i32 @llvm.bpf.preserve.type.info(i32 1, i64 0), !dbg !20, !llvm.preserve.access.index !21 + %add = add i32 %1, %0, !dbg !27 + %2 = tail call i32 @llvm.bpf.preserve.type.info(i32 2, i64 0), !dbg !28, !llvm.preserve.access.index !3 + %add1 = add i32 %add, %2, !dbg !29 + ret i32 %add1, !dbg !30 +} + +; CHECK: mov64 r{{[0-9]+}}, 1 +; CHECK: mov64 r{{[0-9]+}}, 1 +; CHECK: mov64 r{{[0-9]+}}, 1 +; CHECK: exit + +; CHECK: .long 16 # BTF_KIND_TYPEDEF(id = 4) +; CHECK: .long 49 # BTF_KIND_STRUCT(id = 7) +; CHECK: .long 74 # BTF_KIND_ENUM(id = 10) + +; CHECK: .ascii ".text" # string offset=10 +; CHECK: .ascii "func_t" # string offset=16 +; CHECK: .byte 48 # string offset=23 +; CHECK: .ascii "s2" # string offset=49 +; CHECK: .ascii "AA" # string offset=74 + +; CHECK: .long 16 # FieldReloc +; CHECK-NEXT: .long 10 # Field reloc section string offset=10 +; CHECK-NEXT: .long 3 +; CHECK-NEXT: .long .Ltmp{{[0-9]+}} +; CHECK-NEXT: .long 4 +; CHECK-NEXT: .long 23 +; CHECK-NEXT: .long 8 +; CHECK-NEXT: .long .Ltmp{{[0-9]+}} +; CHECK-NEXT: .long 7 +; CHECK-NEXT: .long 23 +; CHECK-NEXT: .long 8 +; CHECK-NEXT: .long .Ltmp{{[0-9]+}} +; CHECK-NEXT: .long 10 +; CHECK-NEXT: .long 23 +; CHECK-NEXT: .long 8 + +; Function Attrs: nounwind readnone +declare i32 @llvm.bpf.preserve.type.info(i32, i64) #1 + +attributes #0 = { nounwind readnone "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" } +attributes #1 = { nounwind readnone } + +!llvm.dbg.cu = !{!0} +!llvm.module.flags = !{!13, !14, !15} +!llvm.ident = !{!16} + +!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 12.0.0 (https://github.com/llvm/llvm-project.git d8b1394a0f4bbf57c254f69f8d3aa5381a89b5cd)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, retainedTypes: !7, splitDebugInlining: false, nameTableKind: None) +!1 = !DIFile(filename: "t1.c", directory: "/tmp/home/yhs/tmp1") +!2 = !{!3} +!3 = !DICompositeType(tag: DW_TAG_enumeration_type, name: "AA", file: !1, line: 1, baseType: !4, size: 32, elements: !5) +!4 = !DIBasicType(name: "unsigned int", size: 32, encoding: DW_ATE_unsigned) +!5 = !{!6} +!6 = !DIEnumerator(name: "VAL", value: 100, isUnsigned: true) +!7 = !{!8} +!8 = !DIDerivedType(tag: DW_TAG_typedef, name: "func_t", file: !1, line: 2, baseType: !9) +!9 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !10, size: 64) +!10 = !DISubroutineType(types: !11) +!11 = !{!12} +!12 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +!13 = !{i32 7, !"Dwarf Version", i32 4} +!14 = !{i32 2, !"Debug Info Version", i32 3} +!15 = !{i32 1, !"wchar_size", i32 4} +!16 = !{!"clang version 12.0.0 (https://github.com/llvm/llvm-project.git d8b1394a0f4bbf57c254f69f8d3aa5381a89b5cd)"} +!17 = distinct !DISubprogram(name: "test", scope: !1, file: !1, line: 4, type: !10, scopeLine: 4, flags: DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !18) +!18 = !{} +!19 = !DILocation(line: 5, column: 10, scope: !17) +!20 = !DILocation(line: 6, column: 10, scope: !17) +!21 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "s2", file: !1, line: 3, size: 320, elements: !22) +!22 = !{!23} +!23 = !DIDerivedType(tag: DW_TAG_member, name: "a", scope: !21, file: !1, line: 3, baseType: !24, size: 320) +!24 = !DICompositeType(tag: DW_TAG_array_type, baseType: !12, size: 320, elements: !25) +!25 = !{!26} +!26 = !DISubrange(count: 10) +!27 = !DILocation(line: 5, column: 56, scope: !17) +!28 = !DILocation(line: 7, column: 10, scope: !17) +!29 = !DILocation(line: 6, column: 59, scope: !17) +!30 = !DILocation(line: 5, column: 3, scope: !17) diff --git a/llvm/test/CodeGen/SBF/CORE/intrinsic-typeinfo-type-match.ll b/llvm/test/CodeGen/SBF/CORE/intrinsic-typeinfo-type-match.ll new file mode 100644 index 0000000000000..2163cb8062c34 --- /dev/null +++ b/llvm/test/CodeGen/SBF/CORE/intrinsic-typeinfo-type-match.ll @@ -0,0 +1,103 @@ +; RUN: opt -O2 %s | llvm-dis > %t1 +; RUN: llc -sbf-enable-btf-emission -filetype=asm -o - %t1 | FileCheck %s +; RUN: llc -sbf-enable-btf-emission -mattr=+alu32 -filetype=asm -o - %t1 | FileCheck %s +; +; Source: +; enum AA { VAL = 100 }; +; typedef int (*func_t)(void); +; struct s2 { int a[10]; }; +; int test() { +; return __builtin_preserve_type_info(*(func_t *)0, 2) + +; __builtin_preserve_type_info(*(struct s2 *)0, 2) + +; __builtin_preserve_type_info(*(enum AA *)0, 2); +; } +; Compiler flag to generate IR: +; clang -target bpf -S -O2 -g -emit-llvm -Xclang -disable-llvm-passes t1.c + +source_filename = "t1.c" +target datalayout = "e-m:e-p:64:64-i64:64-i128:128-n32:64-S128" +target triple = "sbf" + +; Function Attrs: nounwind +define dso_local i32 @test() #0 !dbg !18 { + %1 = call i32 @llvm.bpf.preserve.type.info(i32 0, i64 2), !dbg !20, !llvm.preserve.access.index !8 + %2 = call i32 @llvm.bpf.preserve.type.info(i32 1, i64 2), !dbg !21, !llvm.preserve.access.index !22 + %3 = add i32 %1, %2, !dbg !28 + %4 = call i32 @llvm.bpf.preserve.type.info(i32 2, i64 2), !dbg !29, !llvm.preserve.access.index !3 + %5 = add i32 %3, %4, !dbg !30 + ret i32 %5, !dbg !31 +} + +; CHECK: mov64 r{{[0-9]+}}, 1 +; CHECK: mov64 r{{[0-9]+}}, 1 +; CHECK: mov64 r{{[0-9]+}}, 1 +; CHECK: exit + +; CHECK: .long 16 # BTF_KIND_TYPEDEF(id = 4) +; CHECK: .long 40 # BTF_KIND_STRUCT(id = 7) +; CHECK: .long 65 # BTF_KIND_ENUM(id = 10) + +; CHECK: .ascii ".text" # string offset=10 +; CHECK: .ascii "func_t" # string offset=16 +; CHECK: .byte 48 # string offset=23 +; CHECK: .ascii "s2" # string offset=40 +; CHECK: .ascii "AA" # string offset=65 + +; CHECK: .long 16 # FieldReloc +; CHECK-NEXT: .long 10 # Field reloc section string offset=10 +; CHECK-NEXT: .long 3 +; CHECK-NEXT: .long .Ltmp{{[0-9]+}} +; CHECK-NEXT: .long 4 +; CHECK-NEXT: .long 23 +; CHECK-NEXT: .long 12 +; CHECK-NEXT: .long .Ltmp{{[0-9]+}} +; CHECK-NEXT: .long 7 +; CHECK-NEXT: .long 23 +; CHECK-NEXT: .long 12 +; CHECK-NEXT: .long .Ltmp{{[0-9]+}} +; CHECK-NEXT: .long 10 +; CHECK-NEXT: .long 23 +; CHECK-NEXT: .long 12 + +; Function Attrs: nounwind readnone +declare i32 @llvm.bpf.preserve.type.info(i32, i64) #1 + +attributes #0 = { nounwind "frame-pointer"="all" "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" } +attributes #1 = { nounwind readnone } + +!llvm.dbg.cu = !{!0} +!llvm.module.flags = !{!13, !14, !15, !16} +!llvm.ident = !{!17} + +!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 15.0.0 (https://github.com/llvm/llvm-project.git 3d974661fd15612259d37f603ddf21df7ee0e428)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, retainedTypes: !7, splitDebugInlining: false, nameTableKind: None) +!1 = !DIFile(filename: "t1.c", directory: "/tmp/tmp1", checksumkind: CSK_MD5, checksum: "53350e4a8003565f949c897f1fce8567") +!2 = !{!3} +!3 = !DICompositeType(tag: DW_TAG_enumeration_type, name: "AA", file: !1, line: 1, baseType: !4, size: 32, elements: !5) +!4 = !DIBasicType(name: "unsigned int", size: 32, encoding: DW_ATE_unsigned) +!5 = !{!6} +!6 = !DIEnumerator(name: "VAL", value: 100) +!7 = !{!8} +!8 = !DIDerivedType(tag: DW_TAG_typedef, name: "func_t", file: !1, line: 2, baseType: !9) +!9 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !10, size: 64) +!10 = !DISubroutineType(types: !11) +!11 = !{!12} +!12 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +!13 = !{i32 7, !"Dwarf Version", i32 5} +!14 = !{i32 2, !"Debug Info Version", i32 3} +!15 = !{i32 1, !"wchar_size", i32 4} +!16 = !{i32 7, !"frame-pointer", i32 2} +!17 = !{!"clang version 15.0.0 (https://github.com/llvm/llvm-project.git 3d974661fd15612259d37f603ddf21df7ee0e428)"} +!18 = distinct !DISubprogram(name: "test", scope: !1, file: !1, line: 4, type: !10, scopeLine: 4, flags: DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !19) +!19 = !{} +!20 = !DILocation(line: 5, column: 10, scope: !18) +!21 = !DILocation(line: 6, column: 10, scope: !18) +!22 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "s2", file: !1, line: 3, size: 320, elements: !23) +!23 = !{!24} +!24 = !DIDerivedType(tag: DW_TAG_member, name: "a", scope: !22, file: !1, line: 3, baseType: !25, size: 320) +!25 = !DICompositeType(tag: DW_TAG_array_type, baseType: !12, size: 320, elements: !26) +!26 = !{!27} +!27 = !DISubrange(count: 10) +!28 = !DILocation(line: 5, column: 56, scope: !18) +!29 = !DILocation(line: 7, column: 10, scope: !18) +!30 = !DILocation(line: 6, column: 59, scope: !18) +!31 = !DILocation(line: 5, column: 3, scope: !18) diff --git a/llvm/test/CodeGen/SBF/CORE/intrinsic-typeinfo-type-size-1.ll b/llvm/test/CodeGen/SBF/CORE/intrinsic-typeinfo-type-size-1.ll new file mode 100644 index 0000000000000..b3ed18a0158ea --- /dev/null +++ b/llvm/test/CodeGen/SBF/CORE/intrinsic-typeinfo-type-size-1.ll @@ -0,0 +1,101 @@ +; RUN: opt -O2 %s | llvm-dis > %t1 +; RUN: llc -sbf-enable-btf-emission -filetype=asm -o - %t1 | FileCheck %s +; RUN: llc -sbf-enable-btf-emission -mattr=+alu32 -filetype=asm -o - %t1 | FileCheck %s +; +; Source: +; enum AA { VAL = 100 }; +; typedef int (*func_t)(void); +; struct s2 { int a[10]; }; +; int test() { +; return __builtin_preserve_type_info(*(func_t *)0, 1) + +; __builtin_preserve_type_info(*(struct s2 *)0, 1) + +; __builtin_preserve_type_info(*(enum AA *)0, 1); +; } +; Compiler flag to generate IR: +; clang -target bpf -S -O2 -g -emit-llvm -Xclang -disable-llvm-passes t1.c + +target triple = "sbf" + +; Function Attrs: nounwind readnone +define dso_local i32 @test() local_unnamed_addr #0 !dbg !17 { +entry: + %0 = tail call i32 @llvm.bpf.preserve.type.info(i32 0, i64 1), !dbg !19, !llvm.preserve.access.index !8 + %1 = tail call i32 @llvm.bpf.preserve.type.info(i32 1, i64 1), !dbg !20, !llvm.preserve.access.index !21 + %add = add i32 %1, %0, !dbg !27 + %2 = tail call i32 @llvm.bpf.preserve.type.info(i32 2, i64 1), !dbg !28, !llvm.preserve.access.index !3 + %add1 = add i32 %add, %2, !dbg !29 + ret i32 %add1, !dbg !30 +} + +; CHECK: mov64 r{{[0-9]+}}, 8 +; CHECK: mov64 r{{[0-9]+}}, 40 +; CHECK: mov64 r{{[0-9]+}}, 4 +; CHECK: exit + +; CHECK: .long 16 # BTF_KIND_TYPEDEF(id = 4) +; CHECK: .long 49 # BTF_KIND_STRUCT(id = 7) +; CHECK: .long 74 # BTF_KIND_ENUM(id = 10) + +; CHECK: .ascii ".text" # string offset=10 +; CHECK: .ascii "func_t" # string offset=16 +; CHECK: .byte 48 # string offset=23 +; CHECK: .ascii "s2" # string offset=49 +; CHECK: .ascii "AA" # string offset=74 + +; CHECK: .long 16 # FieldReloc +; CHECK-NEXT: .long 10 # Field reloc section string offset=10 +; CHECK-NEXT: .long 3 +; CHECK-NEXT: .long .Ltmp{{[0-9]+}} +; CHECK-NEXT: .long 4 +; CHECK-NEXT: .long 23 +; CHECK-NEXT: .long 9 +; CHECK-NEXT: .long .Ltmp{{[0-9]+}} +; CHECK-NEXT: .long 7 +; CHECK-NEXT: .long 23 +; CHECK-NEXT: .long 9 +; CHECK-NEXT: .long .Ltmp{{[0-9]+}} +; CHECK-NEXT: .long 10 +; CHECK-NEXT: .long 23 +; CHECK-NEXT: .long 9 + +; Function Attrs: nounwind readnone +declare i32 @llvm.bpf.preserve.type.info(i32, i64) #1 + +attributes #0 = { nounwind readnone "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" } +attributes #1 = { nounwind readnone } + +!llvm.dbg.cu = !{!0} +!llvm.module.flags = !{!13, !14, !15} +!llvm.ident = !{!16} + +!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 12.0.0 (https://github.com/llvm/llvm-project.git d8b1394a0f4bbf57c254f69f8d3aa5381a89b5cd)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, retainedTypes: !7, splitDebugInlining: false, nameTableKind: None) +!1 = !DIFile(filename: "t1.c", directory: "/tmp/home/yhs/tmp1") +!2 = !{!3} +!3 = !DICompositeType(tag: DW_TAG_enumeration_type, name: "AA", file: !1, line: 1, baseType: !4, size: 32, elements: !5) +!4 = !DIBasicType(name: "unsigned int", size: 32, encoding: DW_ATE_unsigned) +!5 = !{!6} +!6 = !DIEnumerator(name: "VAL", value: 100, isUnsigned: true) +!7 = !{!8} +!8 = !DIDerivedType(tag: DW_TAG_typedef, name: "func_t", file: !1, line: 2, baseType: !9) +!9 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !10, size: 64) +!10 = !DISubroutineType(types: !11) +!11 = !{!12} +!12 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +!13 = !{i32 7, !"Dwarf Version", i32 4} +!14 = !{i32 2, !"Debug Info Version", i32 3} +!15 = !{i32 1, !"wchar_size", i32 4} +!16 = !{!"clang version 12.0.0 (https://github.com/llvm/llvm-project.git d8b1394a0f4bbf57c254f69f8d3aa5381a89b5cd)"} +!17 = distinct !DISubprogram(name: "test", scope: !1, file: !1, line: 4, type: !10, scopeLine: 4, flags: DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !18) +!18 = !{} +!19 = !DILocation(line: 5, column: 10, scope: !17) +!20 = !DILocation(line: 6, column: 10, scope: !17) +!21 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "s2", file: !1, line: 3, size: 320, elements: !22) +!22 = !{!23} +!23 = !DIDerivedType(tag: DW_TAG_member, name: "a", scope: !21, file: !1, line: 3, baseType: !24, size: 320) +!24 = !DICompositeType(tag: DW_TAG_array_type, baseType: !12, size: 320, elements: !25) +!25 = !{!26} +!26 = !DISubrange(count: 10) +!27 = !DILocation(line: 5, column: 56, scope: !17) +!28 = !DILocation(line: 7, column: 10, scope: !17) +!29 = !DILocation(line: 6, column: 59, scope: !17) +!30 = !DILocation(line: 5, column: 3, scope: !17) diff --git a/llvm/test/CodeGen/SBF/CORE/intrinsic-typeinfo-type-size-2.ll b/llvm/test/CodeGen/SBF/CORE/intrinsic-typeinfo-type-size-2.ll new file mode 100644 index 0000000000000..256ca6af35b2d --- /dev/null +++ b/llvm/test/CodeGen/SBF/CORE/intrinsic-typeinfo-type-size-2.ll @@ -0,0 +1,117 @@ +; RUN: opt -O2 %s | llvm-dis > %t1 +; RUN: llc -sbf-enable-btf-emission -filetype=asm -o - %t1 | FileCheck %s +; RUN: llc -sbf-enable-btf-emission -mattr=+alu32 -filetype=asm -o - %t1 | FileCheck %s +; +; Source: +; enum AA { VAL = 100 }; +; typedef int (*func_t)(void); +; struct s2 { int a[10]; }; +; int test() { +; func_t f; +; struct s2 s; +; enum AA a; +; return __builtin_preserve_type_info(f, 1) + +; __builtin_preserve_type_info(s, 1) + +; __builtin_preserve_type_info(a, 1); +; } +; Compiler flag to generate IR: +; clang -target bpf -S -O2 -g -emit-llvm -Xclang -disable-llvm-passes t1.c + +target triple = "sbf" + +; Function Attrs: nounwind readnone +define dso_local i32 @test() local_unnamed_addr #0 !dbg !17 { +entry: + call void @llvm.dbg.declare(metadata [10 x i32]* undef, metadata !20, metadata !DIExpression()), !dbg !28 + call void @llvm.dbg.declare(metadata i32 ()** undef, metadata !19, metadata !DIExpression()), !dbg !29 + call void @llvm.dbg.declare(metadata i32* undef, metadata !27, metadata !DIExpression()), !dbg !30 + %0 = tail call i32 @llvm.bpf.preserve.type.info(i32 0, i64 1), !dbg !31, !llvm.preserve.access.index !8 + %1 = tail call i32 @llvm.bpf.preserve.type.info(i32 1, i64 1), !dbg !32, !llvm.preserve.access.index !21 + %add = add i32 %1, %0, !dbg !33 + %2 = tail call i32 @llvm.bpf.preserve.type.info(i32 2, i64 1), !dbg !34, !llvm.preserve.access.index !3 + %add1 = add i32 %add, %2, !dbg !35 + ret i32 %add1, !dbg !36 +} + +; CHECK: mov64 r{{[0-9]+}}, 8 +; CHECK: mov64 r{{[0-9]+}}, 40 +; CHECK: mov64 r{{[0-9]+}}, 4 +; CHECK: exit + +; CHECK: .long 16 # BTF_KIND_TYPEDEF(id = 4) +; CHECK: .long 49 # BTF_KIND_STRUCT(id = 7) +; CHECK: .long 74 # BTF_KIND_ENUM(id = 10) + +; CHECK: .ascii ".text" # string offset=10 +; CHECK: .ascii "func_t" # string offset=16 +; CHECK: .byte 48 # string offset=23 +; CHECK: .ascii "s2" # string offset=49 +; CHECK: .ascii "AA" # string offset=74 + +; CHECK: .long 16 # FieldReloc +; CHECK-NEXT: .long 10 # Field reloc section string offset=10 +; CHECK-NEXT: .long 3 +; CHECK-NEXT: .long .Ltmp{{[0-9]+}} +; CHECK-NEXT: .long 4 +; CHECK-NEXT: .long 23 +; CHECK-NEXT: .long 9 +; CHECK-NEXT: .long .Ltmp{{[0-9]+}} +; CHECK-NEXT: .long 7 +; CHECK-NEXT: .long 23 +; CHECK-NEXT: .long 9 +; CHECK-NEXT: .long .Ltmp{{[0-9]+}} +; CHECK-NEXT: .long 10 +; CHECK-NEXT: .long 23 +; CHECK-NEXT: .long 9 + +; Function Attrs: nounwind readnone speculatable willreturn +declare void @llvm.dbg.declare(metadata, metadata, metadata) #1 + +; Function Attrs: nounwind readnone +declare i32 @llvm.bpf.preserve.type.info(i32, i64) #2 + +attributes #0 = { nounwind readnone "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" } +attributes #1 = { nounwind readnone speculatable willreturn } +attributes #2 = { nounwind readnone } + +!llvm.dbg.cu = !{!0} +!llvm.module.flags = !{!13, !14, !15} +!llvm.ident = !{!16} + +!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 12.0.0 (https://github.com/llvm/llvm-project.git d8b1394a0f4bbf57c254f69f8d3aa5381a89b5cd)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, retainedTypes: !7, splitDebugInlining: false, nameTableKind: None) +!1 = !DIFile(filename: "t1.c", directory: "/tmp/home/yhs/tmp1") +!2 = !{!3} +!3 = !DICompositeType(tag: DW_TAG_enumeration_type, name: "AA", file: !1, line: 1, baseType: !4, size: 32, elements: !5) +!4 = !DIBasicType(name: "unsigned int", size: 32, encoding: DW_ATE_unsigned) +!5 = !{!6} +!6 = !DIEnumerator(name: "VAL", value: 100, isUnsigned: true) +!7 = !{!8} +!8 = !DIDerivedType(tag: DW_TAG_typedef, name: "func_t", file: !1, line: 2, baseType: !9) +!9 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !10, size: 64) +!10 = !DISubroutineType(types: !11) +!11 = !{!12} +!12 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +!13 = !{i32 7, !"Dwarf Version", i32 4} +!14 = !{i32 2, !"Debug Info Version", i32 3} +!15 = !{i32 1, !"wchar_size", i32 4} +!16 = !{!"clang version 12.0.0 (https://github.com/llvm/llvm-project.git d8b1394a0f4bbf57c254f69f8d3aa5381a89b5cd)"} +!17 = distinct !DISubprogram(name: "test", scope: !1, file: !1, line: 4, type: !10, scopeLine: 4, flags: DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !18) +!18 = !{!19, !20, !27} +!19 = !DILocalVariable(name: "f", scope: !17, file: !1, line: 5, type: !8) +!20 = !DILocalVariable(name: "s", scope: !17, file: !1, line: 6, type: !21) +!21 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "s2", file: !1, line: 3, size: 320, elements: !22) +!22 = !{!23} +!23 = !DIDerivedType(tag: DW_TAG_member, name: "a", scope: !21, file: !1, line: 3, baseType: !24, size: 320) +!24 = !DICompositeType(tag: DW_TAG_array_type, baseType: !12, size: 320, elements: !25) +!25 = !{!26} +!26 = !DISubrange(count: 10) +!27 = !DILocalVariable(name: "a", scope: !17, file: !1, line: 7, type: !3) +!28 = !DILocation(line: 6, column: 13, scope: !17) +!29 = !DILocation(line: 5, column: 10, scope: !17) +!30 = !DILocation(line: 7, column: 11, scope: !17) +!31 = !DILocation(line: 8, column: 10, scope: !17) +!32 = !DILocation(line: 9, column: 10, scope: !17) +!33 = !DILocation(line: 8, column: 45, scope: !17) +!34 = !DILocation(line: 10, column: 10, scope: !17) +!35 = !DILocation(line: 9, column: 45, scope: !17) +!36 = !DILocation(line: 8, column: 3, scope: !17) diff --git a/llvm/test/CodeGen/SBF/CORE/intrinsic-union.ll b/llvm/test/CodeGen/SBF/CORE/intrinsic-union.ll new file mode 100644 index 0000000000000..d926508e5c10f --- /dev/null +++ b/llvm/test/CodeGen/SBF/CORE/intrinsic-union.ll @@ -0,0 +1,81 @@ +; RUN: opt -O2 %s | llvm-dis > %t1 +; RUN: llc -sbf-enable-btf-emission -filetype=asm -o - %t1 | FileCheck %s +; RUN: llc -sbf-enable-btf-emission -mattr=+alu32 -filetype=asm -o - %t1 | FileCheck %s +; +; Source code: +; union u { int a; int b; }; +; #define _(x) (__builtin_preserve_access_index(x)) +; int get_value(const void *addr); +; int test(union u *arg) { return get_value(_(&arg->b)); } +; Compiler flag to generate IR: +; clang -target bpf -S -O2 -g -emit-llvm -Xclang -disable-llvm-passes test.c + +target triple = "sbf" + +%union.u = type { i32 } + +; Function Attrs: nounwind +define dso_local i32 @test(%union.u* %arg) local_unnamed_addr #0 !dbg !7 { +entry: + call void @llvm.dbg.value(metadata %union.u* %arg, metadata !17, metadata !DIExpression()), !dbg !18 + %0 = tail call %union.u* @llvm.preserve.union.access.index.p0s_union.us.p0s_union.us(%union.u* %arg, i32 1), !dbg !19, !llvm.preserve.access.index !12 + %1 = bitcast %union.u* %0 to i8*, !dbg !19 + %call = tail call i32 @get_value(i8* %1) #4, !dbg !20 + ret i32 %call, !dbg !21 +} +; CHECK-LABEL: test +; CHECK: [[RELOC:.Ltmp[0-9]+]] +; CHECK: mov64 r2, 0 +; CHECK: add64 r1, r2 +; CHECK: call get_value +; CHECK: exit + +; CHECK: .section .BTF.ext,"",@progbits +; CHECK: .long 16 # FieldReloc +; CHECK-NEXT: .long 20 # Field reloc section string offset=20 +; CHECK-NEXT: .long 1 +; CHECK-NEXT: .long [[RELOC]] +; CHECK-NEXT: .long 2 +; CHECK-NEXT: .long 26 +; CHECK-NEXT: .long 0 + +declare dso_local i32 @get_value(i8*) local_unnamed_addr #1 + +; Function Attrs: nounwind readnone +declare %union.u* @llvm.preserve.union.access.index.p0s_union.us.p0s_union.us(%union.u*, i32 immarg) #2 + +; Function Attrs: nounwind readnone speculatable +declare void @llvm.dbg.value(metadata, metadata, metadata) #3 + +attributes #0 = { nounwind "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "frame-pointer"="all" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" } +attributes #1 = { "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "frame-pointer"="all" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" } +attributes #2 = { nounwind readnone } +attributes #3 = { nounwind readnone speculatable } +attributes #4 = { nounwind } + +!llvm.dbg.cu = !{!0} +!llvm.module.flags = !{!3, !4, !5} +!llvm.ident = !{!6} + +!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 9.0.0 (trunk 365789)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, nameTableKind: None) +!1 = !DIFile(filename: "test.c", directory: "/tmp/home/yhs/work/tests/core") +!2 = !{} +!3 = !{i32 2, !"Dwarf Version", i32 4} +!4 = !{i32 2, !"Debug Info Version", i32 3} +!5 = !{i32 1, !"wchar_size", i32 4} +!6 = !{!"clang version 9.0.0 (trunk 365789)"} +!7 = distinct !DISubprogram(name: "test", scope: !1, file: !1, line: 4, type: !8, scopeLine: 4, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !16) +!8 = !DISubroutineType(types: !9) +!9 = !{!10, !11} +!10 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +!11 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !12, size: 64) +!12 = distinct !DICompositeType(tag: DW_TAG_union_type, name: "u", file: !1, line: 1, size: 32, elements: !13) +!13 = !{!14, !15} +!14 = !DIDerivedType(tag: DW_TAG_member, name: "a", scope: !12, file: !1, line: 1, baseType: !10, size: 32) +!15 = !DIDerivedType(tag: DW_TAG_member, name: "b", scope: !12, file: !1, line: 1, baseType: !10, size: 32) +!16 = !{!17} +!17 = !DILocalVariable(name: "arg", arg: 1, scope: !7, file: !1, line: 4, type: !11) +!18 = !DILocation(line: 0, scope: !7) +!19 = !DILocation(line: 4, column: 43, scope: !7) +!20 = !DILocation(line: 4, column: 33, scope: !7) +!21 = !DILocation(line: 4, column: 26, scope: !7) diff --git a/llvm/test/CodeGen/SBF/CORE/no-elf-ama-symbol.ll b/llvm/test/CodeGen/SBF/CORE/no-elf-ama-symbol.ll new file mode 100644 index 0000000000000..e74a39c0bb4d0 --- /dev/null +++ b/llvm/test/CodeGen/SBF/CORE/no-elf-ama-symbol.ll @@ -0,0 +1,66 @@ +; RUN: opt -O2 %s | llvm-dis > %t1 +; RUN: llc -sbf-enable-btf-emission -filetype=obj -o - %t1 | llvm-readelf -s - | FileCheck -check-prefixes=CHECK %s +; RUN: llc -sbf-enable-btf-emission -filetype=obj -addrsig -o - %t1 | llvm-readelf -s - | FileCheck -check-prefixes=CHECK %s +; +; Source Code: +; struct tt { int a; } __attribute__((preserve_access_index)); +; int test(struct tt *arg) { +; return arg->a; +; } +; Compilation flag: +; clang -target bpf -O2 -g -S -emit-llvm -Xclang -disable-llvm-passes t.c + +target triple = "sbf" + +%struct.tt = type { i32 } + +; Function Attrs: nounwind readonly +define dso_local i32 @test(%struct.tt* readonly %arg) local_unnamed_addr #0 !dbg !7 { +entry: + call void @llvm.dbg.value(metadata %struct.tt* %arg, metadata !16, metadata !DIExpression()), !dbg !17 + %0 = tail call i32* @llvm.preserve.struct.access.index.p0i32.p0s_struct.tts(%struct.tt* elementtype(%struct.tt) %arg, i32 0, i32 0), !dbg !18, !llvm.preserve.access.index !12 + %1 = load i32, i32* %0, align 4, !dbg !18, !tbaa !19 + ret i32 %1, !dbg !24 +} + +; CHECK-NOT: llvm.tt:0:0$0:0 + +; Function Attrs: nounwind readnone +declare i32* @llvm.preserve.struct.access.index.p0i32.p0s_struct.tts(%struct.tt*, i32, i32) #1 + +; Function Attrs: nounwind readnone speculatable +declare void @llvm.dbg.value(metadata, metadata, metadata) #2 + +attributes #0 = { nounwind readonly "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" } +attributes #1 = { nounwind readnone } +attributes #2 = { nounwind readnone speculatable} + +!llvm.dbg.cu = !{!0} +!llvm.module.flags = !{!3, !4, !5} +!llvm.ident = !{!6} + +!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 10.0.0 (https://github.com/llvm/llvm-project.git 947f9692440836dcb8d88b74b69dd379d85974ce)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, nameTableKind: None) +!1 = !DIFile(filename: "test.c", directory: "/tmp/home/yhs/work/tests/bug") +!2 = !{} +!3 = !{i32 7, !"Dwarf Version", i32 4} +!4 = !{i32 2, !"Debug Info Version", i32 3} +!5 = !{i32 1, !"wchar_size", i32 4} +!6 = !{!"clang version 10.0.0 (https://github.com/llvm/llvm-project.git 947f9692440836dcb8d88b74b69dd379d85974ce)"} +!7 = distinct !DISubprogram(name: "test", scope: !1, file: !1, line: 2, type: !8, scopeLine: 2, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !15) +!8 = !DISubroutineType(types: !9) +!9 = !{!10, !11} +!10 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +!11 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !12, size: 64) +!12 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "tt", file: !1, line: 1, size: 32, elements: !13) +!13 = !{!14} +!14 = !DIDerivedType(tag: DW_TAG_member, name: "a", scope: !12, file: !1, line: 1, baseType: !10, size: 32) +!15 = !{!16} +!16 = !DILocalVariable(name: "arg", arg: 1, scope: !7, file: !1, line: 2, type: !11) +!17 = !DILocation(line: 0, scope: !7) +!18 = !DILocation(line: 3, column: 15, scope: !7) +!19 = !{!20, !21, i64 0} +!20 = !{!"tt", !21, i64 0} +!21 = !{!"int", !22, i64 0} +!22 = !{!"omnipotent char", !23, i64 0} +!23 = !{!"Simple C/C++ TBAA"} +!24 = !DILocation(line: 3, column: 3, scope: !7) diff --git a/llvm/test/CodeGen/SBF/CORE/no-narrow-load.ll b/llvm/test/CodeGen/SBF/CORE/no-narrow-load.ll new file mode 100644 index 0000000000000..957fb0956065d --- /dev/null +++ b/llvm/test/CodeGen/SBF/CORE/no-narrow-load.ll @@ -0,0 +1,158 @@ +; RUN: opt -O2 %s | llvm-dis > %t1 +; RUN: llc -sbf-enable-btf-emission -filetype=asm -o - %t1 | FileCheck -check-prefixes=CHECK %s +; Source code: +; struct data_t { +; int d1; +; int d2; +; }; +; struct info_t { +; int pid; +; int flags; +; } __attribute__((preserve_access_index)); +; +; extern void output(void *); +; void test(struct info_t * args) { +; int is_mask2 = args->flags & 0x10000; +; struct data_t data = {}; +; +; data.d1 = is_mask2 ? 2 : args->pid; +; data.d2 = (is_mask2 || (args->flags & 0x8000)) ? 1 : 2; +; output(&data); +; } +; Compilation flag: +; clang -target bpf -O2 -g -S -emit-llvm -Xclang -disable-llvm-passes test.c + +target triple = "sbf" + +%struct.info_t = type { i32, i32 } +%struct.data_t = type { i32, i32 } + +; Function Attrs: nounwind +define dso_local void @test(%struct.info_t* readonly %args) local_unnamed_addr #0 !dbg !12 { +entry: + %data = alloca i64, align 8 + %tmpcast = bitcast i64* %data to %struct.data_t* + call void @llvm.dbg.value(metadata %struct.info_t* %args, metadata !22, metadata !DIExpression()), !dbg !29 + %0 = tail call i32* @llvm.preserve.struct.access.index.p0i32.p0s_struct.info_ts(%struct.info_t* elementtype(%struct.info_t) %args, i32 1, i32 1), !dbg !30, !llvm.preserve.access.index !16 + %1 = load i32, i32* %0, align 4, !dbg !30, !tbaa !31 + %and = and i32 %1, 65536, !dbg !36 + call void @llvm.dbg.value(metadata i32 %and, metadata !23, metadata !DIExpression()), !dbg !29 + %2 = bitcast i64* %data to i8*, !dbg !37 + call void @llvm.lifetime.start.p0i8(i64 8, i8* nonnull %2) #5, !dbg !37 + call void @llvm.dbg.declare(metadata %struct.data_t* %tmpcast, metadata !24, metadata !DIExpression()), !dbg !38 + store i64 0, i64* %data, align 8, !dbg !38 + %tobool = icmp eq i32 %and, 0, !dbg !39 + br i1 %tobool, label %cond.false, label %lor.end.critedge, !dbg !39 + +cond.false: ; preds = %entry + %3 = tail call i32* @llvm.preserve.struct.access.index.p0i32.p0s_struct.info_ts(%struct.info_t* elementtype(%struct.info_t) %args, i32 0, i32 0), !dbg !40, !llvm.preserve.access.index !16 + %4 = load i32, i32* %3, align 4, !dbg !40, !tbaa !41 + %d1 = bitcast i64* %data to i32*, !dbg !42 + store i32 %4, i32* %d1, align 8, !dbg !43, !tbaa !44 + %5 = load i32, i32* %0, align 4, !dbg !46, !tbaa !31 + %and2 = and i32 %5, 32768, !dbg !47 + %tobool3 = icmp eq i32 %and2, 0, !dbg !48 + %phitmp = select i1 %tobool3, i32 2, i32 1, !dbg !48 + br label %lor.end, !dbg !48 + +lor.end.critedge: ; preds = %entry + %d1.c = bitcast i64* %data to i32*, !dbg !42 + store i32 2, i32* %d1.c, align 8, !dbg !43, !tbaa !44 + br label %lor.end, !dbg !48 + +lor.end: ; preds = %lor.end.critedge, %cond.false + %6 = phi i32 [ %phitmp, %cond.false ], [ 1, %lor.end.critedge ] + %d2 = getelementptr inbounds %struct.data_t, %struct.data_t* %tmpcast, i64 0, i32 1, !dbg !49 + store i32 %6, i32* %d2, align 4, !dbg !50, !tbaa !51 + call void @output(i8* nonnull %2) #5, !dbg !52 + call void @llvm.lifetime.end.p0i8(i64 8, i8* nonnull %2) #5, !dbg !53 + ret void, !dbg !53 +} + +; CHECK: ldxw r[[LOAD1:[0-9]+]], [r{{[0-9]+}} + 4] +; CHECK: mov64 r[[LOAD2:[0-9]+]], r[[LOAD1:[0-9]+]] +; CHECK: and64 r[[LOAD2]], 65536 +; CHECK: and64 r[[LOAD1]], 32768 + +; Function Attrs: nounwind readnone speculatable willreturn +declare void @llvm.dbg.declare(metadata, metadata, metadata) #1 + +; Function Attrs: argmemonly nounwind willreturn +declare void @llvm.lifetime.start.p0i8(i64 immarg, i8* nocapture) #2 + +; Function Attrs: nounwind readnone +declare i32* @llvm.preserve.struct.access.index.p0i32.p0s_struct.info_ts(%struct.info_t*, i32 immarg, i32 immarg) #3 + +declare !dbg !4 dso_local void @output(i8*) local_unnamed_addr #4 + +; Function Attrs: argmemonly nounwind willreturn +declare void @llvm.lifetime.end.p0i8(i64 immarg, i8* nocapture) #2 + +; Function Attrs: nounwind readnone speculatable willreturn +declare void @llvm.dbg.value(metadata, metadata, metadata) #1 + +attributes #0 = { nounwind "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" } +attributes #1 = { nounwind readnone speculatable willreturn } +attributes #2 = { argmemonly nounwind willreturn } +attributes #3 = { nounwind readnone } +attributes #4 = { "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" } +attributes #5 = { nounwind } + +!llvm.dbg.cu = !{!0} +!llvm.module.flags = !{!8, !9, !10} +!llvm.ident = !{!11} + +!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 11.0.0 (https://github.com/llvm/llvm-project.git 5884aae58f56786475bbc0f13ad8bd35f7f1ce69)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, retainedTypes: !3, splitDebugInlining: false, nameTableKind: None) +!1 = !DIFile(filename: "test.c", directory: "/tmp/home/yhs/work/tests/core") +!2 = !{} +!3 = !{!4} +!4 = !DISubprogram(name: "output", scope: !1, file: !1, line: 10, type: !5, flags: DIFlagPrototyped, spFlags: DISPFlagOptimized, retainedNodes: !2) +!5 = !DISubroutineType(types: !6) +!6 = !{null, !7} +!7 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: null, size: 64) +!8 = !{i32 7, !"Dwarf Version", i32 4} +!9 = !{i32 2, !"Debug Info Version", i32 3} +!10 = !{i32 1, !"wchar_size", i32 4} +!11 = !{!"clang version 11.0.0 (https://github.com/llvm/llvm-project.git 5884aae58f56786475bbc0f13ad8bd35f7f1ce69)"} +!12 = distinct !DISubprogram(name: "test", scope: !1, file: !1, line: 11, type: !13, scopeLine: 11, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !21) +!13 = !DISubroutineType(types: !14) +!14 = !{null, !15} +!15 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !16, size: 64) +!16 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "info_t", file: !1, line: 5, size: 64, elements: !17) +!17 = !{!18, !20} +!18 = !DIDerivedType(tag: DW_TAG_member, name: "pid", scope: !16, file: !1, line: 6, baseType: !19, size: 32) +!19 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +!20 = !DIDerivedType(tag: DW_TAG_member, name: "flags", scope: !16, file: !1, line: 7, baseType: !19, size: 32, offset: 32) +!21 = !{!22, !23, !24} +!22 = !DILocalVariable(name: "args", arg: 1, scope: !12, file: !1, line: 11, type: !15) +!23 = !DILocalVariable(name: "is_mask2", scope: !12, file: !1, line: 12, type: !19) +!24 = !DILocalVariable(name: "data", scope: !12, file: !1, line: 13, type: !25) +!25 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "data_t", file: !1, line: 1, size: 64, elements: !26) +!26 = !{!27, !28} +!27 = !DIDerivedType(tag: DW_TAG_member, name: "d1", scope: !25, file: !1, line: 2, baseType: !19, size: 32) +!28 = !DIDerivedType(tag: DW_TAG_member, name: "d2", scope: !25, file: !1, line: 3, baseType: !19, size: 32, offset: 32) +!29 = !DILocation(line: 0, scope: !12) +!30 = !DILocation(line: 12, column: 24, scope: !12) +!31 = !{!32, !33, i64 4} +!32 = !{!"info_t", !33, i64 0, !33, i64 4} +!33 = !{!"int", !34, i64 0} +!34 = !{!"omnipotent char", !35, i64 0} +!35 = !{!"Simple C/C++ TBAA"} +!36 = !DILocation(line: 12, column: 30, scope: !12) +!37 = !DILocation(line: 13, column: 3, scope: !12) +!38 = !DILocation(line: 13, column: 17, scope: !12) +!39 = !DILocation(line: 15, column: 13, scope: !12) +!40 = !DILocation(line: 15, column: 34, scope: !12) +!41 = !{!32, !33, i64 0} +!42 = !DILocation(line: 15, column: 8, scope: !12) +!43 = !DILocation(line: 15, column: 11, scope: !12) +!44 = !{!45, !33, i64 0} +!45 = !{!"data_t", !33, i64 0, !33, i64 4} +!46 = !DILocation(line: 16, column: 33, scope: !12) +!47 = !DILocation(line: 16, column: 39, scope: !12) +!48 = !DILocation(line: 16, column: 23, scope: !12) +!49 = !DILocation(line: 16, column: 8, scope: !12) +!50 = !DILocation(line: 16, column: 11, scope: !12) +!51 = !{!45, !33, i64 4} +!52 = !DILocation(line: 17, column: 3, scope: !12) +!53 = !DILocation(line: 18, column: 1, scope: !12) diff --git a/llvm/test/CodeGen/SBF/CORE/offset-reloc-access-str.ll b/llvm/test/CodeGen/SBF/CORE/offset-reloc-access-str.ll new file mode 100644 index 0000000000000..3457b95be2c42 --- /dev/null +++ b/llvm/test/CodeGen/SBF/CORE/offset-reloc-access-str.ll @@ -0,0 +1,100 @@ +; RUN: opt -O2 %s | llvm-dis > %t1 +; RUN: llc -sbf-enable-btf-emission -filetype=asm -o - %t1 | FileCheck %s +; RUN: llc -sbf-enable-btf-emission -mattr=+alu32 -filetype=asm -o - %t1 | FileCheck %s +; +; Source code: +; struct s { int a; int b; }; +; struct t { int c; int d; }; +; #define _(x) (__builtin_preserve_access_index(x)) +; int get_value(const void *addr1, const void *addr2); +; int test(struct s *arg1, struct t *arg2) { +; return get_value(_(&arg1->b), _(&arg2->d)); +; } +; clang -target bpf -S -O2 -g -emit-llvm -Xclang -disable-llvm-passes test.c + +target triple = "sbf" + +%struct.s = type { i32, i32 } +%struct.t = type { i32, i32 } + +; Function Attrs: nounwind +define dso_local i32 @test(%struct.s* %arg1, %struct.t* %arg2) local_unnamed_addr #0 !dbg !7 { +entry: + call void @llvm.dbg.value(metadata %struct.s* %arg1, metadata !22, metadata !DIExpression()), !dbg !24 + call void @llvm.dbg.value(metadata %struct.t* %arg2, metadata !23, metadata !DIExpression()), !dbg !24 + %0 = tail call i32* @llvm.preserve.struct.access.index.p0i32.p0s_struct.ss(%struct.s* elementtype(%struct.s) %arg1, i32 1, i32 1), !dbg !25, !llvm.preserve.access.index !12 + %1 = bitcast i32* %0 to i8*, !dbg !25 + %2 = tail call i32* @llvm.preserve.struct.access.index.p0i32.p0s_struct.ts(%struct.t* elementtype(%struct.t) %arg2, i32 1, i32 1), !dbg !26, !llvm.preserve.access.index !17 + %3 = bitcast i32* %2 to i8*, !dbg !26 + %call = tail call i32 @get_value(i8* %1, i8* %3) #4, !dbg !27 + ret i32 %call, !dbg !28 +} + +; CHECK: .section .BTF,"",@progbits +; CHECK: .ascii ".text" # string offset=[[SEC_INDEX:[0-9]+]] +; CHECK-NEXT: .byte 0 +; CHECK: .ascii "0:1" # string offset=[[ACCESS_STR:[0-9]+]] +; CHECK-NEXT: .byte 0 +; CHECK: .section .BTF.ext,"",@progbits +; CHECK: .long 16 # FieldReloc +; CHECK-NEXT: .long [[SEC_INDEX]] # Field reloc section string offset=[[SEC_INDEX]] +; CHECK-NEXT: .long 2 +; CHECK-NEXT: .long .Ltmp{{[0-9]+}} +; CHECK-NEXT: .long {{[0-9]+}} +; CHECK-NEXT: .long [[ACCESS_STR]] +; CHECK-NEXT: .long 0 +; CHECK-NEXT: .long .Ltmp{{[0-9]+}} +; CHECK-NEXT: .long {{[0-9]+}} +; CHECK-NEXT: .long [[ACCESS_STR]] +; CHECK-NEXT: .long 0 + +declare dso_local i32 @get_value(i8*, i8*) local_unnamed_addr #1 + +; Function Attrs: nounwind readnone +declare i32* @llvm.preserve.struct.access.index.p0i32.p0s_struct.ss(%struct.s*, i32 immarg, i32 immarg) #2 + +; Function Attrs: nounwind readnone +declare i32* @llvm.preserve.struct.access.index.p0i32.p0s_struct.ts(%struct.t*, i32 immarg, i32 immarg) #2 + +; Function Attrs: nounwind readnone speculatable +declare void @llvm.dbg.value(metadata, metadata, metadata) #3 + +attributes #0 = { nounwind "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" } +attributes #1 = { "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" } +attributes #2 = { nounwind readnone } +attributes #3 = { nounwind readnone speculatable } +attributes #4 = { nounwind } + +!llvm.dbg.cu = !{!0} +!llvm.module.flags = !{!3, !4, !5} +!llvm.ident = !{!6} + +!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 10.0.0 (trunk 366831) (llvm/trunk 366867)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, nameTableKind: None) +!1 = !DIFile(filename: "test.c", directory: "/tmp/home/yhs/work/tests/llvm/core-bugs") +!2 = !{} +!3 = !{i32 2, !"Dwarf Version", i32 4} +!4 = !{i32 2, !"Debug Info Version", i32 3} +!5 = !{i32 1, !"wchar_size", i32 4} +!6 = !{!"clang version 10.0.0 (trunk 366831) (llvm/trunk 366867)"} +!7 = distinct !DISubprogram(name: "test", scope: !1, file: !1, line: 5, type: !8, scopeLine: 5, flags: DIFlagPrototyped, isDefinition: true, isOptimized: true, unit: !0, retainedNodes: !21) +!8 = !DISubroutineType(types: !9) +!9 = !{!10, !11, !16} +!10 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +!11 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !12, size: 64) +!12 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "s", file: !1, line: 1, size: 64, elements: !13) +!13 = !{!14, !15} +!14 = !DIDerivedType(tag: DW_TAG_member, name: "a", scope: !12, file: !1, line: 1, baseType: !10, size: 32) +!15 = !DIDerivedType(tag: DW_TAG_member, name: "b", scope: !12, file: !1, line: 1, baseType: !10, size: 32, offset: 32) +!16 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !17, size: 64) +!17 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "t", file: !1, line: 2, size: 64, elements: !18) +!18 = !{!19, !20} +!19 = !DIDerivedType(tag: DW_TAG_member, name: "c", scope: !17, file: !1, line: 2, baseType: !10, size: 32) +!20 = !DIDerivedType(tag: DW_TAG_member, name: "d", scope: !17, file: !1, line: 2, baseType: !10, size: 32, offset: 32) +!21 = !{!22, !23} +!22 = !DILocalVariable(name: "arg1", arg: 1, scope: !7, file: !1, line: 5, type: !11) +!23 = !DILocalVariable(name: "arg2", arg: 2, scope: !7, file: !1, line: 5, type: !16) +!24 = !DILocation(line: 0, scope: !7) +!25 = !DILocation(line: 6, column: 20, scope: !7) +!26 = !DILocation(line: 6, column: 33, scope: !7) +!27 = !DILocation(line: 6, column: 10, scope: !7) +!28 = !DILocation(line: 6, column: 3, scope: !7) diff --git a/llvm/test/CodeGen/SBF/CORE/offset-reloc-basic.ll b/llvm/test/CodeGen/SBF/CORE/offset-reloc-basic.ll new file mode 100644 index 0000000000000..71d9e2124090f --- /dev/null +++ b/llvm/test/CodeGen/SBF/CORE/offset-reloc-basic.ll @@ -0,0 +1,188 @@ +; RUN: opt -O2 %s | llvm-dis > %t1 +; RUN: llc -sbf-enable-btf-emission -filetype=asm -o - %t1 | FileCheck -check-prefixes=CHECK %s +; RUN: llc -sbf-enable-btf-emission -mattr=+alu32 -filetype=asm -o - %t1 | FileCheck -check-prefixes=CHECK %s +; Source code: +; struct sk_buff { +; int i; +; struct net_device *dev; +; }; +; #define _(x) (__builtin_preserve_access_index(x)) +; static int (*bpf_probe_read)(void *dst, int size, void *unsafe_ptr) +; = (void *) 4; +; +; int bpf_prog(struct sk_buff *ctx) { +; struct net_device *dev = 0; +; bpf_probe_read(&dev, sizeof(dev), _(&ctx->dev)); +; return dev != 0; +; } +; Compilation flag: +; clang -target bpf -O2 -g -S -emit-llvm -Xclang -disable-llvm-passes test.c + +target triple = "sbf" + +%struct.sk_buff = type { i32, %struct.net_device* } +%struct.net_device = type opaque + +; Function Attrs: nounwind +define dso_local i32 @bpf_prog(%struct.sk_buff*) local_unnamed_addr #0 !dbg !15 { + %2 = alloca %struct.net_device*, align 8 + call void @llvm.dbg.value(metadata %struct.sk_buff* %0, metadata !26, metadata !DIExpression()), !dbg !28 + %3 = bitcast %struct.net_device** %2 to i8*, !dbg !29 + call void @llvm.lifetime.start.p0i8(i64 8, i8* nonnull %3) #4, !dbg !29 + call void @llvm.dbg.value(metadata %struct.net_device* null, metadata !27, metadata !DIExpression()), !dbg !28 + store %struct.net_device* null, %struct.net_device** %2, align 8, !dbg !30, !tbaa !31 + %4 = tail call %struct.net_device** @llvm.preserve.struct.access.index.p0p0s_struct.net_devices.p0s_struct.sk_buffs(%struct.sk_buff* elementtype(%struct.sk_buff) %0, i32 1, i32 1), !dbg !35, !llvm.preserve.access.index !19 + %5 = bitcast %struct.net_device** %4 to i8*, !dbg !35 + %6 = call i32 inttoptr (i64 4 to i32 (i8*, i32, i8*)*)(i8* nonnull %3, i32 8, i8* %5) #4, !dbg !36 + %7 = load %struct.net_device*, %struct.net_device** %2, align 8, !dbg !37, !tbaa !31 + call void @llvm.dbg.value(metadata %struct.net_device* %7, metadata !27, metadata !DIExpression()), !dbg !28 + %8 = icmp ne %struct.net_device* %7, null, !dbg !38 + %9 = zext i1 %8 to i32, !dbg !38 + call void @llvm.lifetime.end.p0i8(i64 8, i8* nonnull %3) #4, !dbg !39 + ret i32 %9, !dbg !40 +} + +; CHECK: .section .BTF,"",@progbits +; CHECK-NEXT: .short 60319 # 0xeb9f +; CHECK-NEXT: .byte 1 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .long 24 +; CHECK-NEXT: .long 0 +; CHECK-NEXT: .long 120 +; CHECK-NEXT: .long 120 +; CHECK-NEXT: .long 90 +; CHECK-NEXT: .long 0 # BTF_KIND_PTR(id = 1) +; CHECK-NEXT: .long 33554432 # 0x2000000 +; CHECK-NEXT: .long 2 +; CHECK-NEXT: .long 1 # BTF_KIND_STRUCT(id = 2) +; CHECK-NEXT: .long 67108866 # 0x4000002 +; CHECK-NEXT: .long 16 +; CHECK-NEXT: .long 9 +; CHECK-NEXT: .long 3 +; CHECK-NEXT: .long 0 # 0x0 +; CHECK-NEXT: .long 11 +; CHECK-NEXT: .long 4 +; CHECK-NEXT: .long 64 # 0x40 +; CHECK-NEXT: .long 15 # BTF_KIND_INT(id = 3) +; CHECK-NEXT: .long 16777216 # 0x1000000 +; CHECK-NEXT: .long 4 +; CHECK-NEXT: .long 16777248 # 0x1000020 +; CHECK-NEXT: .long 0 # BTF_KIND_PTR(id = 4) +; CHECK-NEXT: .long 33554432 # 0x2000000 +; CHECK-NEXT: .long 5 +; CHECK-NEXT: .long 19 # BTF_KIND_FWD(id = 5) +; CHECK-NEXT: .long 117440512 # 0x7000000 +; CHECK-NEXT: .long 0 +; CHECK-NEXT: .long 0 # BTF_KIND_FUNC_PROTO(id = 6) +; CHECK-NEXT: .long 218103809 # 0xd000001 +; CHECK-NEXT: .long 3 +; CHECK-NEXT: .long 30 +; CHECK-NEXT: .long 1 +; CHECK-NEXT: .long 34 # BTF_KIND_FUNC(id = 7) +; CHECK-NEXT: .long 201326593 # 0xc000001 +; CHECK-NEXT: .long 6 +; CHECK-NEXT: .byte 0 # string offset=0 +; CHECK-NEXT: .ascii "sk_buff" # string offset=1 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .byte 105 # string offset=9 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii "dev" # string offset=11 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii "int" # string offset=15 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii "net_device" # string offset=19 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii "ctx" # string offset=30 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii "bpf_prog" # string offset=34 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii ".text" # string offset=43 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii "/tmp/home/yhs/work/tests/llvm/test.c" # string offset=49 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii "0:1" # string offset=86 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .section .BTF.ext,"",@progbits +; CHECK-NEXT: .short 60319 # 0xeb9f +; CHECK-NEXT: .byte 1 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .long 32 +; CHECK-NEXT: .long 0 +; CHECK-NEXT: .long 20 +; CHECK-NEXT: .long 20 +; CHECK-NEXT: .long 124 +; CHECK-NEXT: .long 144 +; CHECK-NEXT: .long 28 +; CHECK-NEXT: .long 8 # FuncInfo + +; CHECK: .long 16 # FieldReloc +; CHECK-NEXT: .long 43 # Field reloc section string offset=43 +; CHECK-NEXT: .long 1 +; CHECK-NEXT: .long .Ltmp{{[0-9]+}} +; CHECK-NEXT: .long 2 +; CHECK-NEXT: .long 86 +; CHECK-NEXT: .long 0 + +; Function Attrs: argmemonly nounwind +declare void @llvm.lifetime.start.p0i8(i64 immarg, i8* nocapture) #1 + +; Function Attrs: nounwind readnone +declare %struct.net_device** @llvm.preserve.struct.access.index.p0p0s_struct.net_devices.p0s_struct.sk_buffs(%struct.sk_buff*, i32 immarg, i32 immarg) #2 + +; Function Attrs: argmemonly nounwind +declare void @llvm.lifetime.end.p0i8(i64 immarg, i8* nocapture) #1 + +; Function Attrs: nounwind readnone speculatable +declare void @llvm.dbg.value(metadata, metadata, metadata) #3 + +attributes #0 = { nounwind "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "frame-pointer"="all" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" } +attributes #1 = { argmemonly nounwind } +attributes #2 = { nounwind readnone } +attributes #3 = { nounwind readnone speculatable } +attributes #4 = { nounwind } + +!llvm.dbg.cu = !{!0} +!llvm.module.flags = !{!11, !12, !13} +!llvm.ident = !{!14} + +!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 9.0.0 (trunk 360739) (llvm/trunk 360747)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, globals: !3, nameTableKind: None) +!1 = !DIFile(filename: "test.c", directory: "/tmp/home/yhs/work/tests/llvm") +!2 = !{} +!3 = !{!4} +!4 = !DIGlobalVariableExpression(var: !5, expr: !DIExpression()) +!5 = distinct !DIGlobalVariable(name: "bpf_probe_read", scope: !0, file: !1, line: 6, type: !6, isLocal: true, isDefinition: true) +!6 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !7, size: 64) +!7 = !DISubroutineType(types: !8) +!8 = !{!9, !10, !9, !10} +!9 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +!10 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: null, size: 64) +!11 = !{i32 2, !"Dwarf Version", i32 4} +!12 = !{i32 2, !"Debug Info Version", i32 3} +!13 = !{i32 1, !"wchar_size", i32 4} +!14 = !{!"clang version 9.0.0 (trunk 360739) (llvm/trunk 360747)"} +!15 = distinct !DISubprogram(name: "bpf_prog", scope: !1, file: !1, line: 9, type: !16, scopeLine: 9, flags: DIFlagPrototyped, isLocal: false, isDefinition: true, isOptimized: true, unit: !0, retainedNodes: !25) +!16 = !DISubroutineType(types: !17) +!17 = !{!9, !18} +!18 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !19, size: 64) +!19 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "sk_buff", file: !1, line: 1, size: 128, elements: !20) +!20 = !{!21, !22} +!21 = !DIDerivedType(tag: DW_TAG_member, name: "i", scope: !19, file: !1, line: 2, baseType: !9, size: 32) +!22 = !DIDerivedType(tag: DW_TAG_member, name: "dev", scope: !19, file: !1, line: 3, baseType: !23, size: 64, offset: 64) +!23 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !24, size: 64) +!24 = !DICompositeType(tag: DW_TAG_structure_type, name: "net_device", file: !1, line: 3, flags: DIFlagFwdDecl) +!25 = !{!26, !27} +!26 = !DILocalVariable(name: "ctx", arg: 1, scope: !15, file: !1, line: 9, type: !18) +!27 = !DILocalVariable(name: "dev", scope: !15, file: !1, line: 10, type: !23) +!28 = !DILocation(line: 0, scope: !15) +!29 = !DILocation(line: 10, column: 3, scope: !15) +!30 = !DILocation(line: 10, column: 22, scope: !15) +!31 = !{!32, !32, i64 0} +!32 = !{!"any pointer", !33, i64 0} +!33 = !{!"omnipotent char", !34, i64 0} +!34 = !{!"Simple C/C++ TBAA"} +!35 = !DILocation(line: 11, column: 37, scope: !15) +!36 = !DILocation(line: 11, column: 3, scope: !15) +!37 = !DILocation(line: 12, column: 10, scope: !15) +!38 = !DILocation(line: 12, column: 14, scope: !15) +!39 = !DILocation(line: 13, column: 1, scope: !15) +!40 = !DILocation(line: 12, column: 3, scope: !15) diff --git a/llvm/test/CodeGen/SBF/CORE/offset-reloc-cast-array-1.ll b/llvm/test/CodeGen/SBF/CORE/offset-reloc-cast-array-1.ll new file mode 100644 index 0000000000000..c446ae45ee6ed --- /dev/null +++ b/llvm/test/CodeGen/SBF/CORE/offset-reloc-cast-array-1.ll @@ -0,0 +1,129 @@ +; RUN: opt -O2 %s | llvm-dis > %t1 +; RUN: llc -sbf-enable-btf-emission -filetype=asm -o - %t1 | FileCheck -check-prefixes=CHECK %s +; RUN: llc -sbf-enable-btf-emission -mattr=+alu32 -filetype=asm -o - %t1 | FileCheck -check-prefixes=CHECK %s +; Source code: +; struct v1 {int a; int b;}; +; typedef struct v1 __v1; +; typedef __v1 arr[4]; +; struct v3 { char c; int d[100]; }; +; #define _(x) (__builtin_preserve_access_index(x)) +; #define cast_to_arr(x) ((arr *)(x)) +; int get_value(const int *arg); +; int test(struct v3 *arg) { +; return get_value(_(&cast_to_arr(&arg->d[0])[0][2].b)); +; } +; Compilation flag: +; clang -target bpf -O2 -g -S -emit-llvm -Xclang -disable-llvm-passes test.c + +target triple = "sbf" + +%struct.v3 = type { i8, [100 x i32] } +%struct.v1 = type { i32, i32 } + +; Function Attrs: nounwind +define dso_local i32 @test(%struct.v3* %arg) local_unnamed_addr #0 !dbg !22 { +entry: + call void @llvm.dbg.value(metadata %struct.v3* %arg, metadata !32, metadata !DIExpression()), !dbg !33 + %0 = tail call [100 x i32]* @llvm.preserve.struct.access.index.p0a100i32.p0s_struct.v3s(%struct.v3* elementtype(%struct.v3) %arg, i32 1, i32 1), !dbg !34, !llvm.preserve.access.index !26 + %1 = tail call i32* @llvm.preserve.array.access.index.p0i32.p0a100i32([100 x i32]* elementtype([100 x i32]) %0, i32 1, i32 0), !dbg !34, !llvm.preserve.access.index !15 + %2 = bitcast i32* %1 to [4 x %struct.v1]*, !dbg !34 + %3 = tail call [4 x %struct.v1]* @llvm.preserve.array.access.index.p0a4s_struct.v1s.p0a4s_struct.v1s([4 x %struct.v1]* elementtype([4 x %struct.v1]) %2, i32 0, i32 0), !dbg !34, !llvm.preserve.access.index !4 + %4 = tail call %struct.v1* @llvm.preserve.array.access.index.p0s_struct.v1s.p0a4s_struct.v1s([4 x %struct.v1]* elementtype([4 x %struct.v1]) %3, i32 1, i32 2), !dbg !34, !llvm.preserve.access.index !5 + %5 = tail call i32* @llvm.preserve.struct.access.index.p0i32.p0s_struct.v1s(%struct.v1* elementtype(%struct.v1) %4, i32 1, i32 1), !dbg !34, !llvm.preserve.access.index !8 + %call = tail call i32 @get_value(i32* %5) #4, !dbg !35 + ret i32 %call, !dbg !36 +} + +; CHECK: mov64 r2, 4 +; CHECK: add64 r1, r2 +; CHECK: mov64 r2, 20 +; CHECK: add64 r1, r2 +; CHECK: call get_value + +; CHECK: .long 1 # BTF_KIND_STRUCT(id = [[TID1:[0-9]+]]) +; CHECK: .long 100 # BTF_KIND_STRUCT(id = [[TID2:[0-9]+]]) + +; CHECK: .ascii "v3" # string offset=1 +; CHECK: .ascii ".text" # string offset=46 +; CHECK: .ascii "0:1:0" # string offset=52 +; CHECK: .ascii "2:1" # string offset=107 + +; CHECK: .long 16 # FieldReloc +; CHECK-NEXT: .long 46 # Field reloc section string offset=46 +; CHECK-NEXT: .long 2 +; CHECK-NEXT: .long .Ltmp{{[0-9]+}} +; CHECK-NEXT: .long [[TID1]] +; CHECK-NEXT: .long 52 +; CHECK-NEXT: .long 0 +; CHECK-NEXT: .long .Ltmp{{[0-9]+}} +; CHECK-NEXT: .long [[TID2]] +; CHECK-NEXT: .long 107 +; CHECK-NEXT: .long 0 + +declare dso_local i32 @get_value(i32*) local_unnamed_addr #1 + +; Function Attrs: nounwind readnone +declare [100 x i32]* @llvm.preserve.struct.access.index.p0a100i32.p0s_struct.v3s(%struct.v3*, i32, i32) #2 + +; Function Attrs: nounwind readnone +declare i32* @llvm.preserve.array.access.index.p0i32.p0a100i32([100 x i32]*, i32, i32) #2 + +; Function Attrs: nounwind readnone +declare [4 x %struct.v1]* @llvm.preserve.array.access.index.p0a4s_struct.v1s.p0a4s_struct.v1s([4 x %struct.v1]*, i32, i32) #2 + +; Function Attrs: nounwind readnone +declare %struct.v1* @llvm.preserve.array.access.index.p0s_struct.v1s.p0a4s_struct.v1s([4 x %struct.v1]*, i32, i32) #2 + +; Function Attrs: nounwind readnone +declare i32* @llvm.preserve.struct.access.index.p0i32.p0s_struct.v1s(%struct.v1*, i32, i32) #2 + +; Function Attrs: nounwind readnone speculatable willreturn +declare void @llvm.dbg.value(metadata, metadata, metadata) #3 + +attributes #0 = { nounwind "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" } +attributes #1 = { "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" } +attributes #2 = { nounwind readnone } +attributes #3 = { nounwind readnone speculatable willreturn } +attributes #4 = { nounwind } + +!llvm.dbg.cu = !{!0} +!llvm.module.flags = !{!18, !19, !20} +!llvm.ident = !{!21} + +!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 10.0.0 (trunk 367256) (llvm/trunk 367266)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, retainedTypes: !3, nameTableKind: None) +!1 = !DIFile(filename: "test.c", directory: "/tmp/home/yhs/work/tests/llvm/cast") +!2 = !{} +!3 = !{!4, !15, !5} +!4 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !5, size: 64) +!5 = !DIDerivedType(tag: DW_TAG_typedef, name: "arr", file: !1, line: 3, baseType: !6) +!6 = !DICompositeType(tag: DW_TAG_array_type, baseType: !7, size: 256, elements: !13) +!7 = !DIDerivedType(tag: DW_TAG_typedef, name: "__v1", file: !1, line: 2, baseType: !8) +!8 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "v1", file: !1, line: 1, size: 64, elements: !9) +!9 = !{!10, !12} +!10 = !DIDerivedType(tag: DW_TAG_member, name: "a", scope: !8, file: !1, line: 1, baseType: !11, size: 32) +!11 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +!12 = !DIDerivedType(tag: DW_TAG_member, name: "b", scope: !8, file: !1, line: 1, baseType: !11, size: 32, offset: 32) +!13 = !{!14} +!14 = !DISubrange(count: 4) +!15 = !DICompositeType(tag: DW_TAG_array_type, baseType: !11, size: 3200, elements: !16) +!16 = !{!17} +!17 = !DISubrange(count: 100) +!18 = !{i32 2, !"Dwarf Version", i32 4} +!19 = !{i32 2, !"Debug Info Version", i32 3} +!20 = !{i32 1, !"wchar_size", i32 4} +!21 = !{!"clang version 10.0.0 (trunk 367256) (llvm/trunk 367266)"} +!22 = distinct !DISubprogram(name: "test", scope: !1, file: !1, line: 8, type: !23, scopeLine: 8, flags: DIFlagPrototyped, isDefinition: true, isOptimized: true, unit: !0, retainedNodes: !31) +!23 = !DISubroutineType(types: !24) +!24 = !{!11, !25} +!25 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !26, size: 64) +!26 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "v3", file: !1, line: 4, size: 3232, elements: !27) +!27 = !{!28, !30} +!28 = !DIDerivedType(tag: DW_TAG_member, name: "c", scope: !26, file: !1, line: 4, baseType: !29, size: 8) +!29 = !DIBasicType(name: "char", size: 8, encoding: DW_ATE_signed_char) +!30 = !DIDerivedType(tag: DW_TAG_member, name: "d", scope: !26, file: !1, line: 4, baseType: !15, size: 3200, offset: 32) +!31 = !{!32} +!32 = !DILocalVariable(name: "arg", arg: 1, scope: !22, file: !1, line: 8, type: !25) +!33 = !DILocation(line: 0, scope: !22) +!34 = !DILocation(line: 9, column: 20, scope: !22) +!35 = !DILocation(line: 9, column: 10, scope: !22) +!36 = !DILocation(line: 9, column: 3, scope: !22) diff --git a/llvm/test/CodeGen/SBF/CORE/offset-reloc-cast-array-2.ll b/llvm/test/CodeGen/SBF/CORE/offset-reloc-cast-array-2.ll new file mode 100644 index 0000000000000..e2a407f22c4d5 --- /dev/null +++ b/llvm/test/CodeGen/SBF/CORE/offset-reloc-cast-array-2.ll @@ -0,0 +1,136 @@ +; RUN: opt -O2 %s | llvm-dis > %t1 +; RUN: llc -sbf-enable-btf-emission -filetype=asm -o - %t1 | FileCheck -check-prefixes=CHECK %s +; RUN: llc -sbf-enable-btf-emission -mattr=+alu32 -filetype=asm -o - %t1 | FileCheck -check-prefixes=CHECK %s +; Source code: +; struct v1 {int a; int b;}; +; typedef struct v1 __v1; +; typedef __v1 arr[4][4]; +; struct v3 { char c; int d[100]; }; +; #define _(x) (__builtin_preserve_access_index(x)) +; #define cast_to_arr(x) ((arr *)(x)) +; int get_value(const int *arg); +; int test(struct v3 *arg) { +; return get_value(_(&cast_to_arr(&arg->d[0])[0][2][3].b)); +; } +; Compilation flag: +; clang -target bpf -O2 -g -S -emit-llvm -Xclang -disable-llvm-passes test.c + +target triple = "sbf" + +%struct.v3 = type { i8, [100 x i32] } +%struct.v1 = type { i32, i32 } + +; Function Attrs: nounwind +define dso_local i32 @test(%struct.v3* %arg) local_unnamed_addr #0 !dbg !24 { +entry: + call void @llvm.dbg.value(metadata %struct.v3* %arg, metadata !34, metadata !DIExpression()), !dbg !35 + %0 = tail call [100 x i32]* @llvm.preserve.struct.access.index.p0a100i32.p0s_struct.v3s(%struct.v3* elementtype(%struct.v3) %arg, i32 1, i32 1), !dbg !36, !llvm.preserve.access.index !28 + %1 = tail call i32* @llvm.preserve.array.access.index.p0i32.p0a100i32([100 x i32]* elementtype([100 x i32]) %0, i32 1, i32 0), !dbg !36, !llvm.preserve.access.index !15 + %2 = bitcast i32* %1 to [4 x [4 x %struct.v1]]*, !dbg !36 + %3 = tail call [4 x [4 x %struct.v1]]* @llvm.preserve.array.access.index.p0a4a4s_struct.v1s.p0a4a4s_struct.v1s([4 x [4 x %struct.v1]]* elementtype([4 x [4 x %struct.v1]]) %2, i32 0, i32 0), !dbg !36, !llvm.preserve.access.index !4 + %4 = tail call [4 x %struct.v1]* @llvm.preserve.array.access.index.p0a4s_struct.v1s.p0a4a4s_struct.v1s([4 x [4 x %struct.v1]]* elementtype([4 x [4 x %struct.v1]]) %3, i32 1, i32 2), !dbg !36, !llvm.preserve.access.index !5 + %5 = tail call %struct.v1* @llvm.preserve.array.access.index.p0s_struct.v1s.p0a4s_struct.v1s([4 x %struct.v1]* elementtype([4 x %struct.v1]) %4, i32 1, i32 3), !dbg !36, !llvm.preserve.access.index !18 + %6 = tail call i32* @llvm.preserve.struct.access.index.p0i32.p0s_struct.v1s(%struct.v1* elementtype(%struct.v1) %5, i32 1, i32 1), !dbg !36, !llvm.preserve.access.index !8 + %call = tail call i32 @get_value(i32* %6) #4, !dbg !37 + ret i32 %call, !dbg !38 +} + +; CHECK: mov64 r2, 4 +; CHECK: add64 r1, r2 +; CHECK: mov64 r2, 92 +; CHECK: add64 r1, r2 +; CHECK: call get_value + +; CHECK: .long 1 # BTF_KIND_STRUCT(id = [[TID1:[0-9]+]]) +; CHECK: .long 100 # BTF_KIND_STRUCT(id = [[TID2:[0-9]+]]) + +; CHECK: .ascii "v3" # string offset=1 +; CHECK: .ascii ".text" # string offset=46 +; CHECK: .ascii "0:1:0" # string offset=52 +; CHECK: .ascii "v1" # string offset=100 +; CHECK: .ascii "11:1" # string offset=107 + +; CHECK: .long 16 # FieldReloc +; CHECK-NEXT: .long 46 # Field reloc section string offset=46 +; CHECK-NEXT: .long 2 +; CHECK-NEXT: .long .Ltmp{{[0-9]+}} +; CHECK-NEXT: .long [[TID1]] +; CHECK-NEXT: .long 52 +; CHECK-NEXT: .long 0 +; CHECK-NEXT: .long .Ltmp{{[0-9]+}} +; CHECK-NEXT: .long [[TID2]] +; CHECK-NEXT: .long 107 +; CHECK-NEXT: .long 0 + +declare dso_local i32 @get_value(i32*) local_unnamed_addr #1 + +; Function Attrs: nounwind readnone +declare [100 x i32]* @llvm.preserve.struct.access.index.p0a100i32.p0s_struct.v3s(%struct.v3*, i32, i32) #2 + +; Function Attrs: nounwind readnone +declare i32* @llvm.preserve.array.access.index.p0i32.p0a100i32([100 x i32]*, i32, i32) #2 + +; Function Attrs: nounwind readnone +declare [4 x [4 x %struct.v1]]* @llvm.preserve.array.access.index.p0a4a4s_struct.v1s.p0a4a4s_struct.v1s([4 x [4 x %struct.v1]]*, i32, i32) #2 + +; Function Attrs: nounwind readnone +declare [4 x %struct.v1]* @llvm.preserve.array.access.index.p0a4s_struct.v1s.p0a4a4s_struct.v1s([4 x [4 x %struct.v1]]*, i32, i32) #2 + +; Function Attrs: nounwind readnone +declare %struct.v1* @llvm.preserve.array.access.index.p0s_struct.v1s.p0a4s_struct.v1s([4 x %struct.v1]*, i32, i32) #2 + +; Function Attrs: nounwind readnone +declare i32* @llvm.preserve.struct.access.index.p0i32.p0s_struct.v1s(%struct.v1*, i32, i32) #2 + +; Function Attrs: nounwind readnone speculatable willreturn +declare void @llvm.dbg.value(metadata, metadata, metadata) #3 + +attributes #0 = { nounwind "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" } +attributes #1 = { "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" } +attributes #2 = { nounwind readnone } +attributes #3 = { nounwind readnone speculatable willreturn } +attributes #4 = { nounwind } + +!llvm.dbg.cu = !{!0} +!llvm.module.flags = !{!20, !21, !22} +!llvm.ident = !{!23} + +!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 10.0.0 (trunk 367256) (llvm/trunk 367266)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, retainedTypes: !3, nameTableKind: None) +!1 = !DIFile(filename: "test.c", directory: "/tmp/home/yhs/work/tests/llvm/cast") +!2 = !{} +!3 = !{!4, !15, !5, !18} +!4 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !5, size: 64) +!5 = !DIDerivedType(tag: DW_TAG_typedef, name: "arr", file: !1, line: 3, baseType: !6) +!6 = !DICompositeType(tag: DW_TAG_array_type, baseType: !7, size: 1024, elements: !13) +!7 = !DIDerivedType(tag: DW_TAG_typedef, name: "__v1", file: !1, line: 2, baseType: !8) +!8 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "v1", file: !1, line: 1, size: 64, elements: !9) +!9 = !{!10, !12} +!10 = !DIDerivedType(tag: DW_TAG_member, name: "a", scope: !8, file: !1, line: 1, baseType: !11, size: 32) +!11 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +!12 = !DIDerivedType(tag: DW_TAG_member, name: "b", scope: !8, file: !1, line: 1, baseType: !11, size: 32, offset: 32) +!13 = !{!14, !14} +!14 = !DISubrange(count: 4) +!15 = !DICompositeType(tag: DW_TAG_array_type, baseType: !11, size: 3200, elements: !16) +!16 = !{!17} +!17 = !DISubrange(count: 100) +!18 = !DICompositeType(tag: DW_TAG_array_type, baseType: !7, size: 256, elements: !19) +!19 = !{!14} +!20 = !{i32 2, !"Dwarf Version", i32 4} +!21 = !{i32 2, !"Debug Info Version", i32 3} +!22 = !{i32 1, !"wchar_size", i32 4} +!23 = !{!"clang version 10.0.0 (trunk 367256) (llvm/trunk 367266)"} +!24 = distinct !DISubprogram(name: "test", scope: !1, file: !1, line: 8, type: !25, scopeLine: 8, flags: DIFlagPrototyped, isDefinition: true, isOptimized: true, unit: !0, retainedNodes: !33) +!25 = !DISubroutineType(types: !26) +!26 = !{!11, !27} +!27 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !28, size: 64) +!28 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "v3", file: !1, line: 4, size: 3232, elements: !29) +!29 = !{!30, !32} +!30 = !DIDerivedType(tag: DW_TAG_member, name: "c", scope: !28, file: !1, line: 4, baseType: !31, size: 8) +!31 = !DIBasicType(name: "char", size: 8, encoding: DW_ATE_signed_char) +!32 = !DIDerivedType(tag: DW_TAG_member, name: "d", scope: !28, file: !1, line: 4, baseType: !15, size: 3200, offset: 32) +!33 = !{!34} +!34 = !DILocalVariable(name: "arg", arg: 1, scope: !24, file: !1, line: 8, type: !27) +!35 = !DILocation(line: 0, scope: !24) +!36 = !DILocation(line: 9, column: 20, scope: !24) +!37 = !DILocation(line: 9, column: 10, scope: !24) +!38 = !DILocation(line: 9, column: 3, scope: !24) diff --git a/llvm/test/CodeGen/SBF/CORE/offset-reloc-cast-struct-1.ll b/llvm/test/CodeGen/SBF/CORE/offset-reloc-cast-struct-1.ll new file mode 100644 index 0000000000000..6f8dbd215dfd2 --- /dev/null +++ b/llvm/test/CodeGen/SBF/CORE/offset-reloc-cast-struct-1.ll @@ -0,0 +1,117 @@ +; RUN: opt -O2 %s | llvm-dis > %t1 +; RUN: llc -sbf-enable-btf-emission -filetype=asm -o - %t1 | FileCheck -check-prefixes=CHECK %s +; RUN: llc -sbf-enable-btf-emission -mattr=+alu32 -filetype=asm -o - %t1 | FileCheck -check-prefixes=CHECK %s +; Source code: +; struct v1 { int a; int b; }; +; struct v2 { int c; int d; }; +; struct v3 { char c; struct v2 d; }; +; #define _(x) (__builtin_preserve_access_index(x)) +; #define cast_to_v1(x) ((struct v1 *)(x)) +; int get_value(const int *arg); +; int test(struct v3 *arg) { +; return get_value(_(&cast_to_v1(&arg->d)->b)); +; } +; Compilation flag: +; clang -target bpf -O2 -g -S -emit-llvm -Xclang -disable-llvm-passes test.c + +target triple = "sbf" + +%struct.v3 = type { i8, %struct.v2 } +%struct.v2 = type { i32, i32 } +%struct.v1 = type { i32, i32 } + +; Function Attrs: nounwind +define dso_local i32 @test(%struct.v3* %arg) local_unnamed_addr #0 !dbg !14 { +entry: + call void @llvm.dbg.value(metadata %struct.v3* %arg, metadata !28, metadata !DIExpression()), !dbg !29 + %0 = tail call %struct.v2* @llvm.preserve.struct.access.index.p0s_struct.v2s.p0s_struct.v3s(%struct.v3* elementtype(%struct.v3) %arg, i32 1, i32 1), !dbg !30, !llvm.preserve.access.index !18 + %1 = bitcast %struct.v2* %0 to %struct.v1*, !dbg !30 + %2 = tail call i32* @llvm.preserve.struct.access.index.p0i32.p0s_struct.v1s(%struct.v1* elementtype(%struct.v1) %1, i32 1, i32 1), !dbg !30, !llvm.preserve.access.index !5 + %call = tail call i32 @get_value(i32* %2) #4, !dbg !31 + ret i32 %call, !dbg !32 +} + +; CHECK: mov64 r2, 4 +; CHECK: add64 r1, r2 +; CHECK: mov64 r2, 4 +; CHECK: add64 r1, r2 +; CHECK: call get_value + +; CHECK: .long 1 # BTF_KIND_STRUCT(id = [[V3_TID:[0-9]+]]) +; CHECK: .long 81 # BTF_KIND_STRUCT(id = [[V1_TID:[0-9]+]]) + +; CHECK: .ascii "v3" # string offset=1 +; CHECK-NEXT: .byte 0 +; CHECK: .ascii ".text" # string offset=[[SEC_STR:[0-9]+]] +; CHECK-NEXT: .byte 0 +; CHECK: .ascii "0:1" # string offset=[[ACCESS_STR:[0-9]+]] +; CHECK-NEXT: .byte 0 +; CHECK: .ascii "v1" # string offset=81 +; CHECK-NEXT: .byte 0 + +; CHECK: .long 16 # FieldReloc +; CHECK-NEXT: .long [[SEC_STR]] # Field reloc section string offset=[[SEC_STR]] +; CHECK-NEXT: .long 2 +; CHECK-NEXT: .long .Ltmp{{[0-9]+}} +; CHECK-NEXT: .long [[V3_TID]] +; CHECK-NEXT: .long [[ACCESS_STR]] +; CHECK-NEXT: .long 0 +; CHECK-NEXT: .long .Ltmp{{[0-9]+}} +; CHECK-NEXT: .long [[V1_TID]] +; CHECK-NEXT: .long [[ACCESS_STR]] +; CHECK-NEXT: .long 0 + +declare dso_local i32 @get_value(i32*) local_unnamed_addr #1 + +; Function Attrs: nounwind readnone +declare %struct.v2* @llvm.preserve.struct.access.index.p0s_struct.v2s.p0s_struct.v3s(%struct.v3*, i32, i32) #2 + +; Function Attrs: nounwind readnone +declare i32* @llvm.preserve.struct.access.index.p0i32.p0s_struct.v1s(%struct.v1*, i32, i32) #2 + +; Function Attrs: nounwind readnone speculatable willreturn +declare void @llvm.dbg.value(metadata, metadata, metadata) #3 + +attributes #0 = { nounwind "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" } +attributes #1 = { "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" } +attributes #2 = { nounwind readnone } +attributes #3 = { nounwind readnone speculatable willreturn } +attributes #4 = { nounwind } + +!llvm.dbg.cu = !{!0} +!llvm.module.flags = !{!10, !11, !12} +!llvm.ident = !{!13} + +!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 10.0.0 (trunk 367256) (llvm/trunk 367266)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, retainedTypes: !3, nameTableKind: None) +!1 = !DIFile(filename: "test.c", directory: "/tmp/home/yhs/work/tests/llvm/cast") +!2 = !{} +!3 = !{!4} +!4 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !5, size: 64) +!5 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "v1", file: !1, line: 1, size: 64, elements: !6) +!6 = !{!7, !9} +!7 = !DIDerivedType(tag: DW_TAG_member, name: "a", scope: !5, file: !1, line: 1, baseType: !8, size: 32) +!8 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +!9 = !DIDerivedType(tag: DW_TAG_member, name: "b", scope: !5, file: !1, line: 1, baseType: !8, size: 32, offset: 32) +!10 = !{i32 2, !"Dwarf Version", i32 4} +!11 = !{i32 2, !"Debug Info Version", i32 3} +!12 = !{i32 1, !"wchar_size", i32 4} +!13 = !{!"clang version 10.0.0 (trunk 367256) (llvm/trunk 367266)"} +!14 = distinct !DISubprogram(name: "test", scope: !1, file: !1, line: 7, type: !15, scopeLine: 7, flags: DIFlagPrototyped, isDefinition: true, isOptimized: true, unit: !0, retainedNodes: !27) +!15 = !DISubroutineType(types: !16) +!16 = !{!8, !17} +!17 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !18, size: 64) +!18 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "v3", file: !1, line: 3, size: 96, elements: !19) +!19 = !{!20, !22} +!20 = !DIDerivedType(tag: DW_TAG_member, name: "c", scope: !18, file: !1, line: 3, baseType: !21, size: 8) +!21 = !DIBasicType(name: "char", size: 8, encoding: DW_ATE_signed_char) +!22 = !DIDerivedType(tag: DW_TAG_member, name: "d", scope: !18, file: !1, line: 3, baseType: !23, size: 64, offset: 32) +!23 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "v2", file: !1, line: 2, size: 64, elements: !24) +!24 = !{!25, !26} +!25 = !DIDerivedType(tag: DW_TAG_member, name: "c", scope: !23, file: !1, line: 2, baseType: !8, size: 32) +!26 = !DIDerivedType(tag: DW_TAG_member, name: "d", scope: !23, file: !1, line: 2, baseType: !8, size: 32, offset: 32) +!27 = !{!28} +!28 = !DILocalVariable(name: "arg", arg: 1, scope: !14, file: !1, line: 7, type: !17) +!29 = !DILocation(line: 0, scope: !14) +!30 = !DILocation(line: 8, column: 20, scope: !14) +!31 = !DILocation(line: 8, column: 10, scope: !14) +!32 = !DILocation(line: 8, column: 3, scope: !14) diff --git a/llvm/test/CodeGen/SBF/CORE/offset-reloc-cast-struct-2.ll b/llvm/test/CodeGen/SBF/CORE/offset-reloc-cast-struct-2.ll new file mode 100644 index 0000000000000..68d7a65eb0568 --- /dev/null +++ b/llvm/test/CodeGen/SBF/CORE/offset-reloc-cast-struct-2.ll @@ -0,0 +1,122 @@ +; RUN: opt -O2 %s | llvm-dis > %t1 +; RUN: llc -sbf-enable-btf-emission -filetype=asm -o - %t1 | FileCheck -check-prefixes=CHECK %s +; RUN: llc -sbf-enable-btf-emission -mattr=+alu32 -filetype=asm -o - %t1 | FileCheck -check-prefixes=CHECK %s +; Source code: +; struct v1 { int a; int b; }; +; typedef struct v1 __v1; +; struct v2 { int c; int d; }; +; typedef struct v2 __v2; +; struct v3 { char c; volatile const __v2 d; }; +; typedef struct v3 __v3; +; #define _(x) (__builtin_preserve_access_index(x)) +; #define cast_to_v1(x) ((__v1 *)(x)) +; int get_value(const int *arg); +; int test(__v3 *arg) { +; return get_value(_(&cast_to_v1(&arg->d)->b)); +; } +; Compilation flag: +; clang -target bpf -O2 -g -S -emit-llvm -Xclang -disable-llvm-passes test.c + +target triple = "sbf" + +%struct.v3 = type { i8, %struct.v2 } +%struct.v2 = type { i32, i32 } +%struct.v1 = type { i32, i32 } + +; Function Attrs: nounwind +define dso_local i32 @test(%struct.v3* %arg) local_unnamed_addr #0 !dbg !15 { +entry: + call void @llvm.dbg.value(metadata %struct.v3* %arg, metadata !33, metadata !DIExpression()), !dbg !34 + %0 = tail call %struct.v2* @llvm.preserve.struct.access.index.p0s_struct.v2s.p0s_struct.v3s(%struct.v3* elementtype(%struct.v3) %arg, i32 1, i32 1), !dbg !35, !llvm.preserve.access.index !20 + %1 = bitcast %struct.v2* %0 to %struct.v1*, !dbg !35 + %2 = tail call i32* @llvm.preserve.struct.access.index.p0i32.p0s_struct.v1s(%struct.v1* elementtype(%struct.v1) %1, i32 1, i32 1), !dbg !35, !llvm.preserve.access.index !6 + %call = tail call i32 @get_value(i32* %2) #4, !dbg !36 + ret i32 %call, !dbg !37 +} + +; CHECK: mov64 r2, 4 +; CHECK: add64 r1, r2 +; CHECK: mov64 r2, 4 +; CHECK: add64 r1, r2 +; CHECK: call get_value + +; CHECK: .long 6 # BTF_KIND_STRUCT(id = [[TID1:[0-9]+]]) +; CHECK: .long 91 # BTF_KIND_STRUCT(id = [[TID2:[0-9]+]]) + +; CHECK: .ascii "v3" # string offset=6 +; CHECK: .ascii ".text" # string offset=39 +; CHECK: .ascii "0:1" # string offset=45 +; CHECK: .ascii "v1" # string offset=91 + + +; CHECK: .long 16 # FieldReloc +; CHECK-NEXT: .long 39 # Field reloc section string offset=39 +; CHECK-NEXT: .long 2 +; CHECK-NEXT: .long .Ltmp{{[0-9]+}} +; CHECK-NEXT: .long [[TID1]] +; CHECK-NEXT: .long 45 +; CHECK-NEXT: .long 0 +; CHECK-NEXT: .long .Ltmp{{[0-9]+}} +; CHECK-NEXT: .long [[TID2]] +; CHECK-NEXT: .long 45 +; CHECK-NEXT: .long 0 + +declare dso_local i32 @get_value(i32*) local_unnamed_addr #1 + +; Function Attrs: nounwind readnone +declare %struct.v2* @llvm.preserve.struct.access.index.p0s_struct.v2s.p0s_struct.v3s(%struct.v3*, i32, i32) #2 + +; Function Attrs: nounwind readnone +declare i32* @llvm.preserve.struct.access.index.p0i32.p0s_struct.v1s(%struct.v1*, i32, i32) #2 + +; Function Attrs: nounwind readnone speculatable willreturn +declare void @llvm.dbg.value(metadata, metadata, metadata) #3 + +attributes #0 = { nounwind "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" } +attributes #1 = { "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" } +attributes #2 = { nounwind readnone } +attributes #3 = { nounwind readnone speculatable willreturn } +attributes #4 = { nounwind } + +!llvm.dbg.cu = !{!0} +!llvm.module.flags = !{!11, !12, !13} +!llvm.ident = !{!14} + +!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 10.0.0 (trunk 367256) (llvm/trunk 367266)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, retainedTypes: !3, nameTableKind: None) +!1 = !DIFile(filename: "test.c", directory: "/tmp/home/yhs/work/tests/llvm/cast") +!2 = !{} +!3 = !{!4} +!4 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !5, size: 64) +!5 = !DIDerivedType(tag: DW_TAG_typedef, name: "__v1", file: !1, line: 2, baseType: !6) +!6 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "v1", file: !1, line: 1, size: 64, elements: !7) +!7 = !{!8, !10} +!8 = !DIDerivedType(tag: DW_TAG_member, name: "a", scope: !6, file: !1, line: 1, baseType: !9, size: 32) +!9 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +!10 = !DIDerivedType(tag: DW_TAG_member, name: "b", scope: !6, file: !1, line: 1, baseType: !9, size: 32, offset: 32) +!11 = !{i32 2, !"Dwarf Version", i32 4} +!12 = !{i32 2, !"Debug Info Version", i32 3} +!13 = !{i32 1, !"wchar_size", i32 4} +!14 = !{!"clang version 10.0.0 (trunk 367256) (llvm/trunk 367266)"} +!15 = distinct !DISubprogram(name: "test", scope: !1, file: !1, line: 10, type: !16, scopeLine: 10, flags: DIFlagPrototyped, isDefinition: true, isOptimized: true, unit: !0, retainedNodes: !32) +!16 = !DISubroutineType(types: !17) +!17 = !{!9, !18} +!18 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !19, size: 64) +!19 = !DIDerivedType(tag: DW_TAG_typedef, name: "__v3", file: !1, line: 6, baseType: !20) +!20 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "v3", file: !1, line: 5, size: 96, elements: !21) +!21 = !{!22, !24} +!22 = !DIDerivedType(tag: DW_TAG_member, name: "c", scope: !20, file: !1, line: 5, baseType: !23, size: 8) +!23 = !DIBasicType(name: "char", size: 8, encoding: DW_ATE_signed_char) +!24 = !DIDerivedType(tag: DW_TAG_member, name: "d", scope: !20, file: !1, line: 5, baseType: !25, size: 64, offset: 32) +!25 = !DIDerivedType(tag: DW_TAG_const_type, baseType: !26) +!26 = !DIDerivedType(tag: DW_TAG_volatile_type, baseType: !27) +!27 = !DIDerivedType(tag: DW_TAG_typedef, name: "__v2", file: !1, line: 4, baseType: !28) +!28 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "v2", file: !1, line: 3, size: 64, elements: !29) +!29 = !{!30, !31} +!30 = !DIDerivedType(tag: DW_TAG_member, name: "c", scope: !28, file: !1, line: 3, baseType: !9, size: 32) +!31 = !DIDerivedType(tag: DW_TAG_member, name: "d", scope: !28, file: !1, line: 3, baseType: !9, size: 32, offset: 32) +!32 = !{!33} +!33 = !DILocalVariable(name: "arg", arg: 1, scope: !15, file: !1, line: 10, type: !18) +!34 = !DILocation(line: 0, scope: !15) +!35 = !DILocation(line: 11, column: 20, scope: !15) +!36 = !DILocation(line: 11, column: 10, scope: !15) +!37 = !DILocation(line: 11, column: 3, scope: !15) diff --git a/llvm/test/CodeGen/SBF/CORE/offset-reloc-cast-struct-3.ll b/llvm/test/CodeGen/SBF/CORE/offset-reloc-cast-struct-3.ll new file mode 100644 index 0000000000000..907700d352b8f --- /dev/null +++ b/llvm/test/CodeGen/SBF/CORE/offset-reloc-cast-struct-3.ll @@ -0,0 +1,121 @@ +; RUN: opt -O2 %s | llvm-dis > %t1 +; RUN: llc -sbf-enable-btf-emission -filetype=asm -o - %t1 | FileCheck -check-prefixes=CHECK %s +; RUN: llc -sbf-enable-btf-emission -mattr=+alu32 -filetype=asm -o - %t1 | FileCheck -check-prefixes=CHECK %s +; Source code: +; struct v1 { int a; int b; }; +; typedef struct v1 __v1; +; typedef int __int; +; struct v3 { char c; __int d[40]; }; +; typedef struct v3 __v3; +; #define _(x) (__builtin_preserve_access_index(x)) +; #define cast_to_v1(x) ((__v1 *)(x)) +; int get_value(const int *arg); +; int test(__v3 *arg) { +; return get_value(_(&cast_to_v1(&arg->d[4])->b)); +; } +; Compilation flag: +; clang -target bpf -O2 -g -S -emit-llvm -Xclang -disable-llvm-passes test.c + +target triple = "sbf" + +%struct.v3 = type { i8, [40 x i32] } +%struct.v1 = type { i32, i32 } + +; Function Attrs: nounwind +define dso_local i32 @test(%struct.v3* %arg) local_unnamed_addr #0 !dbg !19 { +entry: + call void @llvm.dbg.value(metadata %struct.v3* %arg, metadata !30, metadata !DIExpression()), !dbg !31 + %0 = tail call [40 x i32]* @llvm.preserve.struct.access.index.p0a40i32.p0s_struct.v3s(%struct.v3* elementtype(%struct.v3) %arg, i32 1, i32 1), !dbg !32, !llvm.preserve.access.index !24 + %1 = tail call i32* @llvm.preserve.array.access.index.p0i32.p0a40i32([40 x i32]* elementtype([40 x i32]) %0, i32 1, i32 4), !dbg !32, !llvm.preserve.access.index !11 + %2 = bitcast i32* %1 to %struct.v1*, !dbg !32 + %3 = tail call i32* @llvm.preserve.struct.access.index.p0i32.p0s_struct.v1s(%struct.v1* elementtype(%struct.v1) %2, i32 1, i32 1), !dbg !32, !llvm.preserve.access.index !6 + %call = tail call i32 @get_value(i32* %3) #4, !dbg !33 + ret i32 %call, !dbg !34 +} + +; CHECK: mov64 r2, 20 +; CHECK: add64 r1, r2 +; CHECK: mov64 r2, 4 +; CHECK: add64 r1, r2 +; CHECK: call get_value + +; CHECK: .long 6 # BTF_KIND_STRUCT(id = [[TID1:[0-9]+]]) +; CHECK: .long 111 # BTF_KIND_STRUCT(id = [[TID2:[0-9]+]]) + +; CHECK: .ascii "v3" # string offset=6 +; CHECK: .ascii ".text" # string offset=57 +; CHECK: .ascii "0:1:4" # string offset=63 +; CHECK: .ascii "v1" # string offset=111 +; CHECK: .ascii "0:1" # string offset=118 + +; CHECK: .long 16 # FieldReloc +; CHECK-NEXT: .long 57 # Field reloc section string offset=57 +; CHECK-NEXT: .long 2 +; CHECK-NEXT: .long .Ltmp{{[0-9]+}} +; CHECK-NEXT: .long [[TID1]] +; CHECK-NEXT: .long 63 +; CHECK-NEXT: .long 0 +; CHECK-NEXT: .long .Ltmp{{[0-9]+}} +; CHECK-NEXT: .long [[TID2]] +; CHECK-NEXT: .long 118 +; CHECK-NEXT: .long 0 + +declare dso_local i32 @get_value(i32*) local_unnamed_addr #1 + +; Function Attrs: nounwind readnone +declare [40 x i32]* @llvm.preserve.struct.access.index.p0a40i32.p0s_struct.v3s(%struct.v3*, i32, i32) #2 + +; Function Attrs: nounwind readnone +declare i32* @llvm.preserve.array.access.index.p0i32.p0a40i32([40 x i32]*, i32, i32) #2 + +; Function Attrs: nounwind readnone +declare i32* @llvm.preserve.struct.access.index.p0i32.p0s_struct.v1s(%struct.v1*, i32, i32) #2 + +; Function Attrs: nounwind readnone speculatable willreturn +declare void @llvm.dbg.value(metadata, metadata, metadata) #3 + +attributes #0 = { nounwind "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" } +attributes #1 = { "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" } +attributes #2 = { nounwind readnone } +attributes #3 = { nounwind readnone speculatable willreturn } +attributes #4 = { nounwind } + +!llvm.dbg.cu = !{!0} +!llvm.module.flags = !{!15, !16, !17} +!llvm.ident = !{!18} + +!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 10.0.0 (trunk 367256) (llvm/trunk 367266)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, retainedTypes: !3, nameTableKind: None) +!1 = !DIFile(filename: "test.c", directory: "/tmp/home/yhs/work/tests/llvm/cast") +!2 = !{} +!3 = !{!4, !11} +!4 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !5, size: 64) +!5 = !DIDerivedType(tag: DW_TAG_typedef, name: "__v1", file: !1, line: 2, baseType: !6) +!6 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "v1", file: !1, line: 1, size: 64, elements: !7) +!7 = !{!8, !10} +!8 = !DIDerivedType(tag: DW_TAG_member, name: "a", scope: !6, file: !1, line: 1, baseType: !9, size: 32) +!9 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +!10 = !DIDerivedType(tag: DW_TAG_member, name: "b", scope: !6, file: !1, line: 1, baseType: !9, size: 32, offset: 32) +!11 = !DICompositeType(tag: DW_TAG_array_type, baseType: !12, size: 1280, elements: !13) +!12 = !DIDerivedType(tag: DW_TAG_typedef, name: "__int", file: !1, line: 3, baseType: !9) +!13 = !{!14} +!14 = !DISubrange(count: 40) +!15 = !{i32 2, !"Dwarf Version", i32 4} +!16 = !{i32 2, !"Debug Info Version", i32 3} +!17 = !{i32 1, !"wchar_size", i32 4} +!18 = !{!"clang version 10.0.0 (trunk 367256) (llvm/trunk 367266)"} +!19 = distinct !DISubprogram(name: "test", scope: !1, file: !1, line: 9, type: !20, scopeLine: 9, flags: DIFlagPrototyped, isDefinition: true, isOptimized: true, unit: !0, retainedNodes: !29) +!20 = !DISubroutineType(types: !21) +!21 = !{!9, !22} +!22 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !23, size: 64) +!23 = !DIDerivedType(tag: DW_TAG_typedef, name: "__v3", file: !1, line: 5, baseType: !24) +!24 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "v3", file: !1, line: 4, size: 1312, elements: !25) +!25 = !{!26, !28} +!26 = !DIDerivedType(tag: DW_TAG_member, name: "c", scope: !24, file: !1, line: 4, baseType: !27, size: 8) +!27 = !DIBasicType(name: "char", size: 8, encoding: DW_ATE_signed_char) +!28 = !DIDerivedType(tag: DW_TAG_member, name: "d", scope: !24, file: !1, line: 4, baseType: !11, size: 1280, offset: 32) +!29 = !{!30} +!30 = !DILocalVariable(name: "arg", arg: 1, scope: !19, file: !1, line: 9, type: !22) +!31 = !DILocation(line: 0, scope: !19) +!32 = !DILocation(line: 10, column: 20, scope: !19) +!33 = !DILocation(line: 10, column: 10, scope: !19) +!34 = !DILocation(line: 10, column: 3, scope: !19) diff --git a/llvm/test/CodeGen/SBF/CORE/offset-reloc-cast-union-1.ll b/llvm/test/CodeGen/SBF/CORE/offset-reloc-cast-union-1.ll new file mode 100644 index 0000000000000..e6f6a8c3b9039 --- /dev/null +++ b/llvm/test/CodeGen/SBF/CORE/offset-reloc-cast-union-1.ll @@ -0,0 +1,122 @@ +; RUN: opt -O2 %s | llvm-dis > %t1 +; RUN: llc -sbf-enable-btf-emission -filetype=asm -o - %t1 | FileCheck -check-prefixes=CHECK %s +; RUN: llc -sbf-enable-btf-emission -mattr=+alu32 -filetype=asm -o - %t1 | FileCheck -check-prefixes=CHECK %s +; Source code: +; union v1 { int a; int b; }; +; typedef union v1 __v1; +; union v2 { int c; int d; }; +; typedef union v2 __v2; +; union v3 { char c; volatile const __v2 d; }; +; typedef union v3 __v3; +; #define _(x) (__builtin_preserve_access_index(x)) +; #define cast_to_v1(x) ((__v1 *)(x)) +; int get_value(const int *arg); +; int test(__v3 *arg) { +; return get_value(_(&cast_to_v1(&arg->d)->b)); +; } +; Compilation flag: +; clang -target bpf -O2 -g -S -emit-llvm -Xclang -disable-llvm-passes test.c + +target triple = "sbf" + +%union.v3 = type { %union.v2 } +%union.v2 = type { i32 } +%union.v1 = type { i32 } + +; Function Attrs: nounwind +define dso_local i32 @test(%union.v3* %arg) local_unnamed_addr #0 !dbg !15 { +entry: + call void @llvm.dbg.value(metadata %union.v3* %arg, metadata !33, metadata !DIExpression()), !dbg !34 + %0 = tail call %union.v3* @llvm.preserve.union.access.index.p0s_union.v3s.p0s_union.v3s(%union.v3* %arg, i32 1), !dbg !35, !llvm.preserve.access.index !20 + %1 = bitcast %union.v3* %0 to %union.v1*, !dbg !35 + %2 = tail call %union.v1* @llvm.preserve.union.access.index.p0s_union.v1s.p0s_union.v1s(%union.v1* %1, i32 1), !dbg !35, !llvm.preserve.access.index !6 + %b = getelementptr inbounds %union.v1, %union.v1* %2, i64 0, i32 0, !dbg !35 + %call = tail call i32 @get_value(i32* %b) #4, !dbg !36 + ret i32 %call, !dbg !37 +} + +; CHECK: mov64 r2, 0 +; CHECK: add64 r1, r2 +; CHECK: mov64 r2, 0 +; CHECK: add64 r1, r2 +; CHECK: call get_value + +; CHECK: .long 6 # BTF_KIND_UNION(id = [[TID1:[0-9]+]]) +; CHECK: .long 91 # BTF_KIND_UNION(id = [[TID2:[0-9]+]]) + +; CHECK: .ascii "v3" # string offset=6 +; CHECK: .ascii ".text" # string offset=39 +; CHECK: .ascii "0:1" # string offset=45 +; CHECK: .ascii "v1" # string offset=91 + +; CHECK: .long 16 # FieldReloc +; CHECK-NEXT: .long 39 # Field reloc section string offset=39 +; CHECK-NEXT: .long 2 +; CHECK-NEXT: .long .Ltmp{{[0-9]+}} +; CHECK-NEXT: .long [[TID1]] +; CHECK-NEXT: .long 45 +; CHECK-NEXT: .long 0 +; CHECK-NEXT: .long .Ltmp{{[0-9]+}} +; CHECK-NEXT: .long [[TID2]] +; CHECK-NEXT: .long 45 +; CHECK-NEXT: .long 0 + +declare dso_local i32 @get_value(i32*) local_unnamed_addr #1 + +; Function Attrs: nounwind readnone +declare %union.v3* @llvm.preserve.union.access.index.p0s_union.v3s.p0s_union.v3s(%union.v3*, i32) #2 + +; Function Attrs: nounwind readnone +declare %union.v1* @llvm.preserve.union.access.index.p0s_union.v1s.p0s_union.v1s(%union.v1*, i32) #2 + +; Function Attrs: nounwind readnone speculatable willreturn +declare void @llvm.dbg.value(metadata, metadata, metadata) #3 + +attributes #0 = { nounwind "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" } +attributes #1 = { "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" } +attributes #2 = { nounwind readnone } +attributes #3 = { nounwind readnone speculatable willreturn } +attributes #4 = { nounwind } + +!llvm.dbg.cu = !{!0} +!llvm.module.flags = !{!11, !12, !13} +!llvm.ident = !{!14} + +!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 10.0.0 (trunk 367256) (llvm/trunk 367266)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, retainedTypes: !3, nameTableKind: None) +!1 = !DIFile(filename: "test.c", directory: "/tmp/home/yhs/work/tests/llvm/cast") +!2 = !{} +!3 = !{!4} +!4 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !5, size: 64) +!5 = !DIDerivedType(tag: DW_TAG_typedef, name: "__v1", file: !1, line: 2, baseType: !6) +!6 = distinct !DICompositeType(tag: DW_TAG_union_type, name: "v1", file: !1, line: 1, size: 32, elements: !7) +!7 = !{!8, !10} +!8 = !DIDerivedType(tag: DW_TAG_member, name: "a", scope: !6, file: !1, line: 1, baseType: !9, size: 32) +!9 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +!10 = !DIDerivedType(tag: DW_TAG_member, name: "b", scope: !6, file: !1, line: 1, baseType: !9, size: 32) +!11 = !{i32 2, !"Dwarf Version", i32 4} +!12 = !{i32 2, !"Debug Info Version", i32 3} +!13 = !{i32 1, !"wchar_size", i32 4} +!14 = !{!"clang version 10.0.0 (trunk 367256) (llvm/trunk 367266)"} +!15 = distinct !DISubprogram(name: "test", scope: !1, file: !1, line: 10, type: !16, scopeLine: 10, flags: DIFlagPrototyped, isDefinition: true, isOptimized: true, unit: !0, retainedNodes: !32) +!16 = !DISubroutineType(types: !17) +!17 = !{!9, !18} +!18 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !19, size: 64) +!19 = !DIDerivedType(tag: DW_TAG_typedef, name: "__v3", file: !1, line: 6, baseType: !20) +!20 = distinct !DICompositeType(tag: DW_TAG_union_type, name: "v3", file: !1, line: 5, size: 32, elements: !21) +!21 = !{!22, !24} +!22 = !DIDerivedType(tag: DW_TAG_member, name: "c", scope: !20, file: !1, line: 5, baseType: !23, size: 8) +!23 = !DIBasicType(name: "char", size: 8, encoding: DW_ATE_signed_char) +!24 = !DIDerivedType(tag: DW_TAG_member, name: "d", scope: !20, file: !1, line: 5, baseType: !25, size: 32) +!25 = !DIDerivedType(tag: DW_TAG_const_type, baseType: !26) +!26 = !DIDerivedType(tag: DW_TAG_volatile_type, baseType: !27) +!27 = !DIDerivedType(tag: DW_TAG_typedef, name: "__v2", file: !1, line: 4, baseType: !28) +!28 = distinct !DICompositeType(tag: DW_TAG_union_type, name: "v2", file: !1, line: 3, size: 32, elements: !29) +!29 = !{!30, !31} +!30 = !DIDerivedType(tag: DW_TAG_member, name: "c", scope: !28, file: !1, line: 3, baseType: !9, size: 32) +!31 = !DIDerivedType(tag: DW_TAG_member, name: "d", scope: !28, file: !1, line: 3, baseType: !9, size: 32) +!32 = !{!33} +!33 = !DILocalVariable(name: "arg", arg: 1, scope: !15, file: !1, line: 10, type: !18) +!34 = !DILocation(line: 0, scope: !15) +!35 = !DILocation(line: 11, column: 20, scope: !15) +!36 = !DILocation(line: 11, column: 10, scope: !15) +!37 = !DILocation(line: 11, column: 3, scope: !15) diff --git a/llvm/test/CodeGen/SBF/CORE/offset-reloc-cast-union-2.ll b/llvm/test/CodeGen/SBF/CORE/offset-reloc-cast-union-2.ll new file mode 100644 index 0000000000000..d64dbd60e2497 --- /dev/null +++ b/llvm/test/CodeGen/SBF/CORE/offset-reloc-cast-union-2.ll @@ -0,0 +1,123 @@ +; RUN: opt -O2 %s | llvm-dis > %t1 +; RUN: llc -sbf-enable-btf-emission -filetype=asm -o - %t1 | FileCheck -check-prefixes=CHECK %s +; RUN: llc -sbf-enable-btf-emission -mattr=+alu32 -filetype=asm -o - %t1 | FileCheck -check-prefixes=CHECK %s +; Source code: +; union v1 { int a; int b; }; +; typedef union v1 __v1; +; typedef int __int; +; union v3 { char c; __int d[40]; }; +; typedef union v3 __v3; +; #define _(x) (__builtin_preserve_access_index(x)) +; #define cast_to_v1(x) ((__v1 *)(x)) +; int get_value(const int *arg); +; int test(__v3 *arg) { +; return get_value(_(&cast_to_v1(&arg->d[4])->b)); +; } +; Compilation flag: +; clang -target bpf -O2 -g -S -emit-llvm -Xclang -disable-llvm-passes test.c + +target triple = "sbf" + +%union.v3 = type { [40 x i32] } +%union.v1 = type { i32 } + +; Function Attrs: nounwind +define dso_local i32 @test(%union.v3* %arg) local_unnamed_addr #0 !dbg !19 { +entry: + call void @llvm.dbg.value(metadata %union.v3* %arg, metadata !30, metadata !DIExpression()), !dbg !31 + %0 = tail call %union.v3* @llvm.preserve.union.access.index.p0s_union.v3s.p0s_union.v3s(%union.v3* %arg, i32 1), !dbg !32, !llvm.preserve.access.index !24 + %d = getelementptr inbounds %union.v3, %union.v3* %0, i64 0, i32 0, !dbg !32 + %1 = tail call i32* @llvm.preserve.array.access.index.p0i32.p0a40i32([40 x i32]* elementtype([40 x i32]) %d, i32 1, i32 4), !dbg !32, !llvm.preserve.access.index !11 + %2 = bitcast i32* %1 to %union.v1*, !dbg !32 + %3 = tail call %union.v1* @llvm.preserve.union.access.index.p0s_union.v1s.p0s_union.v1s(%union.v1* %2, i32 1), !dbg !32, !llvm.preserve.access.index !6 + %b = getelementptr inbounds %union.v1, %union.v1* %3, i64 0, i32 0, !dbg !32 + %call = tail call i32 @get_value(i32* %b) #4, !dbg !33 + ret i32 %call, !dbg !34 +} + +; CHECK: mov64 r2, 16 +; CHECK: add64 r1, r2 +; CHECK: mov64 r2, 0 +; CHECK: add64 r1, r2 +; CHECK: call get_value + +; CHECK: .long 6 # BTF_KIND_UNION(id = [[TID1:[0-9]+]]) +; CHECK: .long 111 # BTF_KIND_UNION(id = [[TID2:[0-9]+]]) + +; CHECK: .ascii "v3" # string offset=6 +; CHECK: .ascii ".text" # string offset=57 +; CHECK: .ascii "0:1:4" # string offset=63 +; CHECK: .ascii "v1" # string offset=111 +; CHECK: .ascii "0:1" # string offset=118 + +; CHECK: .long 16 # FieldReloc +; CHECK-NEXT: .long 57 # Field reloc section string offset=57 +; CHECK-NEXT: .long 2 +; CHECK-NEXT: .long .Ltmp{{[0-9]+}} +; CHECK-NEXT: .long [[TID1]] +; CHECK-NEXT: .long 63 +; CHECK-NEXT: .long 0 +; CHECK-NEXT: .long .Ltmp{{[0-9]+}} +; CHECK-NEXT: .long [[TID2]] +; CHECK-NEXT: .long 118 +; CHECK-NEXT: .long 0 + +declare dso_local i32 @get_value(i32*) local_unnamed_addr #1 + +; Function Attrs: nounwind readnone +declare %union.v3* @llvm.preserve.union.access.index.p0s_union.v3s.p0s_union.v3s(%union.v3*, i32) #2 + +; Function Attrs: nounwind readnone +declare i32* @llvm.preserve.array.access.index.p0i32.p0a40i32([40 x i32]*, i32, i32) #2 + +; Function Attrs: nounwind readnone +declare %union.v1* @llvm.preserve.union.access.index.p0s_union.v1s.p0s_union.v1s(%union.v1*, i32) #2 + +; Function Attrs: nounwind readnone speculatable willreturn +declare void @llvm.dbg.value(metadata, metadata, metadata) #3 + +attributes #0 = { nounwind "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" } +attributes #1 = { "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" } +attributes #2 = { nounwind readnone } +attributes #3 = { nounwind readnone speculatable willreturn } +attributes #4 = { nounwind } + +!llvm.dbg.cu = !{!0} +!llvm.module.flags = !{!15, !16, !17} +!llvm.ident = !{!18} + +!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 10.0.0 (trunk 367256) (llvm/trunk 367266)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, retainedTypes: !3, nameTableKind: None) +!1 = !DIFile(filename: "test.c", directory: "/tmp/home/yhs/work/tests/llvm/cast") +!2 = !{} +!3 = !{!4, !11} +!4 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !5, size: 64) +!5 = !DIDerivedType(tag: DW_TAG_typedef, name: "__v1", file: !1, line: 2, baseType: !6) +!6 = distinct !DICompositeType(tag: DW_TAG_union_type, name: "v1", file: !1, line: 1, size: 32, elements: !7) +!7 = !{!8, !10} +!8 = !DIDerivedType(tag: DW_TAG_member, name: "a", scope: !6, file: !1, line: 1, baseType: !9, size: 32) +!9 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +!10 = !DIDerivedType(tag: DW_TAG_member, name: "b", scope: !6, file: !1, line: 1, baseType: !9, size: 32) +!11 = !DICompositeType(tag: DW_TAG_array_type, baseType: !12, size: 1280, elements: !13) +!12 = !DIDerivedType(tag: DW_TAG_typedef, name: "__int", file: !1, line: 3, baseType: !9) +!13 = !{!14} +!14 = !DISubrange(count: 40) +!15 = !{i32 2, !"Dwarf Version", i32 4} +!16 = !{i32 2, !"Debug Info Version", i32 3} +!17 = !{i32 1, !"wchar_size", i32 4} +!18 = !{!"clang version 10.0.0 (trunk 367256) (llvm/trunk 367266)"} +!19 = distinct !DISubprogram(name: "test", scope: !1, file: !1, line: 9, type: !20, scopeLine: 9, flags: DIFlagPrototyped, isDefinition: true, isOptimized: true, unit: !0, retainedNodes: !29) +!20 = !DISubroutineType(types: !21) +!21 = !{!9, !22} +!22 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !23, size: 64) +!23 = !DIDerivedType(tag: DW_TAG_typedef, name: "__v3", file: !1, line: 5, baseType: !24) +!24 = distinct !DICompositeType(tag: DW_TAG_union_type, name: "v3", file: !1, line: 4, size: 1280, elements: !25) +!25 = !{!26, !28} +!26 = !DIDerivedType(tag: DW_TAG_member, name: "c", scope: !24, file: !1, line: 4, baseType: !27, size: 8) +!27 = !DIBasicType(name: "char", size: 8, encoding: DW_ATE_signed_char) +!28 = !DIDerivedType(tag: DW_TAG_member, name: "d", scope: !24, file: !1, line: 4, baseType: !11, size: 1280) +!29 = !{!30} +!30 = !DILocalVariable(name: "arg", arg: 1, scope: !19, file: !1, line: 9, type: !22) +!31 = !DILocation(line: 0, scope: !19) +!32 = !DILocation(line: 10, column: 20, scope: !19) +!33 = !DILocation(line: 10, column: 10, scope: !19) +!34 = !DILocation(line: 10, column: 3, scope: !19) diff --git a/llvm/test/CodeGen/SBF/CORE/offset-reloc-end-load.ll b/llvm/test/CodeGen/SBF/CORE/offset-reloc-end-load.ll new file mode 100644 index 0000000000000..7a85f3101d037 --- /dev/null +++ b/llvm/test/CodeGen/SBF/CORE/offset-reloc-end-load.ll @@ -0,0 +1,86 @@ +; RUN: opt -O2 %s | llvm-dis > %t1 +; RUN: llc -sbf-enable-btf-emission -filetype=asm -o - %t1 | FileCheck -check-prefixes=CHECK,CHECK-ALU64 %s +; RUN: llc -sbf-enable-btf-emission -mattr=+alu32 -filetype=asm -o - %t1 | FileCheck -check-prefixes=CHECK,CHECK-ALU32 %s +; +; Source Code: +; #define _(x) (__builtin_preserve_access_index(x)) +; struct s {int a; int b;}; +; int test(struct s *arg) { return *(const int *)_(&arg->b); } +; Compiler flag to generate IR: +; clang -target bpf -S -O2 -g -emit-llvm -Xclang -disable-llvm-passes test.c + +target triple = "sbf" + +%struct.s = type { i32, i32 } + +; Function Attrs: nounwind readonly +define dso_local i32 @test(%struct.s* readonly %arg) local_unnamed_addr #0 !dbg !11 { +entry: + call void @llvm.dbg.value(metadata %struct.s* %arg, metadata !20, metadata !DIExpression()), !dbg !21 + %0 = tail call i32* @llvm.preserve.struct.access.index.p0i32.p0s_struct.ss(%struct.s* elementtype(%struct.s) %arg, i32 1, i32 1), !dbg !22, !llvm.preserve.access.index !15 + %1 = load i32, i32* %0, align 4, !dbg !23, !tbaa !24 + ret i32 %1, !dbg !28 +} + +; CHECK-LABEL: test +; CHECK-ALU64: ldxw r0, [r1 + 4] +; CHECK-ALU32: ldxw w0, [r1 + 4] +; CHECK: exit +; +; CHECK: .long 1 # BTF_KIND_STRUCT(id = 2) +; +; CHECK: .byte 115 # string offset=1 +; CHECK: .ascii ".text" # string offset=20 +; CHECK: .ascii "0:1" # string offset=26 +; +; CHECK: .long 16 # FieldReloc +; CHECK-NEXT: .long 20 # Field reloc section string offset=20 +; CHECK-NEXT: .long 1 +; CHECK-NEXT: .long .Ltmp{{[0-9]+}} +; CHECK-NEXT: .long 2 +; CHECK-NEXT: .long 26 +; CHECK-NEXT: .long 0 + +; Function Attrs: nounwind readnone +declare i32* @llvm.preserve.struct.access.index.p0i32.p0s_struct.ss(%struct.s*, i32, i32) #1 + +; Function Attrs: nounwind readnone speculatable willreturn +declare void @llvm.dbg.value(metadata, metadata, metadata) #2 + +attributes #0 = { nounwind readonly "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" } +attributes #1 = { nounwind readnone } +attributes #2 = { nounwind readnone speculatable willreturn } + +!llvm.dbg.cu = !{!0} +!llvm.module.flags = !{!7, !8, !9} +!llvm.ident = !{!10} + +!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 10.0.0 (https://github.com/llvm/llvm-project.git 6e353b4df3aa452ed4741a5e5caea02b1a876d8c)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, retainedTypes: !3, nameTableKind: None) +!1 = !DIFile(filename: "test.c", directory: "/tmp/home/yhs/work/tests/core") +!2 = !{} +!3 = !{!4} +!4 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !5, size: 64) +!5 = !DIDerivedType(tag: DW_TAG_const_type, baseType: !6) +!6 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +!7 = !{i32 2, !"Dwarf Version", i32 4} +!8 = !{i32 2, !"Debug Info Version", i32 3} +!9 = !{i32 1, !"wchar_size", i32 4} +!10 = !{!"clang version 10.0.0 (https://github.com/llvm/llvm-project.git 6e353b4df3aa452ed4741a5e5caea02b1a876d8c)"} +!11 = distinct !DISubprogram(name: "test", scope: !1, file: !1, line: 3, type: !12, scopeLine: 3, flags: DIFlagPrototyped, isDefinition: true, isOptimized: true, unit: !0, retainedNodes: !19) +!12 = !DISubroutineType(types: !13) +!13 = !{!6, !14} +!14 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !15, size: 64) +!15 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "s", file: !1, line: 2, size: 64, elements: !16) +!16 = !{!17, !18} +!17 = !DIDerivedType(tag: DW_TAG_member, name: "a", scope: !15, file: !1, line: 2, baseType: !6, size: 32) +!18 = !DIDerivedType(tag: DW_TAG_member, name: "b", scope: !15, file: !1, line: 2, baseType: !6, size: 32, offset: 32) +!19 = !{!20} +!20 = !DILocalVariable(name: "arg", arg: 1, scope: !11, file: !1, line: 3, type: !14) +!21 = !DILocation(line: 0, scope: !11) +!22 = !DILocation(line: 3, column: 48, scope: !11) +!23 = !DILocation(line: 3, column: 34, scope: !11) +!24 = !{!25, !25, i64 0} +!25 = !{!"int", !26, i64 0} +!26 = !{!"omnipotent char", !27, i64 0} +!27 = !{!"Simple C/C++ TBAA"} +!28 = !DILocation(line: 3, column: 27, scope: !11) diff --git a/llvm/test/CodeGen/SBF/CORE/offset-reloc-end-ret.ll b/llvm/test/CodeGen/SBF/CORE/offset-reloc-end-ret.ll new file mode 100644 index 0000000000000..8dffa10c7ebe4 --- /dev/null +++ b/llvm/test/CodeGen/SBF/CORE/offset-reloc-end-ret.ll @@ -0,0 +1,81 @@ +; RUN: opt -O2 %s | llvm-dis > %t1 +; RUN: llc -sbf-enable-btf-emission -filetype=asm -o - %t1 | FileCheck %s +; RUN: llc -sbf-enable-btf-emission -mattr=+alu32 -filetype=asm -o - %t1 | FileCheck %s +; +; Source Code: +; #define _(x) (__builtin_preserve_access_index(x)) +; struct s {int a; int b;}; +; const void *test(struct s *arg) { return _(&arg->b); } +; Compiler flag to generate IR: +; clang -target bpf -S -O2 -g -emit-llvm -Xclang -disable-llvm-passes test.c + +target triple = "sbf" + +%struct.s = type { i32, i32 } + +; Function Attrs: nounwind readnone +define dso_local i8* @test(%struct.s* readnone %arg) local_unnamed_addr #0 !dbg !7 { +entry: + call void @llvm.dbg.value(metadata %struct.s* %arg, metadata !19, metadata !DIExpression()), !dbg !20 + %0 = tail call i32* @llvm.preserve.struct.access.index.p0i32.p0s_struct.ss(%struct.s* elementtype(%struct.s) %arg, i32 1, i32 1), !dbg !21, !llvm.preserve.access.index !13 + %1 = bitcast i32* %0 to i8*, !dbg !21 + ret i8* %1, !dbg !22 +} + +; CHECK-LABEL: test +; CHECK: mov64 r0, r1 +; CHECK: mov64 r1, 4 +; CHECK: add64 r0, r1 +; CHECK: exit +; +; CHECK: .long 1 # BTF_KIND_STRUCT(id = 2) +; +; CHECK: .byte 115 # string offset=1 +; CHECK: .ascii ".text" # string offset=20 +; CHECK: .ascii "0:1" # string offset=63 +; +; CHECK: .long 16 # FieldReloc +; CHECK-NEXT: .long 20 # Field reloc section string offset=20 +; CHECK-NEXT: .long 1 +; CHECK-NEXT: .long .Ltmp{{[0-9]+}} +; CHECK-NEXT: .long 2 +; CHECK-NEXT: .long 63 +; CHECK-NEXT: .long 0 + +; Function Attrs: nounwind readnone +declare i32* @llvm.preserve.struct.access.index.p0i32.p0s_struct.ss(%struct.s*, i32, i32) #1 + +; Function Attrs: nounwind readnone speculatable willreturn +declare void @llvm.dbg.value(metadata, metadata, metadata) #2 + +attributes #0 = { nounwind readnone "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" } +attributes #1 = { nounwind readnone } +attributes #2 = { nounwind readnone speculatable willreturn } + +!llvm.dbg.cu = !{!0} +!llvm.module.flags = !{!3, !4, !5} +!llvm.ident = !{!6} + +!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 10.0.0 (https://github.com/llvm/llvm-project.git 6e353b4df3aa452ed4741a5e5caea02b1a876d8c)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, nameTableKind: None) +!1 = !DIFile(filename: "test.c", directory: "/tmp/home/yhs/work/tests/core") +!2 = !{} +!3 = !{i32 2, !"Dwarf Version", i32 4} +!4 = !{i32 2, !"Debug Info Version", i32 3} +!5 = !{i32 1, !"wchar_size", i32 4} +!6 = !{!"clang version 10.0.0 (https://github.com/llvm/llvm-project.git 6e353b4df3aa452ed4741a5e5caea02b1a876d8c)"} +!7 = distinct !DISubprogram(name: "test", scope: !1, file: !1, line: 3, type: !8, scopeLine: 3, flags: DIFlagPrototyped, isDefinition: true, isOptimized: true, unit: !0, retainedNodes: !18) +!8 = !DISubroutineType(types: !9) +!9 = !{!10, !12} +!10 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !11, size: 64) +!11 = !DIDerivedType(tag: DW_TAG_const_type, baseType: null) +!12 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !13, size: 64) +!13 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "s", file: !1, line: 2, size: 64, elements: !14) +!14 = !{!15, !17} +!15 = !DIDerivedType(tag: DW_TAG_member, name: "a", scope: !13, file: !1, line: 2, baseType: !16, size: 32) +!16 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +!17 = !DIDerivedType(tag: DW_TAG_member, name: "b", scope: !13, file: !1, line: 2, baseType: !16, size: 32, offset: 32) +!18 = !{!19} +!19 = !DILocalVariable(name: "arg", arg: 1, scope: !7, file: !1, line: 3, type: !12) +!20 = !DILocation(line: 0, scope: !7) +!21 = !DILocation(line: 3, column: 42, scope: !7) +!22 = !DILocation(line: 3, column: 35, scope: !7) diff --git a/llvm/test/CodeGen/SBF/CORE/offset-reloc-fieldinfo-1.ll b/llvm/test/CodeGen/SBF/CORE/offset-reloc-fieldinfo-1.ll new file mode 100644 index 0000000000000..57df4ebe5c5c1 --- /dev/null +++ b/llvm/test/CodeGen/SBF/CORE/offset-reloc-fieldinfo-1.ll @@ -0,0 +1,200 @@ +; RUN: opt -O2 %s | llvm-dis > %t1 +; RUN: llc -sbf-enable-btf-emission -filetype=asm -o - %t1 | FileCheck -check-prefixes=CHECK,CHECK64 %s +; RUN: llc -sbf-enable-btf-emission -mattr=+alu32 -filetype=asm -o - %t1 | FileCheck -check-prefixes=CHECK,CHECK32 %s +; Source code: +; struct s { +; int a; +; int b1:9; +; int b2:4; +; }; +; enum { +; FIELD_BYTE_OFFSET = 0, +; FIELD_BYTE_SIZE, +; FIELD_EXISTENCE, +; FIELD_SIGNEDNESS, +; FIELD_LSHIFT_U64, +; FIELD_RSHIFT_U64, +; }; +; void bpf_probe_read(void *, unsigned, const void *); +; int field_read(struct s *arg) { +; unsigned long long ull; +; unsigned offset = __builtin_preserve_field_info(arg->b2, FIELD_BYTE_OFFSET); +; unsigned size = __builtin_preserve_field_info(arg->b2, FIELD_BYTE_SIZE); +; unsigned lshift; +; +; bpf_probe_read(&ull, size, (const void *)arg + offset); +; lshift = __builtin_preserve_field_info(arg->b2, FIELD_LSHIFT_U64); +; #if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ +; lshift = lshift + (size << 3) - 64; +; #endif +; ull <<= lshift; +; if (__builtin_preserve_field_info(arg->b2, FIELD_SIGNEDNESS)) +; return (long long)ull >> __builtin_preserve_field_info(arg->b2, FIELD_RSHIFT_U64); +; return ull >> __builtin_preserve_field_info(arg->b2, FIELD_RSHIFT_U64); +; } +; Compilation flag: +; clang -target bpfel -O2 -g -S -emit-llvm -Xclang -disable-llvm-passes test.c + +target triple = "sbf" + +%struct.s = type { i32, i16 } + +; Function Attrs: nounwind +define dso_local i32 @field_read(%struct.s* %arg) local_unnamed_addr #0 !dbg !20 { +entry: + %ull = alloca i64, align 8 + call void @llvm.dbg.value(metadata %struct.s* %arg, metadata !31, metadata !DIExpression()), !dbg !37 + %0 = bitcast i64* %ull to i8*, !dbg !38 + call void @llvm.lifetime.start.p0i8(i64 8, i8* nonnull %0) #5, !dbg !38 + %1 = tail call i16* @llvm.preserve.struct.access.index.p0i16.p0s_struct.ss(%struct.s* elementtype(%struct.s) %arg, i32 1, i32 2), !dbg !39, !llvm.preserve.access.index !25 + %2 = tail call i32 @llvm.bpf.preserve.field.info.p0i16(i16* %1, i64 0), !dbg !40 + call void @llvm.dbg.value(metadata i32 %2, metadata !34, metadata !DIExpression()), !dbg !37 + %3 = tail call i32 @llvm.bpf.preserve.field.info.p0i16(i16* %1, i64 1), !dbg !41 + call void @llvm.dbg.value(metadata i32 %3, metadata !35, metadata !DIExpression()), !dbg !37 + %4 = bitcast %struct.s* %arg to i8*, !dbg !42 + %idx.ext = zext i32 %2 to i64, !dbg !43 + %add.ptr = getelementptr i8, i8* %4, i64 %idx.ext, !dbg !43 + call void @bpf_probe_read(i8* nonnull %0, i32 %3, i8* %add.ptr) #5, !dbg !44 + %5 = call i32 @llvm.bpf.preserve.field.info.p0i16(i16* %1, i64 4), !dbg !45 + call void @llvm.dbg.value(metadata i32 %5, metadata !36, metadata !DIExpression()), !dbg !37 + %6 = load i64, i64* %ull, align 8, !dbg !46, !tbaa !47 + call void @llvm.dbg.value(metadata i64 %6, metadata !32, metadata !DIExpression()), !dbg !37 + %sh_prom = zext i32 %5 to i64, !dbg !46 + %shl = shl i64 %6, %sh_prom, !dbg !46 + call void @llvm.dbg.value(metadata i64 %shl, metadata !32, metadata !DIExpression()), !dbg !37 + %7 = call i32 @llvm.bpf.preserve.field.info.p0i16(i16* %1, i64 3), !dbg !51 + %tobool = icmp eq i32 %7, 0, !dbg !51 + %8 = call i32 @llvm.bpf.preserve.field.info.p0i16(i16* %1, i64 5), !dbg !37 + %sh_prom1 = zext i32 %8 to i64, !dbg !37 + %shr = ashr i64 %shl, %sh_prom1, !dbg !53 + %shr3 = lshr i64 %shl, %sh_prom1, !dbg !53 + %retval.0.in = select i1 %tobool, i64 %shr3, i64 %shr, !dbg !53 + %retval.0 = trunc i64 %retval.0.in to i32, !dbg !37 + call void @llvm.lifetime.end.p0i8(i64 8, i8* nonnull %0) #5, !dbg !54 + ret i32 %retval.0, !dbg !54 +} + +; CHECK: mov64 r{{[0-9]+}}, 4 +; CHECK: mov64 r{{[0-9]+}}, 4 +; CHECK: lsh64 r{{[0-9]+}}, 51 +; CHECK64: arsh64 r{{[0-9]+}}, 60 +; CHECK64: rsh64 r{{[0-9]+}}, 60 +; CHECK32: rsh64 r{{[0-9]+}}, 60 +; CHECK32: arsh64 r{{[0-9]+}}, 60 +; CHECK: mov64 r{{[0-9]+}}, 1 + +; CHECK: .byte 115 # string offset=1 +; CHECK: .ascii ".text" # string offset=30 +; CHECK: .ascii "0:2" # string offset=73 + +; CHECK: .long 16 # FieldReloc +; CHECK-NEXT: .long 30 # Field reloc section string offset=30 +; CHECK-NEXT: .long 6 +; CHECK-NEXT: .long .Ltmp{{[0-9]+}} +; CHECK-NEXT: .long 2 +; CHECK-NEXT: .long 73 +; CHECK-NEXT: .long 0 +; CHECK-NEXT: .long .Ltmp{{[0-9]+}} +; CHECK-NEXT: .long 2 +; CHECK-NEXT: .long 73 +; CHECK-NEXT: .long 1 +; CHECK-NEXT: .long .Ltmp{{[0-9]+}} +; CHECK-NEXT: .long 2 +; CHECK-NEXT: .long 73 +; CHECK-NEXT: .long 4 +; CHECK-NEXT: .long .Ltmp{{[0-9]+}} +; CHECK-NEXT: .long 2 +; CHECK-NEXT: .long 73 +; CHECK-NEXT: .long 5 +; CHECK-NEXT: .long .Ltmp{{[0-9]+}} +; CHECK-NEXT: .long 2 +; CHECK-NEXT: .long 73 +; CHECK-NEXT: .long 5 +; CHECK-NEXT: .long .Ltmp{{[0-9]+}} +; CHECK-NEXT: .long 2 +; CHECK-NEXT: .long 73 +; CHECK-NEXT: .long 3 + +; Function Attrs: argmemonly nounwind willreturn +declare void @llvm.lifetime.start.p0i8(i64, i8* nocapture) #1 + +; Function Attrs: nounwind readnone +declare i16* @llvm.preserve.struct.access.index.p0i16.p0s_struct.ss(%struct.s*, i32, i32) #2 + +; Function Attrs: nounwind readnone +declare i32 @llvm.bpf.preserve.field.info.p0i16(i16*, i64) #2 + +declare dso_local void @bpf_probe_read(i8*, i32, i8*) local_unnamed_addr #3 + +; Function Attrs: argmemonly nounwind willreturn +declare void @llvm.lifetime.end.p0i8(i64, i8* nocapture) #1 + +; Function Attrs: nounwind readnone speculatable willreturn +declare void @llvm.dbg.value(metadata, metadata, metadata) #4 + +attributes #0 = { nounwind "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" } +attributes #1 = { argmemonly nounwind willreturn } +attributes #2 = { nounwind readnone } +attributes #3 = { "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" } +attributes #4 = { nounwind readnone speculatable willreturn } +attributes #5 = { nounwind } + +!llvm.dbg.cu = !{!0} +!llvm.module.flags = !{!16, !17, !18} +!llvm.ident = !{!19} + +!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 10.0.0 (https://github.com/llvm/llvm-project.git 923aa0ce806f7739b754167239fee2c9a15e2f31)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, retainedTypes: !12, nameTableKind: None) +!1 = !DIFile(filename: "test.c", directory: "/tmp/home/yhs/work/tests/core") +!2 = !{!3} +!3 = !DICompositeType(tag: DW_TAG_enumeration_type, file: !1, line: 6, baseType: !4, size: 32, elements: !5) +!4 = !DIBasicType(name: "unsigned int", size: 32, encoding: DW_ATE_unsigned) +!5 = !{!6, !7, !8, !9, !10, !11} +!6 = !DIEnumerator(name: "FIELD_BYTE_OFFSET", value: 0, isUnsigned: true) +!7 = !DIEnumerator(name: "FIELD_BYTE_SIZE", value: 1, isUnsigned: true) +!8 = !DIEnumerator(name: "FIELD_EXISTENCE", value: 2, isUnsigned: true) +!9 = !DIEnumerator(name: "FIELD_SIGNEDNESS", value: 3, isUnsigned: true) +!10 = !DIEnumerator(name: "FIELD_LSHIFT_U64", value: 4, isUnsigned: true) +!11 = !DIEnumerator(name: "FIELD_RSHIFT_U64", value: 5, isUnsigned: true) +!12 = !{!13, !15} +!13 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !14, size: 64) +!14 = !DIDerivedType(tag: DW_TAG_const_type, baseType: null) +!15 = !DIBasicType(name: "long long int", size: 64, encoding: DW_ATE_signed) +!16 = !{i32 2, !"Dwarf Version", i32 4} +!17 = !{i32 2, !"Debug Info Version", i32 3} +!18 = !{i32 1, !"wchar_size", i32 4} +!19 = !{!"clang version 10.0.0 (https://github.com/llvm/llvm-project.git 923aa0ce806f7739b754167239fee2c9a15e2f31)"} +!20 = distinct !DISubprogram(name: "field_read", scope: !1, file: !1, line: 15, type: !21, scopeLine: 15, flags: DIFlagPrototyped, isDefinition: true, isOptimized: true, unit: !0, retainedNodes: !30) +!21 = !DISubroutineType(types: !22) +!22 = !{!23, !24} +!23 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +!24 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !25, size: 64) +!25 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "s", file: !1, line: 1, size: 64, elements: !26) +!26 = !{!27, !28, !29} +!27 = !DIDerivedType(tag: DW_TAG_member, name: "a", scope: !25, file: !1, line: 2, baseType: !23, size: 32) +!28 = !DIDerivedType(tag: DW_TAG_member, name: "b1", scope: !25, file: !1, line: 3, baseType: !23, size: 9, offset: 32, flags: DIFlagBitField, extraData: i64 32) +!29 = !DIDerivedType(tag: DW_TAG_member, name: "b2", scope: !25, file: !1, line: 4, baseType: !23, size: 4, offset: 41, flags: DIFlagBitField, extraData: i64 32) +!30 = !{!31, !32, !34, !35, !36} +!31 = !DILocalVariable(name: "arg", arg: 1, scope: !20, file: !1, line: 15, type: !24) +!32 = !DILocalVariable(name: "ull", scope: !20, file: !1, line: 16, type: !33) +!33 = !DIBasicType(name: "long long unsigned int", size: 64, encoding: DW_ATE_unsigned) +!34 = !DILocalVariable(name: "offset", scope: !20, file: !1, line: 17, type: !4) +!35 = !DILocalVariable(name: "size", scope: !20, file: !1, line: 18, type: !4) +!36 = !DILocalVariable(name: "lshift", scope: !20, file: !1, line: 19, type: !4) +!37 = !DILocation(line: 0, scope: !20) +!38 = !DILocation(line: 16, column: 3, scope: !20) +!39 = !DILocation(line: 17, column: 56, scope: !20) +!40 = !DILocation(line: 17, column: 21, scope: !20) +!41 = !DILocation(line: 18, column: 19, scope: !20) +!42 = !DILocation(line: 21, column: 30, scope: !20) +!43 = !DILocation(line: 21, column: 48, scope: !20) +!44 = !DILocation(line: 21, column: 3, scope: !20) +!45 = !DILocation(line: 22, column: 12, scope: !20) +!46 = !DILocation(line: 26, column: 7, scope: !20) +!47 = !{!48, !48, i64 0} +!48 = !{!"long long", !49, i64 0} +!49 = !{!"omnipotent char", !50, i64 0} +!50 = !{!"Simple C/C++ TBAA"} +!51 = !DILocation(line: 27, column: 7, scope: !52) +!52 = distinct !DILexicalBlock(scope: !20, file: !1, line: 27, column: 7) +!53 = !DILocation(line: 27, column: 7, scope: !20) +!54 = !DILocation(line: 30, column: 1, scope: !20) diff --git a/llvm/test/CodeGen/SBF/CORE/offset-reloc-fieldinfo-2.ll b/llvm/test/CodeGen/SBF/CORE/offset-reloc-fieldinfo-2.ll new file mode 100644 index 0000000000000..5148a2760318d --- /dev/null +++ b/llvm/test/CodeGen/SBF/CORE/offset-reloc-fieldinfo-2.ll @@ -0,0 +1,263 @@ +; RUN: opt -O2 %s | llvm-dis > %t1 +; RUN: llc -sbf-enable-btf-emission -filetype=asm -o - %t1 | FileCheck -check-prefixes=CHECK,CHECK-EL,CHECK64 %s +; RUN: llc -sbf-enable-btf-emission -mattr=+alu32 -filetype=asm -o - %t1 | FileCheck -check-prefixes=CHECK,CHECK-EL,CHECK32 %s +; Source code: +; struct s { +; int a; +; int b1:9; +; int b2:4; +; }; +; enum { +; FIELD_BYTE_OFFSET = 0, +; FIELD_BYTE_SIZE, +; FIELD_EXISTENCE, +; FIELD_SIGNEDNESS, +; FIELD_LSHIFT_U64, +; FIELD_RSHIFT_U64, +; }; +; int field_read(struct s *arg) { +; unsigned long long ull; +; unsigned offset = __builtin_preserve_field_info(arg->b2, FIELD_BYTE_OFFSET); +; unsigned size = __builtin_preserve_field_info(arg->b2, FIELD_BYTE_SIZE); +; switch(size) { +; case 1: +; ull = *(unsigned char *)((void *)arg + offset); break; +; case 2: +; ull = *(unsigned short *)((void *)arg + offset); break; +; case 4: +; ull = *(unsigned int *)((void *)arg + offset); break; +; case 8: +; ull = *(unsigned long long *)((void *)arg + offset); break; +; } +; ull <<= __builtin_preserve_field_info(arg->b2, FIELD_LSHIFT_U64); +; if (__builtin_preserve_field_info(arg->b2, FIELD_SIGNEDNESS)) +; return ((long long)ull) >>__builtin_preserve_field_info(arg->b2, FIELD_RSHIFT_U64); +; return ull >> __builtin_preserve_field_info(arg->b2, FIELD_RSHIFT_U64); +; } +; Compilation flag: +; clang -target bpfel -O2 -g -S -emit-llvm -Xclang -disable-llvm-passes test.c + +target triple = "sbf" + +%struct.s = type { i32, i16 } + +; Function Attrs: nounwind readonly +define dso_local i32 @field_read(%struct.s* %arg) local_unnamed_addr #0 !dbg !26 { +entry: + call void @llvm.dbg.value(metadata %struct.s* %arg, metadata !37, metadata !DIExpression()), !dbg !41 + %0 = tail call i16* @llvm.preserve.struct.access.index.p0i16.p0s_struct.ss(%struct.s* elementtype(%struct.s) %arg, i32 1, i32 2), !dbg !42, !llvm.preserve.access.index !31 + %1 = tail call i32 @llvm.bpf.preserve.field.info.p0i16(i16* %0, i64 0), !dbg !43 + call void @llvm.dbg.value(metadata i32 %1, metadata !39, metadata !DIExpression()), !dbg !41 + %2 = tail call i32 @llvm.bpf.preserve.field.info.p0i16(i16* %0, i64 1), !dbg !44 + call void @llvm.dbg.value(metadata i32 %2, metadata !40, metadata !DIExpression()), !dbg !41 + switch i32 %2, label %sw.epilog [ + i32 1, label %sw.bb + i32 2, label %sw.bb1 + i32 4, label %sw.bb5 + i32 8, label %sw.bb9 + ], !dbg !45 + +sw.bb: ; preds = %entry + %3 = bitcast %struct.s* %arg to i8*, !dbg !46 + %idx.ext = zext i32 %1 to i64, !dbg !48 + %add.ptr = getelementptr i8, i8* %3, i64 %idx.ext, !dbg !48 + %4 = load i8, i8* %add.ptr, align 1, !dbg !49, !tbaa !50 + %conv = zext i8 %4 to i64, !dbg !49 + call void @llvm.dbg.value(metadata i64 %conv, metadata !38, metadata !DIExpression()), !dbg !41 + br label %sw.epilog, !dbg !53 + +sw.bb1: ; preds = %entry + %5 = bitcast %struct.s* %arg to i8*, !dbg !54 + %idx.ext2 = zext i32 %1 to i64, !dbg !55 + %add.ptr3 = getelementptr i8, i8* %5, i64 %idx.ext2, !dbg !55 + %6 = bitcast i8* %add.ptr3 to i16*, !dbg !56 + %7 = load i16, i16* %6, align 2, !dbg !57, !tbaa !58 + %conv4 = zext i16 %7 to i64, !dbg !57 + call void @llvm.dbg.value(metadata i64 %conv4, metadata !38, metadata !DIExpression()), !dbg !41 + br label %sw.epilog, !dbg !60 + +sw.bb5: ; preds = %entry + %8 = bitcast %struct.s* %arg to i8*, !dbg !61 + %idx.ext6 = zext i32 %1 to i64, !dbg !62 + %add.ptr7 = getelementptr i8, i8* %8, i64 %idx.ext6, !dbg !62 + %9 = bitcast i8* %add.ptr7 to i32*, !dbg !63 + %10 = load i32, i32* %9, align 4, !dbg !64, !tbaa !65 + %conv8 = zext i32 %10 to i64, !dbg !64 + call void @llvm.dbg.value(metadata i64 %conv8, metadata !38, metadata !DIExpression()), !dbg !41 + br label %sw.epilog, !dbg !67 + +sw.bb9: ; preds = %entry + %11 = bitcast %struct.s* %arg to i8*, !dbg !68 + %idx.ext10 = zext i32 %1 to i64, !dbg !69 + %add.ptr11 = getelementptr i8, i8* %11, i64 %idx.ext10, !dbg !69 + %12 = bitcast i8* %add.ptr11 to i64*, !dbg !70 + %13 = load i64, i64* %12, align 8, !dbg !71, !tbaa !72 + call void @llvm.dbg.value(metadata i64 %13, metadata !38, metadata !DIExpression()), !dbg !41 + br label %sw.epilog, !dbg !74 + +sw.epilog: ; preds = %entry, %sw.bb9, %sw.bb5, %sw.bb1, %sw.bb + %ull.0 = phi i64 [ undef, %entry ], [ %13, %sw.bb9 ], [ %conv8, %sw.bb5 ], [ %conv4, %sw.bb1 ], [ %conv, %sw.bb ] + call void @llvm.dbg.value(metadata i64 %ull.0, metadata !38, metadata !DIExpression()), !dbg !41 + %14 = tail call i32 @llvm.bpf.preserve.field.info.p0i16(i16* %0, i64 4), !dbg !75 + %sh_prom = zext i32 %14 to i64, !dbg !76 + %shl = shl i64 %ull.0, %sh_prom, !dbg !76 + call void @llvm.dbg.value(metadata i64 %shl, metadata !38, metadata !DIExpression()), !dbg !41 + %15 = tail call i32 @llvm.bpf.preserve.field.info.p0i16(i16* %0, i64 3), !dbg !77 + %tobool = icmp eq i32 %15, 0, !dbg !77 + %16 = tail call i32 @llvm.bpf.preserve.field.info.p0i16(i16* %0, i64 5), !dbg !41 + %sh_prom12 = zext i32 %16 to i64, !dbg !41 + %shr = ashr i64 %shl, %sh_prom12, !dbg !79 + %shr15 = lshr i64 %shl, %sh_prom12, !dbg !79 + %retval.0.in = select i1 %tobool, i64 %shr15, i64 %shr, !dbg !79 + %retval.0 = trunc i64 %retval.0.in to i32, !dbg !41 + ret i32 %retval.0, !dbg !80 +} + +; CHECK: mov64 r{{[0-9]+}}, 4 +; CHECK: mov64 r{{[0-9]+}}, 4 +; CHECK-EL: lsh64 r{{[0-9]+}}, 51 +; CHECK64: rsh64 r{{[0-9]+}}, 60 +; CHECK64: rsh64 r{{[0-9]+}}, 60 +; CHECK32: rsh64 r{{[0-9]+}}, 60 +; CHECK32: arsh64 r{{[0-9]+}}, 60 +; CHECK: mov64 r{{[0-9]+}}, 1 + +; CHECK: .long 1 # BTF_KIND_STRUCT(id = 2) +; CHECK: .byte 115 # string offset=1 +; CHECK: .ascii ".text" # string offset=30 +; CHECK: .ascii "0:2" # string offset=36 + +; CHECK: .long 16 # FieldReloc +; CHECK-NEXT: .long 30 # Field reloc section string offset=30 +; CHECK-NEXT: .long 8 +; CHECK-NEXT: .long .Ltmp{{[0-9]+}} +; CHECK-NEXT: .long 2 +; CHECK-NEXT: .long 36 +; CHECK-NEXT: .long 1 +; CHECK-NEXT: .long .Ltmp{{[0-9]+}} +; CHECK-NEXT: .long 2 +; CHECK-NEXT: .long 36 +; CHECK-NEXT: .long 0 +; CHECK-NEXT: .long .Ltmp{{[0-9]+}} +; CHECK-NEXT: .long 2 +; CHECK-NEXT: .long 36 +; CHECK-NEXT: .long 0 +; CHECK-NEXT: .long .Ltmp{{[0-9]+}} +; CHECK-NEXT: .long 2 +; CHECK-NEXT: .long 36 +; CHECK-NEXT: .long 0 +; CHECK-NEXT: .long .Ltmp{{[0-9]+}} +; CHECK-NEXT: .long 2 +; CHECK-NEXT: .long 36 +; CHECK-NEXT: .long 4 +; CHECK-NEXT: .long .Ltmp{{[0-9]+}} +; CHECK-NEXT: .long 2 +; CHECK-NEXT: .long 36 +; CHECK-NEXT: .long 5 +; CHECK-NEXT: .long .Ltmp{{[0-9]+}} +; CHECK-NEXT: .long 2 +; CHECK-NEXT: .long 36 +; CHECK-NEXT: .long 5 +; CHECK-NEXT: .long .Ltmp{{[0-9]+}} +; CHECK-NEXT: .long 2 +; CHECK-NEXT: .long 36 +; CHECK-NEXT: .long 3 + +; Function Attrs: nounwind readnone +declare i16* @llvm.preserve.struct.access.index.p0i16.p0s_struct.ss(%struct.s*, i32, i32) #1 + +; Function Attrs: nounwind readnone +declare i32 @llvm.bpf.preserve.field.info.p0i16(i16*, i64) #1 + +; Function Attrs: nounwind readnone speculatable willreturn +declare void @llvm.dbg.value(metadata, metadata, metadata) #2 + +attributes #0 = { nounwind readonly "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" } +attributes #1 = { nounwind readnone } +attributes #2 = { nounwind readnone speculatable willreturn } + +!llvm.dbg.cu = !{!0} +!llvm.module.flags = !{!22, !23, !24} +!llvm.ident = !{!25} + +!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 10.0.0 (https://github.com/llvm/llvm-project.git 923aa0ce806f7739b754167239fee2c9a15e2f31)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, retainedTypes: !12, nameTableKind: None) +!1 = !DIFile(filename: "test.c", directory: "/tmp/home/yhs/work/tests/core") +!2 = !{!3} +!3 = !DICompositeType(tag: DW_TAG_enumeration_type, file: !1, line: 6, baseType: !4, size: 32, elements: !5) +!4 = !DIBasicType(name: "unsigned int", size: 32, encoding: DW_ATE_unsigned) +!5 = !{!6, !7, !8, !9, !10, !11} +!6 = !DIEnumerator(name: "FIELD_BYTE_OFFSET", value: 0, isUnsigned: true) +!7 = !DIEnumerator(name: "FIELD_BYTE_SIZE", value: 1, isUnsigned: true) +!8 = !DIEnumerator(name: "FIELD_EXISTENCE", value: 2, isUnsigned: true) +!9 = !DIEnumerator(name: "FIELD_SIGNEDNESS", value: 3, isUnsigned: true) +!10 = !DIEnumerator(name: "FIELD_LSHIFT_U64", value: 4, isUnsigned: true) +!11 = !DIEnumerator(name: "FIELD_RSHIFT_U64", value: 5, isUnsigned: true) +!12 = !{!13, !15, !16, !18, !19, !21} +!13 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !14, size: 64) +!14 = !DIBasicType(name: "unsigned char", size: 8, encoding: DW_ATE_unsigned_char) +!15 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: null, size: 64) +!16 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !17, size: 64) +!17 = !DIBasicType(name: "unsigned short", size: 16, encoding: DW_ATE_unsigned) +!18 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !4, size: 64) +!19 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !20, size: 64) +!20 = !DIBasicType(name: "long long unsigned int", size: 64, encoding: DW_ATE_unsigned) +!21 = !DIBasicType(name: "long long int", size: 64, encoding: DW_ATE_signed) +!22 = !{i32 2, !"Dwarf Version", i32 4} +!23 = !{i32 2, !"Debug Info Version", i32 3} +!24 = !{i32 1, !"wchar_size", i32 4} +!25 = !{!"clang version 10.0.0 (https://github.com/llvm/llvm-project.git 923aa0ce806f7739b754167239fee2c9a15e2f31)"} +!26 = distinct !DISubprogram(name: "field_read", scope: !1, file: !1, line: 14, type: !27, scopeLine: 14, flags: DIFlagPrototyped, isDefinition: true, isOptimized: true, unit: !0, retainedNodes: !36) +!27 = !DISubroutineType(types: !28) +!28 = !{!29, !30} +!29 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +!30 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !31, size: 64) +!31 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "s", file: !1, line: 1, size: 64, elements: !32) +!32 = !{!33, !34, !35} +!33 = !DIDerivedType(tag: DW_TAG_member, name: "a", scope: !31, file: !1, line: 2, baseType: !29, size: 32) +!34 = !DIDerivedType(tag: DW_TAG_member, name: "b1", scope: !31, file: !1, line: 3, baseType: !29, size: 9, offset: 32, flags: DIFlagBitField, extraData: i64 32) +!35 = !DIDerivedType(tag: DW_TAG_member, name: "b2", scope: !31, file: !1, line: 4, baseType: !29, size: 4, offset: 41, flags: DIFlagBitField, extraData: i64 32) +!36 = !{!37, !38, !39, !40} +!37 = !DILocalVariable(name: "arg", arg: 1, scope: !26, file: !1, line: 14, type: !30) +!38 = !DILocalVariable(name: "ull", scope: !26, file: !1, line: 15, type: !20) +!39 = !DILocalVariable(name: "offset", scope: !26, file: !1, line: 16, type: !4) +!40 = !DILocalVariable(name: "size", scope: !26, file: !1, line: 17, type: !4) +!41 = !DILocation(line: 0, scope: !26) +!42 = !DILocation(line: 16, column: 56, scope: !26) +!43 = !DILocation(line: 16, column: 21, scope: !26) +!44 = !DILocation(line: 17, column: 19, scope: !26) +!45 = !DILocation(line: 18, column: 3, scope: !26) +!46 = !DILocation(line: 20, column: 30, scope: !47) +!47 = distinct !DILexicalBlock(scope: !26, file: !1, line: 18, column: 16) +!48 = !DILocation(line: 20, column: 42, scope: !47) +!49 = !DILocation(line: 20, column: 11, scope: !47) +!50 = !{!51, !51, i64 0} +!51 = !{!"omnipotent char", !52, i64 0} +!52 = !{!"Simple C/C++ TBAA"} +!53 = !DILocation(line: 20, column: 53, scope: !47) +!54 = !DILocation(line: 22, column: 31, scope: !47) +!55 = !DILocation(line: 22, column: 43, scope: !47) +!56 = !DILocation(line: 22, column: 12, scope: !47) +!57 = !DILocation(line: 22, column: 11, scope: !47) +!58 = !{!59, !59, i64 0} +!59 = !{!"short", !51, i64 0} +!60 = !DILocation(line: 22, column: 54, scope: !47) +!61 = !DILocation(line: 24, column: 29, scope: !47) +!62 = !DILocation(line: 24, column: 41, scope: !47) +!63 = !DILocation(line: 24, column: 12, scope: !47) +!64 = !DILocation(line: 24, column: 11, scope: !47) +!65 = !{!66, !66, i64 0} +!66 = !{!"int", !51, i64 0} +!67 = !DILocation(line: 24, column: 52, scope: !47) +!68 = !DILocation(line: 26, column: 35, scope: !47) +!69 = !DILocation(line: 26, column: 47, scope: !47) +!70 = !DILocation(line: 26, column: 12, scope: !47) +!71 = !DILocation(line: 26, column: 11, scope: !47) +!72 = !{!73, !73, i64 0} +!73 = !{!"long long", !51, i64 0} +!74 = !DILocation(line: 26, column: 58, scope: !47) +!75 = !DILocation(line: 28, column: 11, scope: !26) +!76 = !DILocation(line: 28, column: 7, scope: !26) +!77 = !DILocation(line: 29, column: 7, scope: !78) +!78 = distinct !DILexicalBlock(scope: !26, file: !1, line: 29, column: 7) +!79 = !DILocation(line: 29, column: 7, scope: !26) +!80 = !DILocation(line: 32, column: 1, scope: !26) diff --git a/llvm/test/CodeGen/SBF/CORE/offset-reloc-global-1.ll b/llvm/test/CodeGen/SBF/CORE/offset-reloc-global-1.ll new file mode 100644 index 0000000000000..1b61455100697 --- /dev/null +++ b/llvm/test/CodeGen/SBF/CORE/offset-reloc-global-1.ll @@ -0,0 +1,83 @@ +; RUN: opt -O2 %s | llvm-dis > %t1 +; RUN: llc -sbf-enable-btf-emission -filetype=asm -o - %t1 | FileCheck -check-prefixes=CHECK %s +; RUN: llc -sbf-enable-btf-emission -mattr=+alu32 -filetype=asm -o - %t1 | FileCheck -check-prefixes=CHECK %s +; Source code: +; typedef struct v3 { int a; int b; } __v3; +; #define _(x) (__builtin_preserve_access_index(x)) +; int get_value(const int *arg); +; __v3 g __attribute__((section("stats"))); +; int test() { +; return get_value(_(&g.b)); +; } +; Compilation flag: +; clang -target bpf -O2 -g -S -emit-llvm -Xclang -disable-llvm-passes test.c + +target triple = "sbf" + +%struct.v3 = type { i32, i32 } + +@g = dso_local global %struct.v3 zeroinitializer, section "stats", align 4, !dbg !0 + +; Function Attrs: nounwind +define dso_local i32 @test() local_unnamed_addr #0 !dbg !16 { +entry: + %0 = tail call i32* @llvm.preserve.struct.access.index.p0i32.p0s_struct.v3s(%struct.v3* elementtype(%struct.v3) nonnull @g, i32 1, i32 1), !dbg !19, !llvm.preserve.access.index !7 + %call = tail call i32 @get_value(i32* %0) #3, !dbg !20 + ret i32 %call, !dbg !21 +} + +; CHECK: mov64 r2, 4 +; CHECK: lddw r1, g +; CHECK: add64 r1, r2 +; CHECK: call get_value + +; CHECK: .long 16 # BTF_KIND_STRUCT(id = [[TID1:[0-9]+]]) + +; CHECK: .ascii ".text" # string offset=10 +; CHECK: .ascii "v3" # string offset=16 +; CHECK: .ascii "0:1" # string offset=23 + +; CHECK: .long 16 # FieldReloc +; CHECK-NEXT: .long 10 # Field reloc section string offset=10 +; CHECK-NEXT: .long 1 +; CHECK-NEXT: .long .Ltmp{{[0-9]+}} +; CHECK-NEXT: .long [[TID1]] +; CHECK-NEXT: .long 23 +; CHECK-NEXT: .long 0 + +declare dso_local i32 @get_value(i32*) local_unnamed_addr #1 + +; Function Attrs: nounwind readnone +declare i32* @llvm.preserve.struct.access.index.p0i32.p0s_struct.v3s(%struct.v3*, i32, i32) #2 + +attributes #0 = { nounwind "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" } +attributes #1 = { "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" } +attributes #2 = { nounwind readnone } +attributes #3 = { nounwind } + +!llvm.dbg.cu = !{!2} +!llvm.module.flags = !{!12, !13, !14} +!llvm.ident = !{!15} + +!0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression()) +!1 = distinct !DIGlobalVariable(name: "g", scope: !2, file: !3, line: 4, type: !6, isLocal: false, isDefinition: true) +!2 = distinct !DICompileUnit(language: DW_LANG_C99, file: !3, producer: "clang version 10.0.0 (trunk 367256) (llvm/trunk 367266)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !4, globals: !5, nameTableKind: None) +!3 = !DIFile(filename: "test.c", directory: "/tmp/home/yhs/work/tests/llvm/cast") +!4 = !{} +!5 = !{!0} +!6 = !DIDerivedType(tag: DW_TAG_typedef, name: "__v3", file: !3, line: 1, baseType: !7) +!7 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "v3", file: !3, line: 1, size: 64, elements: !8) +!8 = !{!9, !11} +!9 = !DIDerivedType(tag: DW_TAG_member, name: "a", scope: !7, file: !3, line: 1, baseType: !10, size: 32) +!10 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +!11 = !DIDerivedType(tag: DW_TAG_member, name: "b", scope: !7, file: !3, line: 1, baseType: !10, size: 32, offset: 32) +!12 = !{i32 2, !"Dwarf Version", i32 4} +!13 = !{i32 2, !"Debug Info Version", i32 3} +!14 = !{i32 1, !"wchar_size", i32 4} +!15 = !{!"clang version 10.0.0 (trunk 367256) (llvm/trunk 367266)"} +!16 = distinct !DISubprogram(name: "test", scope: !3, file: !3, line: 5, type: !17, scopeLine: 5, isDefinition: true, isOptimized: true, unit: !2, retainedNodes: !4) +!17 = !DISubroutineType(types: !18) +!18 = !{!10} +!19 = !DILocation(line: 6, column: 20, scope: !16) +!20 = !DILocation(line: 6, column: 10, scope: !16) +!21 = !DILocation(line: 6, column: 3, scope: !16) diff --git a/llvm/test/CodeGen/SBF/CORE/offset-reloc-global-2.ll b/llvm/test/CodeGen/SBF/CORE/offset-reloc-global-2.ll new file mode 100644 index 0000000000000..e094c55d67ca5 --- /dev/null +++ b/llvm/test/CodeGen/SBF/CORE/offset-reloc-global-2.ll @@ -0,0 +1,99 @@ +; RUN: opt -O2 %s | llvm-dis > %t1 +; RUN: llc -sbf-enable-btf-emission -filetype=asm -o - %t1 | FileCheck -check-prefixes=CHECK %s +; RUN: llc -sbf-enable-btf-emission -mattr=+alu32 -filetype=asm -o - %t1 | FileCheck -check-prefixes=CHECK %s +; Source code: +; typedef struct v3 { int a; int b; } __v3; +; #define _(x) (__builtin_preserve_access_index(x)) +; int get_value(const int *arg); +; __v3 g[4][5] __attribute__((section("stats"))); +; int test() { +; return get_value(_(&g[1][2].b)); +; } +; Compilation flag: +; clang -target bpf -O2 -g -S -emit-llvm -Xclang -disable-llvm-passes test.c + +target triple = "sbf" + +%struct.v3 = type { i32, i32 } + +@g = dso_local global [4 x [5 x %struct.v3]] zeroinitializer, section "stats", align 4, !dbg !0 + +; Function Attrs: nounwind +define dso_local i32 @test() local_unnamed_addr #0 !dbg !23 { +entry: + %0 = tail call [5 x %struct.v3]* @llvm.preserve.array.access.index.p0a5s_struct.v3s.p0a4a5s_struct.v3s([4 x [5 x %struct.v3]]* elementtype([4 x [5 x %struct.v3]]) nonnull @g, i32 1, i32 1), !dbg !26, !llvm.preserve.access.index !6 + %1 = tail call %struct.v3* @llvm.preserve.array.access.index.p0s_struct.v3s.p0a5s_struct.v3s([5 x %struct.v3]* elementtype([5 x %struct.v3]) %0, i32 1, i32 2), !dbg !26, !llvm.preserve.access.index !16 + %2 = tail call i32* @llvm.preserve.struct.access.index.p0i32.p0s_struct.v3s(%struct.v3* elementtype(%struct.v3) %1, i32 1, i32 1), !dbg !26, !llvm.preserve.access.index !8 + %call = tail call i32 @get_value(i32* %2) #3, !dbg !27 + ret i32 %call, !dbg !28 +} + +; CHECK: mov64 r2, 60 +; CHECK: lddw r1, g +; CHECK: add64 r1, r2 +; CHECK: call get_value + +; CHECK: .long 16 # BTF_KIND_STRUCT(id = [[TID1:[0-9]+]]) + +; CHECK: .ascii ".text" # string offset=10 +; CHECK: .ascii "v3" # string offset=16 +; CHECK: .ascii "7:1" # string offset=23 + +; CHECK: .long 16 # FieldReloc +; CHECK-NEXT: .long 10 # Field reloc section string offset=10 +; CHECK-NEXT: .long 1 +; CHECK-NEXT: .long .Ltmp{{[0-9]+}} +; CHECK-NEXT: .long [[TID1]] +; CHECK-NEXT: .long 23 +; CHECK-NEXT: .long 0 + + +declare dso_local i32 @get_value(i32*) local_unnamed_addr #1 + +; Function Attrs: nounwind readnone +declare [5 x %struct.v3]* @llvm.preserve.array.access.index.p0a5s_struct.v3s.p0a4a5s_struct.v3s([4 x [5 x %struct.v3]]*, i32, i32) #2 + +; Function Attrs: nounwind readnone +declare %struct.v3* @llvm.preserve.array.access.index.p0s_struct.v3s.p0a5s_struct.v3s([5 x %struct.v3]*, i32, i32) #2 + +; Function Attrs: nounwind readnone +declare i32* @llvm.preserve.struct.access.index.p0i32.p0s_struct.v3s(%struct.v3*, i32, i32) #2 + +attributes #0 = { nounwind "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" } +attributes #1 = { "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" } +attributes #2 = { nounwind readnone } +attributes #3 = { nounwind } + +!llvm.dbg.cu = !{!2} +!llvm.module.flags = !{!19, !20, !21} +!llvm.ident = !{!22} + +!0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression()) +!1 = distinct !DIGlobalVariable(name: "g", scope: !2, file: !3, line: 4, type: !6, isLocal: false, isDefinition: true) +!2 = distinct !DICompileUnit(language: DW_LANG_C99, file: !3, producer: "clang version 10.0.0 (trunk 367256) (llvm/trunk 367266)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !4, retainedTypes: !5, globals: !18, nameTableKind: None) +!3 = !DIFile(filename: "test.c", directory: "/tmp/home/yhs/work/tests/llvm/cast") +!4 = !{} +!5 = !{!6, !16} +!6 = !DICompositeType(tag: DW_TAG_array_type, baseType: !7, size: 1280, elements: !13) +!7 = !DIDerivedType(tag: DW_TAG_typedef, name: "__v3", file: !3, line: 1, baseType: !8) +!8 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "v3", file: !3, line: 1, size: 64, elements: !9) +!9 = !{!10, !12} +!10 = !DIDerivedType(tag: DW_TAG_member, name: "a", scope: !8, file: !3, line: 1, baseType: !11, size: 32) +!11 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +!12 = !DIDerivedType(tag: DW_TAG_member, name: "b", scope: !8, file: !3, line: 1, baseType: !11, size: 32, offset: 32) +!13 = !{!14, !15} +!14 = !DISubrange(count: 4) +!15 = !DISubrange(count: 5) +!16 = !DICompositeType(tag: DW_TAG_array_type, baseType: !7, size: 320, elements: !17) +!17 = !{!15} +!18 = !{!0} +!19 = !{i32 2, !"Dwarf Version", i32 4} +!20 = !{i32 2, !"Debug Info Version", i32 3} +!21 = !{i32 1, !"wchar_size", i32 4} +!22 = !{!"clang version 10.0.0 (trunk 367256) (llvm/trunk 367266)"} +!23 = distinct !DISubprogram(name: "test", scope: !3, file: !3, line: 5, type: !24, scopeLine: 5, isDefinition: true, isOptimized: true, unit: !2, retainedNodes: !4) +!24 = !DISubroutineType(types: !25) +!25 = !{!11} +!26 = !DILocation(line: 6, column: 20, scope: !23) +!27 = !DILocation(line: 6, column: 10, scope: !23) +!28 = !DILocation(line: 6, column: 3, scope: !23) diff --git a/llvm/test/CodeGen/SBF/CORE/offset-reloc-global-3.ll b/llvm/test/CodeGen/SBF/CORE/offset-reloc-global-3.ll new file mode 100644 index 0000000000000..d7845097d6ee5 --- /dev/null +++ b/llvm/test/CodeGen/SBF/CORE/offset-reloc-global-3.ll @@ -0,0 +1,88 @@ +; RUN: opt -O2 %s | llvm-dis > %t1 +; RUN: llc -sbf-enable-btf-emission -filetype=asm -o - %t1 | FileCheck -check-prefixes=CHECK %s +; RUN: llc -sbf-enable-btf-emission -mattr=+alu32 -filetype=asm -o - %t1 | FileCheck -check-prefixes=CHECK %s +; Source code: +; typedef struct v3 { int a; int b; } __v3; +; #define _(x) (__builtin_preserve_access_index(x)) +; int get_value(const int *arg); +; __v3 *g __attribute__((section("stats"))); +; int test() { +; return get_value(_(&g->b)); +; } +; Compilation flag: +; clang -target bpf -O2 -g -S -emit-llvm -Xclang -disable-llvm-passes test.c + +target triple = "sbf" + +%struct.v3 = type { i32, i32 } + +@g = dso_local local_unnamed_addr global %struct.v3* null, section "stats", align 8, !dbg !0 + +; Function Attrs: nounwind +define dso_local i32 @test() local_unnamed_addr #0 !dbg !17 { +entry: + %0 = load %struct.v3*, %struct.v3** @g, align 8, !dbg !20, !tbaa !21 + %1 = tail call i32* @llvm.preserve.struct.access.index.p0i32.p0s_struct.v3s(%struct.v3* elementtype(%struct.v3) %0, i32 1, i32 1), !dbg !20, !llvm.preserve.access.index !8 + %call = tail call i32 @get_value(i32* %1) #3, !dbg !25 + ret i32 %call, !dbg !26 +} + +; CHECK: mov64 r2, 4 +; CHECK: add64 r1, r2 +; CHECK: call get_value + +; CHECK: .long 16 # BTF_KIND_STRUCT(id = [[TID1:[0-9]+]]) + +; CHECK: .ascii ".text" # string offset=10 +; CHECK: .ascii "v3" # string offset=16 +; CHECK: .ascii "0:1" # string offset=23 + +; CHECK: .long 16 # FieldReloc +; CHECK-NEXT: .long 10 # Field reloc section string offset=10 +; CHECK-NEXT: .long 1 +; CHECK-NEXT: .long .Ltmp{{[0-9]+}} +; CHECK-NEXT: .long [[TID1]] +; CHECK-NEXT: .long 23 +; CHECK-NEXT: .long 0 + +declare dso_local i32 @get_value(i32*) local_unnamed_addr #1 + +; Function Attrs: nounwind readnone +declare i32* @llvm.preserve.struct.access.index.p0i32.p0s_struct.v3s(%struct.v3*, i32, i32) #2 + +attributes #0 = { nounwind "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" } +attributes #1 = { "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" } +attributes #2 = { nounwind readnone } +attributes #3 = { nounwind } + +!llvm.dbg.cu = !{!2} +!llvm.module.flags = !{!13, !14, !15} +!llvm.ident = !{!16} + +!0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression()) +!1 = distinct !DIGlobalVariable(name: "g", scope: !2, file: !3, line: 4, type: !6, isLocal: false, isDefinition: true) +!2 = distinct !DICompileUnit(language: DW_LANG_C99, file: !3, producer: "clang version 10.0.0 (trunk 367256) (llvm/trunk 367266)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !4, globals: !5, nameTableKind: None) +!3 = !DIFile(filename: "test.c", directory: "/tmp/home/yhs/work/tests/llvm/cast") +!4 = !{} +!5 = !{!0} +!6 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !7, size: 64) +!7 = !DIDerivedType(tag: DW_TAG_typedef, name: "__v3", file: !3, line: 1, baseType: !8) +!8 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "v3", file: !3, line: 1, size: 64, elements: !9) +!9 = !{!10, !12} +!10 = !DIDerivedType(tag: DW_TAG_member, name: "a", scope: !8, file: !3, line: 1, baseType: !11, size: 32) +!11 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +!12 = !DIDerivedType(tag: DW_TAG_member, name: "b", scope: !8, file: !3, line: 1, baseType: !11, size: 32, offset: 32) +!13 = !{i32 2, !"Dwarf Version", i32 4} +!14 = !{i32 2, !"Debug Info Version", i32 3} +!15 = !{i32 1, !"wchar_size", i32 4} +!16 = !{!"clang version 10.0.0 (trunk 367256) (llvm/trunk 367266)"} +!17 = distinct !DISubprogram(name: "test", scope: !3, file: !3, line: 5, type: !18, scopeLine: 5, isDefinition: true, isOptimized: true, unit: !2, retainedNodes: !4) +!18 = !DISubroutineType(types: !19) +!19 = !{!11} +!20 = !DILocation(line: 6, column: 20, scope: !17) +!21 = !{!22, !22, i64 0} +!22 = !{!"any pointer", !23, i64 0} +!23 = !{!"omnipotent char", !24, i64 0} +!24 = !{!"Simple C/C++ TBAA"} +!25 = !DILocation(line: 6, column: 10, scope: !17) +!26 = !DILocation(line: 6, column: 3, scope: !17) diff --git a/llvm/test/CodeGen/SBF/CORE/offset-reloc-ignore.ll b/llvm/test/CodeGen/SBF/CORE/offset-reloc-ignore.ll new file mode 100644 index 0000000000000..4734c03964ab7 --- /dev/null +++ b/llvm/test/CodeGen/SBF/CORE/offset-reloc-ignore.ll @@ -0,0 +1,65 @@ +; RUN: opt -O2 %s | llvm-dis > %t1 +; RUN: llc -sbf-enable-btf-emission -filetype=asm -o - %t1 | FileCheck -check-prefixes=CHECK %s +; RUN: llc -sbf-enable-btf-emission -mattr=+alu32 -filetype=asm -o - %t1 | FileCheck -check-prefixes=CHECK %s +; Source code: +; #define _(x) (__builtin_preserve_access_index(x)) +; int get_value(const int *arg); +; int test(int *arg) { +; return get_value(_(&arg[4])); +; } +; Compilation flag: +; clang -target bpf -O2 -g -S -emit-llvm -Xclang -disable-llvm-passes test.c + +target triple = "sbf" + +; Function Attrs: nounwind +define dso_local i32 @test(i32* %arg) local_unnamed_addr #0 !dbg !10 { +entry: + call void @llvm.dbg.value(metadata i32* %arg, metadata !14, metadata !DIExpression()), !dbg !15 + %0 = tail call i32* @llvm.preserve.array.access.index.p0i32.p0i32(i32* elementtype(i32) %arg, i32 0, i32 4), !dbg !16, !llvm.preserve.access.index !4 + %call = tail call i32 @get_value(i32* %0) #4, !dbg !17 + ret i32 %call, !dbg !18 +} + +; CHECK: add64 r1, 16 +; CHECK: call get_value +; CHECK: .section .BTF.ext,"",@progbits +; CHECK-NOT: .long 16 # FieldReloc + +declare dso_local i32 @get_value(i32*) local_unnamed_addr #1 + +; Function Attrs: nounwind readnone +declare i32* @llvm.preserve.array.access.index.p0i32.p0i32(i32*, i32, i32) #2 + +; Function Attrs: nounwind readnone speculatable willreturn +declare void @llvm.dbg.value(metadata, metadata, metadata) #3 + +attributes #0 = { nounwind "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" } +attributes #1 = { "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" } +attributes #2 = { nounwind readnone } +attributes #3 = { nounwind readnone speculatable willreturn } +attributes #4 = { nounwind } + +!llvm.dbg.cu = !{!0} +!llvm.module.flags = !{!6, !7, !8} +!llvm.ident = !{!9} + +!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 10.0.0 (trunk 367256) (llvm/trunk 367266)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, retainedTypes: !3, nameTableKind: None) +!1 = !DIFile(filename: "test.c", directory: "/tmp/home/yhs/work/tests/llvm/cast") +!2 = !{} +!3 = !{!4} +!4 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !5, size: 64) +!5 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +!6 = !{i32 2, !"Dwarf Version", i32 4} +!7 = !{i32 2, !"Debug Info Version", i32 3} +!8 = !{i32 1, !"wchar_size", i32 4} +!9 = !{!"clang version 10.0.0 (trunk 367256) (llvm/trunk 367266)"} +!10 = distinct !DISubprogram(name: "test", scope: !1, file: !1, line: 3, type: !11, scopeLine: 3, flags: DIFlagPrototyped, isDefinition: true, isOptimized: true, unit: !0, retainedNodes: !13) +!11 = !DISubroutineType(types: !12) +!12 = !{!5, !4} +!13 = !{!14} +!14 = !DILocalVariable(name: "arg", arg: 1, scope: !10, file: !1, line: 3, type: !4) +!15 = !DILocation(line: 0, scope: !10) +!16 = !DILocation(line: 4, column: 20, scope: !10) +!17 = !DILocation(line: 4, column: 10, scope: !10) +!18 = !DILocation(line: 4, column: 3, scope: !10) diff --git a/llvm/test/CodeGen/SBF/CORE/offset-reloc-middle-chain.ll b/llvm/test/CodeGen/SBF/CORE/offset-reloc-middle-chain.ll new file mode 100644 index 0000000000000..cdd13eccffd78 --- /dev/null +++ b/llvm/test/CodeGen/SBF/CORE/offset-reloc-middle-chain.ll @@ -0,0 +1,133 @@ +; RUN: opt -O2 %s | llvm-dis > %t1 +; RUN: llc -sbf-enable-btf-emission -filetype=asm -o - %t1 | FileCheck -check-prefixes=CHECK %s +; RUN: llc -sbf-enable-btf-emission -mattr=+alu32 -filetype=asm -o - %t1 | FileCheck -check-prefixes=CHECK %s +; Source code: +; struct t1 { +; int c; +; }; +; struct s1 { +; struct t1 b; +; }; +; struct r1 { +; struct s1 a; +; }; +; #define _(x) __builtin_preserve_access_index(x) +; void test1(void *p1, void *p2, void *p3); +; void test(struct r1 *arg) { +; struct s1 *ps = _(&arg->a); +; struct t1 *pt = _(&arg->a.b); +; int *pi = _(&arg->a.b.c); +; test1(ps, pt, pi); +; } +; Compilation flag: +; clang -target bpf -O2 -g -S -emit-llvm -Xclang -disable-llvm-passes test.c + +target triple = "sbf" + +%struct.r1 = type { %struct.s1 } +%struct.s1 = type { %struct.t1 } +%struct.t1 = type { i32 } + +; Function Attrs: nounwind +define dso_local void @test(%struct.r1* %arg) local_unnamed_addr #0 !dbg !7 { +entry: + call void @llvm.dbg.value(metadata %struct.r1* %arg, metadata !22, metadata !DIExpression()), !dbg !29 + %0 = tail call %struct.s1* @llvm.preserve.struct.access.index.p0s_struct.s1s.p0s_struct.r1s(%struct.r1* elementtype(%struct.r1) %arg, i32 0, i32 0), !dbg !30, !llvm.preserve.access.index !11 + call void @llvm.dbg.value(metadata %struct.s1* %0, metadata !23, metadata !DIExpression()), !dbg !29 + %1 = tail call %struct.t1* @llvm.preserve.struct.access.index.p0s_struct.t1s.p0s_struct.s1s(%struct.s1* elementtype(%struct.s1) %0, i32 0, i32 0), !dbg !31, !llvm.preserve.access.index !14 + call void @llvm.dbg.value(metadata %struct.t1* %1, metadata !25, metadata !DIExpression()), !dbg !29 + %2 = tail call i32* @llvm.preserve.struct.access.index.p0i32.p0s_struct.t1s(%struct.t1* elementtype(%struct.t1) %1, i32 0, i32 0), !dbg !32, !llvm.preserve.access.index !17 + call void @llvm.dbg.value(metadata i32* %2, metadata !27, metadata !DIExpression()), !dbg !29 + %3 = bitcast %struct.s1* %0 to i8*, !dbg !33 + %4 = bitcast %struct.t1* %1 to i8*, !dbg !34 + %5 = bitcast i32* %2 to i8*, !dbg !35 + tail call void @test1(i8* %3, i8* %4, i8* %5) #4, !dbg !36 + ret void, !dbg !37 +} + +; CHECK: .long 1 # BTF_KIND_STRUCT(id = 2) + +; CHECK: .ascii "r1" # string offset=1 +; CHECK: .ascii ".text" # string offset=29 +; CHECK: .ascii "0:0" # string offset=72 +; CHECK: .ascii "0:0:0" # string offset=76 +; CHECK: .ascii "0:0:0:0" # string offset=82 + +; CHECK: .long 16 # FieldReloc +; CHECK-NEXT: .long 29 # Field reloc section string offset=29 +; CHECK-NEXT: .long 3 +; CHECK-NEXT: .long .Ltmp{{[0-9]+}} +; CHECK-NEXT: .long 2 +; CHECK-NEXT: .long 72 +; CHECK-NEXT: .long 0 +; CHECK-NEXT: .long .Ltmp{{[0-9]+}} +; CHECK-NEXT: .long 2 +; CHECK-NEXT: .long 76 +; CHECK-NEXT: .long 0 +; CHECK-NEXT: .long .Ltmp{{[0-9]+}} +; CHECK-NEXT: .long 2 +; CHECK-NEXT: .long 82 +; CHECK-NEXT: .long 0 + +; Function Attrs: nounwind readnone +declare %struct.s1* @llvm.preserve.struct.access.index.p0s_struct.s1s.p0s_struct.r1s(%struct.r1*, i32, i32) #1 + +; Function Attrs: nounwind readnone +declare %struct.t1* @llvm.preserve.struct.access.index.p0s_struct.t1s.p0s_struct.s1s(%struct.s1*, i32, i32) #1 + +; Function Attrs: nounwind readnone +declare i32* @llvm.preserve.struct.access.index.p0i32.p0s_struct.t1s(%struct.t1*, i32, i32) #1 + +declare dso_local void @test1(i8*, i8*, i8*) local_unnamed_addr #2 + +; Function Attrs: nounwind readnone speculatable willreturn +declare void @llvm.dbg.value(metadata, metadata, metadata) #3 + +attributes #0 = { nounwind "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" } +attributes #1 = { nounwind readnone } +attributes #2 = { "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" } +attributes #3 = { nounwind readnone speculatable willreturn } +attributes #4 = { nounwind } + +!llvm.dbg.cu = !{!0} +!llvm.module.flags = !{!3, !4, !5} +!llvm.ident = !{!6} + +!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 10.0.0 (https://github.com/llvm/llvm-project.git 42b3328a2368b38fba6bdb0c616fe6c5520e3bc5)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, nameTableKind: None) +!1 = !DIFile(filename: "test.c", directory: "/tmp/home/yhs/work/tests/core") +!2 = !{} +!3 = !{i32 2, !"Dwarf Version", i32 4} +!4 = !{i32 2, !"Debug Info Version", i32 3} +!5 = !{i32 1, !"wchar_size", i32 4} +!6 = !{!"clang version 10.0.0 (https://github.com/llvm/llvm-project.git 42b3328a2368b38fba6bdb0c616fe6c5520e3bc5)"} +!7 = distinct !DISubprogram(name: "test", scope: !1, file: !1, line: 12, type: !8, scopeLine: 12, flags: DIFlagPrototyped, isDefinition: true, isOptimized: true, unit: !0, retainedNodes: !21) +!8 = !DISubroutineType(types: !9) +!9 = !{null, !10} +!10 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !11, size: 64) +!11 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "r1", file: !1, line: 7, size: 32, elements: !12) +!12 = !{!13} +!13 = !DIDerivedType(tag: DW_TAG_member, name: "a", scope: !11, file: !1, line: 8, baseType: !14, size: 32) +!14 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "s1", file: !1, line: 4, size: 32, elements: !15) +!15 = !{!16} +!16 = !DIDerivedType(tag: DW_TAG_member, name: "b", scope: !14, file: !1, line: 5, baseType: !17, size: 32) +!17 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "t1", file: !1, line: 1, size: 32, elements: !18) +!18 = !{!19} +!19 = !DIDerivedType(tag: DW_TAG_member, name: "c", scope: !17, file: !1, line: 2, baseType: !20, size: 32) +!20 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +!21 = !{!22, !23, !25, !27} +!22 = !DILocalVariable(name: "arg", arg: 1, scope: !7, file: !1, line: 12, type: !10) +!23 = !DILocalVariable(name: "ps", scope: !7, file: !1, line: 13, type: !24) +!24 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !14, size: 64) +!25 = !DILocalVariable(name: "pt", scope: !7, file: !1, line: 14, type: !26) +!26 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !17, size: 64) +!27 = !DILocalVariable(name: "pi", scope: !7, file: !1, line: 15, type: !28) +!28 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !20, size: 64) +!29 = !DILocation(line: 0, scope: !7) +!30 = !DILocation(line: 13, column: 19, scope: !7) +!31 = !DILocation(line: 14, column: 19, scope: !7) +!32 = !DILocation(line: 15, column: 13, scope: !7) +!33 = !DILocation(line: 16, column: 9, scope: !7) +!34 = !DILocation(line: 16, column: 13, scope: !7) +!35 = !DILocation(line: 16, column: 17, scope: !7) +!36 = !DILocation(line: 16, column: 3, scope: !7) +!37 = !DILocation(line: 17, column: 1, scope: !7) diff --git a/llvm/test/CodeGen/SBF/CORE/offset-reloc-multi-array-1.ll b/llvm/test/CodeGen/SBF/CORE/offset-reloc-multi-array-1.ll new file mode 100644 index 0000000000000..15519038dfbdb --- /dev/null +++ b/llvm/test/CodeGen/SBF/CORE/offset-reloc-multi-array-1.ll @@ -0,0 +1,105 @@ +; RUN: opt -O2 %s | llvm-dis > %t1 +; RUN: llc -sbf-enable-btf-emission -filetype=asm -o - %t1 | FileCheck -check-prefixes=CHECK %s +; RUN: llc -sbf-enable-btf-emission -mattr=+alu32 -filetype=asm -o - %t1 | FileCheck -check-prefixes=CHECK %s +; Source code: +; typedef int __int; +; typedef struct v3 { int a; __int b[4][4]; } __v3; +; #define _(x) (__builtin_preserve_access_index(x)) +; int get_value(const int *arg); +; int test(__v3 *arg) { +; return get_value(_(&arg[1].b[2][3])); +; } +; Compilation flag: +; clang -target bpf -O2 -g -S -emit-llvm -Xclang -disable-llvm-passes test.c + +target triple = "sbf" + +%struct.v3 = type { i32, [4 x [4 x i32]] } + +; Function Attrs: nounwind +define dso_local i32 @test(%struct.v3* %arg) local_unnamed_addr #0 !dbg !21 { +entry: + call void @llvm.dbg.value(metadata %struct.v3* %arg, metadata !25, metadata !DIExpression()), !dbg !26 + %0 = tail call %struct.v3* @llvm.preserve.array.access.index.p0s_struct.v3s.p0s_struct.v3s(%struct.v3* elementtype(%struct.v3) %arg, i32 0, i32 1), !dbg !27, !llvm.preserve.access.index !4 + %1 = tail call [4 x [4 x i32]]* @llvm.preserve.struct.access.index.p0a4a4i32.p0s_struct.v3s(%struct.v3* elementtype(%struct.v3) %0, i32 1, i32 1), !dbg !27, !llvm.preserve.access.index !6 + %2 = tail call [4 x i32]* @llvm.preserve.array.access.index.p0a4i32.p0a4a4i32([4 x [4 x i32]]* elementtype([4 x [4 x i32]]) %1, i32 1, i32 2), !dbg !27, !llvm.preserve.access.index !11 + %3 = tail call i32* @llvm.preserve.array.access.index.p0i32.p0a4i32([4 x i32]* elementtype([4 x i32]) %2, i32 1, i32 3), !dbg !27, !llvm.preserve.access.index !15 + %call = tail call i32 @get_value(i32* %3) #4, !dbg !28 + ret i32 %call, !dbg !29 +} + +; CHECK: mov64 r2, 116 +; CHECK: add64 r1, r2 +; CHECK: call get_value + +; CHECK: .long 6 # BTF_KIND_STRUCT(id = [[TID1:[0-9]+]]) + +; CHECK: .ascii "v3" # string offset=6 +; CHECK: .ascii ".text" # string offset=52 +; CHECK: .ascii "1:1:2:3" # string offset=58 + +; CHECK: .long 16 # FieldReloc +; CHECK-NEXT: .long 52 # Field reloc section string offset=52 +; CHECK-NEXT: .long 1 +; CHECK-NEXT: .long .Ltmp{{[0-9]+}} +; CHECK-NEXT: .long [[TID1]] +; CHECK-NEXT: .long 58 +; CHECK-NEXT: .long 0 + +declare dso_local i32 @get_value(i32*) local_unnamed_addr #1 + +; Function Attrs: nounwind readnone +declare %struct.v3* @llvm.preserve.array.access.index.p0s_struct.v3s.p0s_struct.v3s(%struct.v3*, i32, i32) #2 + +; Function Attrs: nounwind readnone +declare [4 x [4 x i32]]* @llvm.preserve.struct.access.index.p0a4a4i32.p0s_struct.v3s(%struct.v3*, i32, i32) #2 + +; Function Attrs: nounwind readnone +declare [4 x i32]* @llvm.preserve.array.access.index.p0a4i32.p0a4a4i32([4 x [4 x i32]]*, i32, i32) #2 + +; Function Attrs: nounwind readnone +declare i32* @llvm.preserve.array.access.index.p0i32.p0a4i32([4 x i32]*, i32, i32) #2 + +; Function Attrs: nounwind readnone speculatable willreturn +declare void @llvm.dbg.value(metadata, metadata, metadata) #3 + +attributes #0 = { nounwind "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" } +attributes #1 = { "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" } +attributes #2 = { nounwind readnone } +attributes #3 = { nounwind readnone speculatable willreturn } +attributes #4 = { nounwind } + +!llvm.dbg.cu = !{!0} +!llvm.module.flags = !{!17, !18, !19} +!llvm.ident = !{!20} + +!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 10.0.0 (trunk 367256) (llvm/trunk 367266)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, retainedTypes: !3, nameTableKind: None) +!1 = !DIFile(filename: "test.c", directory: "/tmp/home/yhs/work/tests/llvm/cast") +!2 = !{} +!3 = !{!4, !11, !15} +!4 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !5, size: 64) +!5 = !DIDerivedType(tag: DW_TAG_typedef, name: "__v3", file: !1, line: 2, baseType: !6) +!6 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "v3", file: !1, line: 2, size: 544, elements: !7) +!7 = !{!8, !10} +!8 = !DIDerivedType(tag: DW_TAG_member, name: "a", scope: !6, file: !1, line: 2, baseType: !9, size: 32) +!9 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +!10 = !DIDerivedType(tag: DW_TAG_member, name: "b", scope: !6, file: !1, line: 2, baseType: !11, size: 512, offset: 32) +!11 = !DICompositeType(tag: DW_TAG_array_type, baseType: !12, size: 512, elements: !13) +!12 = !DIDerivedType(tag: DW_TAG_typedef, name: "__int", file: !1, line: 1, baseType: !9) +!13 = !{!14, !14} +!14 = !DISubrange(count: 4) +!15 = !DICompositeType(tag: DW_TAG_array_type, baseType: !12, size: 128, elements: !16) +!16 = !{!14} +!17 = !{i32 2, !"Dwarf Version", i32 4} +!18 = !{i32 2, !"Debug Info Version", i32 3} +!19 = !{i32 1, !"wchar_size", i32 4} +!20 = !{!"clang version 10.0.0 (trunk 367256) (llvm/trunk 367266)"} +!21 = distinct !DISubprogram(name: "test", scope: !1, file: !1, line: 5, type: !22, scopeLine: 5, flags: DIFlagPrototyped, isDefinition: true, isOptimized: true, unit: !0, retainedNodes: !24) +!22 = !DISubroutineType(types: !23) +!23 = !{!9, !4} +!24 = !{!25} +!25 = !DILocalVariable(name: "arg", arg: 1, scope: !21, file: !1, line: 5, type: !4) +!26 = !DILocation(line: 0, scope: !21) +!27 = !DILocation(line: 6, column: 20, scope: !21) +!28 = !DILocation(line: 6, column: 10, scope: !21) +!29 = !DILocation(line: 6, column: 3, scope: !21) diff --git a/llvm/test/CodeGen/SBF/CORE/offset-reloc-multi-array-2.ll b/llvm/test/CodeGen/SBF/CORE/offset-reloc-multi-array-2.ll new file mode 100644 index 0000000000000..d2613698f1e3f --- /dev/null +++ b/llvm/test/CodeGen/SBF/CORE/offset-reloc-multi-array-2.ll @@ -0,0 +1,111 @@ +; RUN: opt -O2 %s | llvm-dis > %t1 +; RUN: llc -sbf-enable-btf-emission -filetype=asm -o - %t1 | FileCheck -check-prefixes=CHECK %s +; RUN: llc -sbf-enable-btf-emission -mattr=+alu32 -filetype=asm -o - %t1 | FileCheck -check-prefixes=CHECK %s +; Source code: +; typedef int __int; +; typedef struct v3 { int a; __int b[4][4][4]; } __v3; +; #define _(x) (__builtin_preserve_access_index(x)) +; int get_value(const int *arg); +; int test(__v3 *arg) { +; return get_value(_(&arg[1].b[2][3][2])); +; } +; Compilation flag: +; clang -target bpf -O2 -g -S -emit-llvm -Xclang -disable-llvm-passes test.c + +target triple = "sbf" + +%struct.v3 = type { i32, [4 x [4 x [4 x i32]]] } + +; Function Attrs: nounwind +define dso_local i32 @test(%struct.v3* %arg) local_unnamed_addr #0 !dbg !23 { +entry: + call void @llvm.dbg.value(metadata %struct.v3* %arg, metadata !27, metadata !DIExpression()), !dbg !28 + %0 = tail call %struct.v3* @llvm.preserve.array.access.index.p0s_struct.v3s.p0s_struct.v3s(%struct.v3* elementtype(%struct.v3) %arg, i32 0, i32 1), !dbg !29, !llvm.preserve.access.index !4 + %1 = tail call [4 x [4 x [4 x i32]]]* @llvm.preserve.struct.access.index.p0a4a4a4i32.p0s_struct.v3s(%struct.v3* elementtype(%struct.v3) %0, i32 1, i32 1), !dbg !29, !llvm.preserve.access.index !6 + %2 = tail call [4 x [4 x i32]]* @llvm.preserve.array.access.index.p0a4a4i32.p0a4a4a4i32([4 x [4 x [4 x i32]]]* elementtype([4 x [4 x [4 x i32]]]) %1, i32 1, i32 2), !dbg !29, !llvm.preserve.access.index !11 + %3 = tail call [4 x i32]* @llvm.preserve.array.access.index.p0a4i32.p0a4a4i32([4 x [4 x i32]]* elementtype([4 x [4 x i32]]) %2, i32 1, i32 3), !dbg !29, !llvm.preserve.access.index !15 + %4 = tail call i32* @llvm.preserve.array.access.index.p0i32.p0a4i32([4 x i32]* elementtype([4 x i32]) %3, i32 1, i32 2), !dbg !29, !llvm.preserve.access.index !17 + %call = tail call i32 @get_value(i32* %4) #4, !dbg !30 + ret i32 %call, !dbg !31 +} + +; CHECK: mov64 r2, 448 +; CHECK: add64 r1, r2 +; CHECK: call get_value + +; CHECK: .long 6 # BTF_KIND_STRUCT(id = [[TID1:[0-9]+]]) + +; CHECK: .ascii "v3" # string offset=6 +; CHECK: .ascii ".text" # string offset=52 +; CHECK: .ascii "1:1:2:3:2" # string offset=58 + +; CHECK: .long 16 # FieldReloc +; CHECK-NEXT: .long 52 # Field reloc section string offset=52 +; CHECK-NEXT: .long 1 +; CHECK-NEXT: .long .Ltmp{{[0-9]+}} +; CHECK-NEXT: .long [[TID1]] +; CHECK-NEXT: .long 58 +; CHECK-NEXT: .long 0 + +declare dso_local i32 @get_value(i32*) local_unnamed_addr #1 + +; Function Attrs: nounwind readnone +declare %struct.v3* @llvm.preserve.array.access.index.p0s_struct.v3s.p0s_struct.v3s(%struct.v3*, i32, i32) #2 + +; Function Attrs: nounwind readnone +declare [4 x [4 x [4 x i32]]]* @llvm.preserve.struct.access.index.p0a4a4a4i32.p0s_struct.v3s(%struct.v3*, i32, i32) #2 + +; Function Attrs: nounwind readnone +declare [4 x [4 x i32]]* @llvm.preserve.array.access.index.p0a4a4i32.p0a4a4a4i32([4 x [4 x [4 x i32]]]*, i32, i32) #2 + +; Function Attrs: nounwind readnone +declare [4 x i32]* @llvm.preserve.array.access.index.p0a4i32.p0a4a4i32([4 x [4 x i32]]*, i32, i32) #2 + +; Function Attrs: nounwind readnone +declare i32* @llvm.preserve.array.access.index.p0i32.p0a4i32([4 x i32]*, i32, i32) #2 + +; Function Attrs: nounwind readnone speculatable willreturn +declare void @llvm.dbg.value(metadata, metadata, metadata) #3 + +attributes #0 = { nounwind "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" } +attributes #1 = { "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" } +attributes #2 = { nounwind readnone } +attributes #3 = { nounwind readnone speculatable willreturn } +attributes #4 = { nounwind } + +!llvm.dbg.cu = !{!0} +!llvm.module.flags = !{!19, !20, !21} +!llvm.ident = !{!22} + +!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 10.0.0 (trunk 367256) (llvm/trunk 367266)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, retainedTypes: !3, nameTableKind: None) +!1 = !DIFile(filename: "test.c", directory: "/tmp/home/yhs/work/tests/llvm/cast") +!2 = !{} +!3 = !{!4, !11, !15, !17} +!4 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !5, size: 64) +!5 = !DIDerivedType(tag: DW_TAG_typedef, name: "__v3", file: !1, line: 2, baseType: !6) +!6 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "v3", file: !1, line: 2, size: 2080, elements: !7) +!7 = !{!8, !10} +!8 = !DIDerivedType(tag: DW_TAG_member, name: "a", scope: !6, file: !1, line: 2, baseType: !9, size: 32) +!9 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +!10 = !DIDerivedType(tag: DW_TAG_member, name: "b", scope: !6, file: !1, line: 2, baseType: !11, size: 2048, offset: 32) +!11 = !DICompositeType(tag: DW_TAG_array_type, baseType: !12, size: 2048, elements: !13) +!12 = !DIDerivedType(tag: DW_TAG_typedef, name: "__int", file: !1, line: 1, baseType: !9) +!13 = !{!14, !14, !14} +!14 = !DISubrange(count: 4) +!15 = !DICompositeType(tag: DW_TAG_array_type, baseType: !12, size: 512, elements: !16) +!16 = !{!14, !14} +!17 = !DICompositeType(tag: DW_TAG_array_type, baseType: !12, size: 128, elements: !18) +!18 = !{!14} +!19 = !{i32 2, !"Dwarf Version", i32 4} +!20 = !{i32 2, !"Debug Info Version", i32 3} +!21 = !{i32 1, !"wchar_size", i32 4} +!22 = !{!"clang version 10.0.0 (trunk 367256) (llvm/trunk 367266)"} +!23 = distinct !DISubprogram(name: "test", scope: !1, file: !1, line: 5, type: !24, scopeLine: 5, flags: DIFlagPrototyped, isDefinition: true, isOptimized: true, unit: !0, retainedNodes: !26) +!24 = !DISubroutineType(types: !25) +!25 = !{!9, !4} +!26 = !{!27} +!27 = !DILocalVariable(name: "arg", arg: 1, scope: !23, file: !1, line: 5, type: !4) +!28 = !DILocation(line: 0, scope: !23) +!29 = !DILocation(line: 6, column: 20, scope: !23) +!30 = !DILocation(line: 6, column: 10, scope: !23) +!31 = !DILocation(line: 6, column: 3, scope: !23) diff --git a/llvm/test/CodeGen/SBF/CORE/offset-reloc-multilevel.ll b/llvm/test/CodeGen/SBF/CORE/offset-reloc-multilevel.ll new file mode 100644 index 0000000000000..76cec1b359744 --- /dev/null +++ b/llvm/test/CodeGen/SBF/CORE/offset-reloc-multilevel.ll @@ -0,0 +1,199 @@ +; RUN: opt -O2 %s | llvm-dis > %t1 +; RUN: llc -sbf-enable-btf-emission -filetype=asm -o - %t1 | FileCheck -check-prefixes=CHECK %s +; RUN: llc -sbf-enable-btf-emission -mattr=+alu32 -filetype=asm -o - %t1 | FileCheck -check-prefixes=CHECK %s +; Source code: +; struct net_device { +; int dev_id; +; int others; +; }; +; struct sk_buff { +; int i; +; struct net_device dev; +; }; +; #define _(x) (__builtin_preserve_access_index(x)) +; static int (*bpf_probe_read)(void *dst, int size, void *unsafe_ptr) +; = (void *) 4; +; +; int bpf_prog(struct sk_buff *ctx) { +; int dev_id; +; bpf_probe_read(&dev_id, sizeof(int), _(&ctx->dev.dev_id)); +; return dev_id; +; } +; Compilation flag: +; clang -target bpf -O2 -g -S -emit-llvm -Xclang -disable-llvm-passes test.c + +target triple = "sbf" + +%struct.sk_buff = type { i32, %struct.net_device } +%struct.net_device = type { i32, i32 } + +; Function Attrs: nounwind +define dso_local i32 @bpf_prog(%struct.sk_buff*) local_unnamed_addr #0 !dbg !15 { + %2 = alloca i32, align 4 + call void @llvm.dbg.value(metadata %struct.sk_buff* %0, metadata !28, metadata !DIExpression()), !dbg !30 + %3 = bitcast i32* %2 to i8*, !dbg !31 + call void @llvm.lifetime.start.p0i8(i64 4, i8* nonnull %3) #4, !dbg !31 + %4 = tail call %struct.net_device* @llvm.preserve.struct.access.index.p0s_struct.net_devices.p0s_struct.sk_buffs(%struct.sk_buff* elementtype(%struct.sk_buff) %0, i32 1, i32 1), !dbg !32, !llvm.preserve.access.index !19 + %5 = tail call i32* @llvm.preserve.struct.access.index.p0i32.p0s_struct.net_devices(%struct.net_device* elementtype(%struct.net_device) %4, i32 0, i32 0), !dbg !32, !llvm.preserve.access.index !23 + %6 = bitcast i32* %5 to i8*, !dbg !32 + %7 = call i32 inttoptr (i64 4 to i32 (i8*, i32, i8*)*)(i8* nonnull %3, i32 4, i8* %6) #4, !dbg !33 + %8 = load i32, i32* %2, align 4, !dbg !34, !tbaa !35 + call void @llvm.dbg.value(metadata i32 %8, metadata !29, metadata !DIExpression()), !dbg !30 + call void @llvm.lifetime.end.p0i8(i64 4, i8* nonnull %3) #4, !dbg !39 + ret i32 %8, !dbg !40 +} + +; CHECK: .section .BTF,"",@progbits +; CHECK-NEXT: .short 60319 # 0xeb9f +; CHECK-NEXT: .byte 1 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .long 24 +; CHECK-NEXT: .long 0 +; CHECK-NEXT: .long 132 +; CHECK-NEXT: .long 132 +; CHECK-NEXT: .long 106 +; CHECK-NEXT: .long 0 # BTF_KIND_PTR(id = 1) +; CHECK-NEXT: .long 33554432 # 0x2000000 +; CHECK-NEXT: .long 2 +; CHECK-NEXT: .long 1 # BTF_KIND_STRUCT(id = 2) +; CHECK-NEXT: .long 67108866 # 0x4000002 +; CHECK-NEXT: .long 12 +; CHECK-NEXT: .long 9 +; CHECK-NEXT: .long 3 +; CHECK-NEXT: .long 0 # 0x0 +; CHECK-NEXT: .long 11 +; CHECK-NEXT: .long 4 +; CHECK-NEXT: .long 32 # 0x20 +; CHECK-NEXT: .long 15 # BTF_KIND_INT(id = 3) +; CHECK-NEXT: .long 16777216 # 0x1000000 +; CHECK-NEXT: .long 4 +; CHECK-NEXT: .long 16777248 # 0x1000020 +; CHECK-NEXT: .long 19 # BTF_KIND_STRUCT(id = 4) +; CHECK-NEXT: .long 67108866 # 0x4000002 +; CHECK-NEXT: .long 8 +; CHECK-NEXT: .long 30 +; CHECK-NEXT: .long 3 +; CHECK-NEXT: .long 0 # 0x0 +; CHECK-NEXT: .long 37 +; CHECK-NEXT: .long 3 +; CHECK-NEXT: .long 32 # 0x20 +; CHECK-NEXT: .long 0 # BTF_KIND_FUNC_PROTO(id = 5) +; CHECK-NEXT: .long 218103809 # 0xd000001 +; CHECK-NEXT: .long 3 +; CHECK-NEXT: .long 44 +; CHECK-NEXT: .long 1 +; CHECK-NEXT: .long 48 # BTF_KIND_FUNC(id = 6) +; CHECK-NEXT: .long 201326593 # 0xc000001 +; CHECK-NEXT: .long 5 +; CHECK-NEXT: .byte 0 # string offset=0 +; CHECK-NEXT: .ascii "sk_buff" # string offset=1 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .byte 105 # string offset=9 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii "dev" # string offset=11 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii "int" # string offset=15 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii "net_device" # string offset=19 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii "dev_id" # string offset=30 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii "others" # string offset=37 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii "ctx" # string offset=44 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii "bpf_prog" # string offset=48 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii ".text" # string offset=57 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii "/tmp/home/yhs/work/tests/llvm/test.c" # string offset=63 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii "0:1:0" # string offset=100 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .section .BTF.ext,"",@progbits +; CHECK-NEXT: .short 60319 # 0xeb9f +; CHECK-NEXT: .byte 1 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .long 32 +; CHECK-NEXT: .long 0 +; CHECK-NEXT: .long 20 +; CHECK-NEXT: .long 20 +; CHECK-NEXT: .long {{[0-9]+}} +; CHECK-NEXT: .long {{[0-9]+}} +; CHECK-NEXT: .long 28 +; CHECK-NEXT: .long 8 # FuncInfo + +; CHECK: .long 16 # FieldReloc +; CHECK-NEXT: .long 57 # Field reloc section string offset=57 +; CHECK-NEXT: .long 1 +; CHECK-NEXT: .long .Ltmp{{[0-9]+}} +; CHECK-NEXT: .long 2 +; CHECK-NEXT: .long 100 +; CHECK-NEXT: .long 0 + +; Function Attrs: argmemonly nounwind +declare void @llvm.lifetime.start.p0i8(i64 immarg, i8* nocapture) #1 + +; Function Attrs: nounwind readnone +declare %struct.net_device* @llvm.preserve.struct.access.index.p0s_struct.net_devices.p0s_struct.sk_buffs(%struct.sk_buff*, i32 immarg, i32 immarg) #2 + +; Function Attrs: nounwind readnone +declare i32* @llvm.preserve.struct.access.index.p0i32.p0s_struct.net_devices(%struct.net_device*, i32 immarg, i32 immarg) #2 + +; Function Attrs: argmemonly nounwind +declare void @llvm.lifetime.end.p0i8(i64 immarg, i8* nocapture) #1 + +; Function Attrs: nounwind readnone speculatable +declare void @llvm.dbg.value(metadata, metadata, metadata) #3 + +attributes #0 = { nounwind "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "frame-pointer"="all" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" } +attributes #1 = { argmemonly nounwind } +attributes #2 = { nounwind readnone } +attributes #3 = { nounwind readnone speculatable } +attributes #4 = { nounwind } + +!llvm.dbg.cu = !{!0} +!llvm.module.flags = !{!11, !12, !13} +!llvm.ident = !{!14} + +!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 9.0.0 (trunk 360739) (llvm/trunk 360747)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, globals: !3, nameTableKind: None) +!1 = !DIFile(filename: "test.c", directory: "/tmp/home/yhs/work/tests/llvm") +!2 = !{} +!3 = !{!4} +!4 = !DIGlobalVariableExpression(var: !5, expr: !DIExpression()) +!5 = distinct !DIGlobalVariable(name: "bpf_probe_read", scope: !0, file: !1, line: 10, type: !6, isLocal: true, isDefinition: true) +!6 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !7, size: 64) +!7 = !DISubroutineType(types: !8) +!8 = !{!9, !10, !9, !10} +!9 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +!10 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: null, size: 64) +!11 = !{i32 2, !"Dwarf Version", i32 4} +!12 = !{i32 2, !"Debug Info Version", i32 3} +!13 = !{i32 1, !"wchar_size", i32 4} +!14 = !{!"clang version 9.0.0 (trunk 360739) (llvm/trunk 360747)"} +!15 = distinct !DISubprogram(name: "bpf_prog", scope: !1, file: !1, line: 13, type: !16, scopeLine: 13, flags: DIFlagPrototyped, isLocal: false, isDefinition: true, isOptimized: true, unit: !0, retainedNodes: !27) +!16 = !DISubroutineType(types: !17) +!17 = !{!9, !18} +!18 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !19, size: 64) +!19 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "sk_buff", file: !1, line: 5, size: 96, elements: !20) +!20 = !{!21, !22} +!21 = !DIDerivedType(tag: DW_TAG_member, name: "i", scope: !19, file: !1, line: 6, baseType: !9, size: 32) +!22 = !DIDerivedType(tag: DW_TAG_member, name: "dev", scope: !19, file: !1, line: 7, baseType: !23, size: 64, offset: 32) +!23 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "net_device", file: !1, line: 1, size: 64, elements: !24) +!24 = !{!25, !26} +!25 = !DIDerivedType(tag: DW_TAG_member, name: "dev_id", scope: !23, file: !1, line: 2, baseType: !9, size: 32) +!26 = !DIDerivedType(tag: DW_TAG_member, name: "others", scope: !23, file: !1, line: 3, baseType: !9, size: 32, offset: 32) +!27 = !{!28, !29} +!28 = !DILocalVariable(name: "ctx", arg: 1, scope: !15, file: !1, line: 13, type: !18) +!29 = !DILocalVariable(name: "dev_id", scope: !15, file: !1, line: 14, type: !9) +!30 = !DILocation(line: 0, scope: !15) +!31 = !DILocation(line: 14, column: 3, scope: !15) +!32 = !DILocation(line: 15, column: 40, scope: !15) +!33 = !DILocation(line: 15, column: 3, scope: !15) +!34 = !DILocation(line: 16, column: 10, scope: !15) +!35 = !{!36, !36, i64 0} +!36 = !{!"int", !37, i64 0} +!37 = !{!"omnipotent char", !38, i64 0} +!38 = !{!"Simple C/C++ TBAA"} +!39 = !DILocation(line: 17, column: 1, scope: !15) +!40 = !DILocation(line: 16, column: 3, scope: !15) diff --git a/llvm/test/CodeGen/SBF/CORE/offset-reloc-pointer-1.ll b/llvm/test/CodeGen/SBF/CORE/offset-reloc-pointer-1.ll new file mode 100644 index 0000000000000..0ce6ed8b1912e --- /dev/null +++ b/llvm/test/CodeGen/SBF/CORE/offset-reloc-pointer-1.ll @@ -0,0 +1,87 @@ +; RUN: opt -O2 %s | llvm-dis > %t1 +; RUN: llc -sbf-enable-btf-emission -filetype=asm -o - %t1 | FileCheck -check-prefixes=CHECK %s +; RUN: llc -sbf-enable-btf-emission -mattr=+alu32 -filetype=asm -o - %t1 | FileCheck -check-prefixes=CHECK %s +; Source code: +; typedef struct v3 { int a; int b; } __v3; +; #define _(x) (__builtin_preserve_access_index(x)) +; int get_value(const int *arg); +; int test(__v3 *arg) { +; return get_value(_(&arg[1])); +; } +; Compilation flag: +; clang -target bpf -O2 -g -S -emit-llvm -Xclang -disable-llvm-passes test.c + +target triple = "sbf" + +%struct.v3 = type { i32, i32 } + +; Function Attrs: nounwind +define dso_local i32 @test(%struct.v3* %arg) local_unnamed_addr #0 !dbg !15 { +entry: + call void @llvm.dbg.value(metadata %struct.v3* %arg, metadata !19, metadata !DIExpression()), !dbg !20 + %0 = tail call %struct.v3* @llvm.preserve.array.access.index.p0s_struct.v3s.p0s_struct.v3s(%struct.v3* elementtype(%struct.v3) %arg, i32 0, i32 1), !dbg !21, !llvm.preserve.access.index !4 + %1 = getelementptr inbounds %struct.v3, %struct.v3* %0, i64 0, i32 0, !dbg !21 + %call = tail call i32 @get_value(i32* %1) #4, !dbg !22 + ret i32 %call, !dbg !23 +} + +; CHECK: mov64 r2, 8 +; CHECK: add64 r1, r2 +; CHECK: call get_value + +; CHECK: .long 6 # BTF_KIND_STRUCT(id = [[TID1:[0-9]+]]) + +; CHECK: .ascii "v3" # string offset=6 +; CHECK: .ascii ".text" # string offset=26 +; CHECK: .byte 49 # string offset=32 + +; CHECK: .long 16 # FieldReloc +; CHECK-NEXT: .long 26 # Field reloc section string offset=26 +; CHECK-NEXT: .long 1 +; CHECK-NEXT: .long .Ltmp{{[0-9]+}} +; CHECK-NEXT: .long [[TID1]] +; CHECK-NEXT: .long 32 +; CHECK-NEXT: .long 0 + +declare dso_local i32 @get_value(i32*) local_unnamed_addr #1 + +; Function Attrs: nounwind readnone +declare %struct.v3* @llvm.preserve.array.access.index.p0s_struct.v3s.p0s_struct.v3s(%struct.v3*, i32, i32) #2 + +; Function Attrs: nounwind readnone speculatable willreturn +declare void @llvm.dbg.value(metadata, metadata, metadata) #3 + +attributes #0 = { nounwind "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" } +attributes #1 = { "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" } +attributes #2 = { nounwind readnone } +attributes #3 = { nounwind readnone speculatable willreturn } +attributes #4 = { nounwind } + +!llvm.dbg.cu = !{!0} +!llvm.module.flags = !{!11, !12, !13} +!llvm.ident = !{!14} + +!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 10.0.0 (trunk 367256) (llvm/trunk 367266)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, retainedTypes: !3, nameTableKind: None) +!1 = !DIFile(filename: "test.c", directory: "/tmp/home/yhs/work/tests/llvm/cast") +!2 = !{} +!3 = !{!4} +!4 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !5, size: 64) +!5 = !DIDerivedType(tag: DW_TAG_typedef, name: "__v3", file: !1, line: 1, baseType: !6) +!6 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "v3", file: !1, line: 1, size: 64, elements: !7) +!7 = !{!8, !10} +!8 = !DIDerivedType(tag: DW_TAG_member, name: "a", scope: !6, file: !1, line: 1, baseType: !9, size: 32) +!9 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +!10 = !DIDerivedType(tag: DW_TAG_member, name: "b", scope: !6, file: !1, line: 1, baseType: !9, size: 32, offset: 32) +!11 = !{i32 2, !"Dwarf Version", i32 4} +!12 = !{i32 2, !"Debug Info Version", i32 3} +!13 = !{i32 1, !"wchar_size", i32 4} +!14 = !{!"clang version 10.0.0 (trunk 367256) (llvm/trunk 367266)"} +!15 = distinct !DISubprogram(name: "test", scope: !1, file: !1, line: 4, type: !16, scopeLine: 4, flags: DIFlagPrototyped, isDefinition: true, isOptimized: true, unit: !0, retainedNodes: !18) +!16 = !DISubroutineType(types: !17) +!17 = !{!9, !4} +!18 = !{!19} +!19 = !DILocalVariable(name: "arg", arg: 1, scope: !15, file: !1, line: 4, type: !4) +!20 = !DILocation(line: 0, scope: !15) +!21 = !DILocation(line: 5, column: 20, scope: !15) +!22 = !DILocation(line: 5, column: 10, scope: !15) +!23 = !DILocation(line: 5, column: 3, scope: !15) diff --git a/llvm/test/CodeGen/SBF/CORE/offset-reloc-pointer-2.ll b/llvm/test/CodeGen/SBF/CORE/offset-reloc-pointer-2.ll new file mode 100644 index 0000000000000..c401fe8d311e0 --- /dev/null +++ b/llvm/test/CodeGen/SBF/CORE/offset-reloc-pointer-2.ll @@ -0,0 +1,89 @@ +; RUN: opt -O2 %s | llvm-dis > %t1 +; RUN: llc -sbf-enable-btf-emission -filetype=asm -o - %t1 | FileCheck -check-prefixes=CHECK %s +; RUN: llc -sbf-enable-btf-emission -mattr=+alu32 -filetype=asm -o - %t1 | FileCheck -check-prefixes=CHECK %s +; Source code: +; typedef struct v3 { int a; int b; } __v3; +; #define _(x) (__builtin_preserve_access_index(x)) +; int get_value(const int *arg); +; int test(__v3 *arg) { +; return get_value(_(&arg[1].b)); +; } +; Compilation flag: +; clang -target bpf -O2 -g -S -emit-llvm -Xclang -disable-llvm-passes test.c + +target triple = "sbf" + +%struct.v3 = type { i32, i32 } + +; Function Attrs: nounwind +define dso_local i32 @test(%struct.v3* %arg) local_unnamed_addr #0 !dbg !15 { +entry: + call void @llvm.dbg.value(metadata %struct.v3* %arg, metadata !19, metadata !DIExpression()), !dbg !20 + %0 = tail call %struct.v3* @llvm.preserve.array.access.index.p0s_struct.v3s.p0s_struct.v3s(%struct.v3* elementtype(%struct.v3) %arg, i32 0, i32 1), !dbg !21, !llvm.preserve.access.index !4 + %1 = tail call i32* @llvm.preserve.struct.access.index.p0i32.p0s_struct.v3s(%struct.v3* elementtype(%struct.v3) %0, i32 1, i32 1), !dbg !21, !llvm.preserve.access.index !6 + %call = tail call i32 @get_value(i32* %1) #4, !dbg !22 + ret i32 %call, !dbg !23 +} + +; CHECK: mov64 r2, 12 +; CHECK-NEXT: add64 r1, r2 +; CHECK: call get_value + +; CHECK: .long 6 # BTF_KIND_STRUCT(id = [[TID1:[0-9]+]]) +; CHECK: .ascii "v3" # string offset=6 +; CHECK: .ascii ".text" # string offset=26 +; CHECK: .ascii "1:1" # string offset=32 + +; CHECK: .long 16 # FieldReloc +; CHECK-NEXT: .long 26 # Field reloc section string offset=26 +; CHECK-NEXT: .long 1 +; CHECK-NEXT: .long .Ltmp{{[0-9]+}} +; CHECK-NEXT: .long [[TID1]] +; CHECK-NEXT: .long 32 +; CHECK-NEXT: .long 0 + +declare dso_local i32 @get_value(i32*) local_unnamed_addr #1 + +; Function Attrs: nounwind readnone +declare %struct.v3* @llvm.preserve.array.access.index.p0s_struct.v3s.p0s_struct.v3s(%struct.v3*, i32, i32) #2 + +; Function Attrs: nounwind readnone +declare i32* @llvm.preserve.struct.access.index.p0i32.p0s_struct.v3s(%struct.v3*, i32, i32) #2 + +; Function Attrs: nounwind readnone speculatable willreturn +declare void @llvm.dbg.value(metadata, metadata, metadata) #3 + +attributes #0 = { nounwind "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" } +attributes #1 = { "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" } +attributes #2 = { nounwind readnone } +attributes #3 = { nounwind readnone speculatable willreturn } +attributes #4 = { nounwind } + +!llvm.dbg.cu = !{!0} +!llvm.module.flags = !{!11, !12, !13} +!llvm.ident = !{!14} + +!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 10.0.0 (trunk 367256) (llvm/trunk 367266)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, retainedTypes: !3, nameTableKind: None) +!1 = !DIFile(filename: "test.c", directory: "/tmp/home/yhs/work/tests/llvm/cast") +!2 = !{} +!3 = !{!4} +!4 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !5, size: 64) +!5 = !DIDerivedType(tag: DW_TAG_typedef, name: "__v3", file: !1, line: 1, baseType: !6) +!6 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "v3", file: !1, line: 1, size: 64, elements: !7) +!7 = !{!8, !10} +!8 = !DIDerivedType(tag: DW_TAG_member, name: "a", scope: !6, file: !1, line: 1, baseType: !9, size: 32) +!9 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +!10 = !DIDerivedType(tag: DW_TAG_member, name: "b", scope: !6, file: !1, line: 1, baseType: !9, size: 32, offset: 32) +!11 = !{i32 2, !"Dwarf Version", i32 4} +!12 = !{i32 2, !"Debug Info Version", i32 3} +!13 = !{i32 1, !"wchar_size", i32 4} +!14 = !{!"clang version 10.0.0 (trunk 367256) (llvm/trunk 367266)"} +!15 = distinct !DISubprogram(name: "test", scope: !1, file: !1, line: 4, type: !16, scopeLine: 4, flags: DIFlagPrototyped, isDefinition: true, isOptimized: true, unit: !0, retainedNodes: !18) +!16 = !DISubroutineType(types: !17) +!17 = !{!9, !4} +!18 = !{!19} +!19 = !DILocalVariable(name: "arg", arg: 1, scope: !15, file: !1, line: 4, type: !4) +!20 = !DILocation(line: 0, scope: !15) +!21 = !DILocation(line: 5, column: 20, scope: !15) +!22 = !DILocation(line: 5, column: 10, scope: !15) +!23 = !DILocation(line: 5, column: 3, scope: !15) diff --git a/llvm/test/CodeGen/SBF/CORE/offset-reloc-struct-anonymous.ll b/llvm/test/CodeGen/SBF/CORE/offset-reloc-struct-anonymous.ll new file mode 100644 index 0000000000000..d038194589161 --- /dev/null +++ b/llvm/test/CodeGen/SBF/CORE/offset-reloc-struct-anonymous.ll @@ -0,0 +1,215 @@ +; RUN: opt -O2 %s | llvm-dis > %t1 +; RUN: llc -sbf-enable-btf-emission -filetype=asm -o - %t1 | FileCheck -check-prefixes=CHECK %s +; RUN: llc -sbf-enable-btf-emission -mattr=+alu32 -filetype=asm -o - %t1 | FileCheck -check-prefixes=CHECK %s +; Source code: +; struct sk_buff { +; int i; +; struct { +; int dev_id; +; int others; +; } dev[10]; +; }; +; #define _(x) (__builtin_preserve_access_index(x)) +; static int (*bpf_probe_read)(void *dst, int size, void *unsafe_ptr) +; = (void *) 4; +; +; int bpf_prog(struct sk_buff *ctx) { +; int dev_id; +; bpf_probe_read(&dev_id, sizeof(int), _(&ctx->dev[5].dev_id)); +; return dev_id; +; } +; Compilation flag: +; clang -target bpf -O2 -g -S -emit-llvm -Xclang -disable-llvm-passes test.c + +target triple = "sbf" + +%struct.sk_buff = type { i32, [10 x %struct.anon] } +%struct.anon = type { i32, i32 } + +; Function Attrs: nounwind +define dso_local i32 @bpf_prog(%struct.sk_buff*) local_unnamed_addr #0 !dbg !15 { + %2 = alloca i32, align 4 + call void @llvm.dbg.value(metadata %struct.sk_buff* %0, metadata !31, metadata !DIExpression()), !dbg !33 + %3 = bitcast i32* %2 to i8*, !dbg !34 + call void @llvm.lifetime.start.p0i8(i64 4, i8* nonnull %3) #4, !dbg !34 + %4 = tail call [10 x %struct.anon]* @llvm.preserve.struct.access.index.p0a10s_struct.anons.p0s_struct.sk_buffs(%struct.sk_buff* elementtype(%struct.sk_buff) %0, i32 1, i32 1), !dbg !35, !llvm.preserve.access.index !19 + %5 = tail call %struct.anon* @llvm.preserve.array.access.index.p0s_struct.anons.p0a10s_struct.anons([10 x %struct.anon]* elementtype([10 x %struct.anon]) %4, i32 1, i32 5), !dbg !35, !llvm.preserve.access.index !23 + %6 = tail call i32* @llvm.preserve.struct.access.index.p0i32.p0s_struct.anons(%struct.anon* elementtype(%struct.anon) %5, i32 0, i32 0), !dbg !35, !llvm.preserve.access.index !24 + %7 = bitcast i32* %6 to i8*, !dbg !35 + %8 = call i32 inttoptr (i64 4 to i32 (i8*, i32, i8*)*)(i8* nonnull %3, i32 4, i8* %7) #4, !dbg !36 + %9 = load i32, i32* %2, align 4, !dbg !37, !tbaa !38 + call void @llvm.dbg.value(metadata i32 %9, metadata !32, metadata !DIExpression()), !dbg !33 + call void @llvm.lifetime.end.p0i8(i64 4, i8* nonnull %3) #4, !dbg !42 + ret i32 %9, !dbg !43 +} + +; CHECK: .section .BTF,"",@progbits +; CHECK-NEXT: .short 60319 # 0xeb9f +; CHECK-NEXT: .byte 1 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .long 24 +; CHECK-NEXT: .long 0 +; CHECK-NEXT: .long 172 +; CHECK-NEXT: .long 172 +; CHECK-NEXT: .long 117 +; CHECK-NEXT: .long 0 # BTF_KIND_PTR(id = 1) +; CHECK-NEXT: .long 33554432 # 0x2000000 +; CHECK-NEXT: .long 2 +; CHECK-NEXT: .long 1 # BTF_KIND_STRUCT(id = 2) +; CHECK-NEXT: .long 67108866 # 0x4000002 +; CHECK-NEXT: .long 84 +; CHECK-NEXT: .long 9 +; CHECK-NEXT: .long 3 +; CHECK-NEXT: .long 0 # 0x0 +; CHECK-NEXT: .long 11 +; CHECK-NEXT: .long 5 +; CHECK-NEXT: .long 32 # 0x20 +; CHECK-NEXT: .long 15 # BTF_KIND_INT(id = 3) +; CHECK-NEXT: .long 16777216 # 0x1000000 +; CHECK-NEXT: .long 4 +; CHECK-NEXT: .long 16777248 # 0x1000020 +; CHECK-NEXT: .long 0 # BTF_KIND_STRUCT(id = 4) +; CHECK-NEXT: .long 67108866 # 0x4000002 +; CHECK-NEXT: .long 8 +; CHECK-NEXT: .long 19 +; CHECK-NEXT: .long 3 +; CHECK-NEXT: .long 0 # 0x0 +; CHECK-NEXT: .long 26 +; CHECK-NEXT: .long 3 +; CHECK-NEXT: .long 32 # 0x20 +; CHECK-NEXT: .long 0 # BTF_KIND_ARRAY(id = 5) +; CHECK-NEXT: .long 50331648 # 0x3000000 +; CHECK-NEXT: .long 0 +; CHECK-NEXT: .long 4 +; CHECK-NEXT: .long 6 +; CHECK-NEXT: .long 10 +; CHECK-NEXT: .long 33 # BTF_KIND_INT(id = 6) +; CHECK-NEXT: .long 16777216 # 0x1000000 +; CHECK-NEXT: .long 4 +; CHECK-NEXT: .long 32 # 0x20 +; CHECK-NEXT: .long 0 # BTF_KIND_FUNC_PROTO(id = 7) +; CHECK-NEXT: .long 218103809 # 0xd000001 +; CHECK-NEXT: .long 3 +; CHECK-NEXT: .long 53 +; CHECK-NEXT: .long 1 +; CHECK-NEXT: .long 57 # BTF_KIND_FUNC(id = 8) +; CHECK-NEXT: .long 201326593 # 0xc000001 +; CHECK-NEXT: .long 7 +; CHECK-NEXT: .byte 0 # string offset=0 +; CHECK-NEXT: .ascii "sk_buff" # string offset=1 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .byte 105 # string offset=9 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii "dev" # string offset=11 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii "int" # string offset=15 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii "dev_id" # string offset=19 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii "others" # string offset=26 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii "__ARRAY_SIZE_TYPE__" # string offset=33 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii "ctx" # string offset=53 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii "bpf_prog" # string offset=57 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii ".text" # string offset=66 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii "/tmp/home/yhs/work/tests/llvm/test.c" # string offset=72 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii "0:1:5:0" # string offset=109 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .section .BTF.ext,"",@progbits +; CHECK-NEXT: .short 60319 # 0xeb9f +; CHECK-NEXT: .byte 1 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .long 32 +; CHECK-NEXT: .long 0 +; CHECK-NEXT: .long 20 +; CHECK-NEXT: .long 20 +; CHECK-NEXT: .long {{[0-9]+}} +; CHECK-NEXT: .long {{[0-9]+}} +; CHECK-NEXT: .long 28 +; CHECK-NEXT: .long 8 # FuncInfo + +; CHECK: .long 16 # FieldReloc +; CHECK-NEXT: .long 66 # Field reloc section string offset=66 +; CHECK-NEXT: .long 1 +; CHECK-NEXT: .long .Ltmp{{[0-9]+}} +; CHECK-NEXT: .long 2 +; CHECK-NEXT: .long 109 +; CHECK-NEXT: .long 0 + +; Function Attrs: argmemonly nounwind +declare void @llvm.lifetime.start.p0i8(i64 immarg, i8* nocapture) #1 + +; Function Attrs: nounwind readnone +declare [10 x %struct.anon]* @llvm.preserve.struct.access.index.p0a10s_struct.anons.p0s_struct.sk_buffs(%struct.sk_buff*, i32 immarg, i32 immarg) #2 + +; Function Attrs: nounwind readnone +declare %struct.anon* @llvm.preserve.array.access.index.p0s_struct.anons.p0a10s_struct.anons([10 x %struct.anon]*, i32 immarg, i32 immarg) #2 + +; Function Attrs: nounwind readnone +declare i32* @llvm.preserve.struct.access.index.p0i32.p0s_struct.anons(%struct.anon*, i32 immarg, i32 immarg) #2 + +; Function Attrs: argmemonly nounwind +declare void @llvm.lifetime.end.p0i8(i64 immarg, i8* nocapture) #1 + +; Function Attrs: nounwind readnone speculatable +declare void @llvm.dbg.value(metadata, metadata, metadata) #3 + +attributes #0 = { nounwind "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "frame-pointer"="all" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" } +attributes #1 = { argmemonly nounwind } +attributes #2 = { nounwind readnone } +attributes #3 = { nounwind readnone speculatable } +attributes #4 = { nounwind } + +!llvm.dbg.cu = !{!0} +!llvm.module.flags = !{!11, !12, !13} +!llvm.ident = !{!14} + +!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 9.0.0 (trunk 360739) (llvm/trunk 360747)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, globals: !3, nameTableKind: None) +!1 = !DIFile(filename: "test.c", directory: "/tmp/home/yhs/work/tests/llvm") +!2 = !{} +!3 = !{!4} +!4 = !DIGlobalVariableExpression(var: !5, expr: !DIExpression()) +!5 = distinct !DIGlobalVariable(name: "bpf_probe_read", scope: !0, file: !1, line: 9, type: !6, isLocal: true, isDefinition: true) +!6 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !7, size: 64) +!7 = !DISubroutineType(types: !8) +!8 = !{!9, !10, !9, !10} +!9 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +!10 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: null, size: 64) +!11 = !{i32 2, !"Dwarf Version", i32 4} +!12 = !{i32 2, !"Debug Info Version", i32 3} +!13 = !{i32 1, !"wchar_size", i32 4} +!14 = !{!"clang version 9.0.0 (trunk 360739) (llvm/trunk 360747)"} +!15 = distinct !DISubprogram(name: "bpf_prog", scope: !1, file: !1, line: 12, type: !16, scopeLine: 12, flags: DIFlagPrototyped, isLocal: false, isDefinition: true, isOptimized: true, unit: !0, retainedNodes: !30) +!16 = !DISubroutineType(types: !17) +!17 = !{!9, !18} +!18 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !19, size: 64) +!19 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "sk_buff", file: !1, line: 1, size: 672, elements: !20) +!20 = !{!21, !22} +!21 = !DIDerivedType(tag: DW_TAG_member, name: "i", scope: !19, file: !1, line: 2, baseType: !9, size: 32) +!22 = !DIDerivedType(tag: DW_TAG_member, name: "dev", scope: !19, file: !1, line: 6, baseType: !23, size: 640, offset: 32) +!23 = !DICompositeType(tag: DW_TAG_array_type, baseType: !24, size: 640, elements: !28) +!24 = distinct !DICompositeType(tag: DW_TAG_structure_type, scope: !19, file: !1, line: 3, size: 64, elements: !25) +!25 = !{!26, !27} +!26 = !DIDerivedType(tag: DW_TAG_member, name: "dev_id", scope: !24, file: !1, line: 4, baseType: !9, size: 32) +!27 = !DIDerivedType(tag: DW_TAG_member, name: "others", scope: !24, file: !1, line: 5, baseType: !9, size: 32, offset: 32) +!28 = !{!29} +!29 = !DISubrange(count: 10) +!30 = !{!31, !32} +!31 = !DILocalVariable(name: "ctx", arg: 1, scope: !15, file: !1, line: 12, type: !18) +!32 = !DILocalVariable(name: "dev_id", scope: !15, file: !1, line: 13, type: !9) +!33 = !DILocation(line: 0, scope: !15) +!34 = !DILocation(line: 13, column: 3, scope: !15) +!35 = !DILocation(line: 14, column: 40, scope: !15) +!36 = !DILocation(line: 14, column: 3, scope: !15) +!37 = !DILocation(line: 15, column: 10, scope: !15) +!38 = !{!39, !39, i64 0} +!39 = !{!"int", !40, i64 0} +!40 = !{!"omnipotent char", !41, i64 0} +!41 = !{!"Simple C/C++ TBAA"} +!42 = !DILocation(line: 16, column: 1, scope: !15) +!43 = !DILocation(line: 15, column: 3, scope: !15) diff --git a/llvm/test/CodeGen/SBF/CORE/offset-reloc-struct-array.ll b/llvm/test/CodeGen/SBF/CORE/offset-reloc-struct-array.ll new file mode 100644 index 0000000000000..b365c85902d21 --- /dev/null +++ b/llvm/test/CodeGen/SBF/CORE/offset-reloc-struct-array.ll @@ -0,0 +1,218 @@ +; RUN: opt -O2 %s | llvm-dis > %t1 +; RUN: llc -sbf-enable-btf-emission -filetype=asm -o - %t1 | FileCheck -check-prefixes=CHECK %s +; RUN: llc -sbf-enable-btf-emission -mattr=+alu32 -filetype=asm -o - %t1 | FileCheck -check-prefixes=CHECK %s +; Source code: +; struct net_device { +; int dev_id; +; int others; +; }; +; struct sk_buff { +; int i; +; struct net_device dev[10]; +; }; +; #define _(x) (__builtin_preserve_access_index(x)) +; static int (*bpf_probe_read)(void *dst, int size, void *unsafe_ptr) +; = (void *) 4; +; +; int bpf_prog(struct sk_buff *ctx) { +; int dev_id; +; bpf_probe_read(&dev_id, sizeof(int), _(&ctx->dev[5].dev_id)); +; return dev_id; +; } +; Compilation flag: +; clang -target bpf -O2 -g -S -emit-llvm -Xclang -disable-llvm-passes test.c + +target triple = "sbf" + +%struct.sk_buff = type { i32, [10 x %struct.net_device] } +%struct.net_device = type { i32, i32 } + +; Function Attrs: nounwind +define dso_local i32 @bpf_prog(%struct.sk_buff*) local_unnamed_addr #0 !dbg !15 { + %2 = alloca i32, align 4 + call void @llvm.dbg.value(metadata %struct.sk_buff* %0, metadata !31, metadata !DIExpression()), !dbg !33 + %3 = bitcast i32* %2 to i8*, !dbg !34 + call void @llvm.lifetime.start.p0i8(i64 4, i8* nonnull %3) #4, !dbg !34 + %4 = tail call [10 x %struct.net_device]* @llvm.preserve.struct.access.index.p0a10s_struct.net_devices.p0s_struct.sk_buffs(%struct.sk_buff* elementtype(%struct.sk_buff) %0, i32 1, i32 1), !dbg !35, !llvm.preserve.access.index !19 + %5 = tail call %struct.net_device* @llvm.preserve.array.access.index.p0s_struct.net_devices.p0a10s_struct.net_devices([10 x %struct.net_device]* elementtype([10 x %struct.net_device]) %4, i32 1, i32 5), !dbg !35, !llvm.preserve.access.index !23 + %6 = tail call i32* @llvm.preserve.struct.access.index.p0i32.p0s_struct.net_devices(%struct.net_device* elementtype(%struct.net_device) %5, i32 0, i32 0), !dbg !35, !llvm.preserve.access.index !24 + %7 = bitcast i32* %6 to i8*, !dbg !35 + %8 = call i32 inttoptr (i64 4 to i32 (i8*, i32, i8*)*)(i8* nonnull %3, i32 4, i8* %7) #4, !dbg !36 + %9 = load i32, i32* %2, align 4, !dbg !37, !tbaa !38 + call void @llvm.dbg.value(metadata i32 %9, metadata !32, metadata !DIExpression()), !dbg !33 + call void @llvm.lifetime.end.p0i8(i64 4, i8* nonnull %3) #4, !dbg !42 + ret i32 %9, !dbg !43 +} + +; CHECK: .section .BTF,"",@progbits +; CHECK-NEXT: .short 60319 # 0xeb9f +; CHECK-NEXT: .byte 1 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .long 24 +; CHECK-NEXT: .long 0 +; CHECK-NEXT: .long 172 +; CHECK-NEXT: .long 172 +; CHECK-NEXT: .long 128 +; CHECK-NEXT: .long 0 # BTF_KIND_PTR(id = 1) +; CHECK-NEXT: .long 33554432 # 0x2000000 +; CHECK-NEXT: .long 2 +; CHECK-NEXT: .long 1 # BTF_KIND_STRUCT(id = 2) +; CHECK-NEXT: .long 67108866 # 0x4000002 +; CHECK-NEXT: .long 84 +; CHECK-NEXT: .long 9 +; CHECK-NEXT: .long 3 +; CHECK-NEXT: .long 0 # 0x0 +; CHECK-NEXT: .long 11 +; CHECK-NEXT: .long 5 +; CHECK-NEXT: .long 32 # 0x20 +; CHECK-NEXT: .long 15 # BTF_KIND_INT(id = 3) +; CHECK-NEXT: .long 16777216 # 0x1000000 +; CHECK-NEXT: .long 4 +; CHECK-NEXT: .long 16777248 # 0x1000020 +; CHECK-NEXT: .long 19 # BTF_KIND_STRUCT(id = 4) +; CHECK-NEXT: .long 67108866 # 0x4000002 +; CHECK-NEXT: .long 8 +; CHECK-NEXT: .long 30 +; CHECK-NEXT: .long 3 +; CHECK-NEXT: .long 0 # 0x0 +; CHECK-NEXT: .long 37 +; CHECK-NEXT: .long 3 +; CHECK-NEXT: .long 32 # 0x20 +; CHECK-NEXT: .long 0 # BTF_KIND_ARRAY(id = 5) +; CHECK-NEXT: .long 50331648 # 0x3000000 +; CHECK-NEXT: .long 0 +; CHECK-NEXT: .long 4 +; CHECK-NEXT: .long 6 +; CHECK-NEXT: .long 10 +; CHECK-NEXT: .long 44 # BTF_KIND_INT(id = 6) +; CHECK-NEXT: .long 16777216 # 0x1000000 +; CHECK-NEXT: .long 4 +; CHECK-NEXT: .long 32 # 0x20 +; CHECK-NEXT: .long 0 # BTF_KIND_FUNC_PROTO(id = 7) +; CHECK-NEXT: .long 218103809 # 0xd000001 +; CHECK-NEXT: .long 3 +; CHECK-NEXT: .long 64 +; CHECK-NEXT: .long 1 +; CHECK-NEXT: .long 68 # BTF_KIND_FUNC(id = 8) +; CHECK-NEXT: .long 201326593 # 0xc000001 +; CHECK-NEXT: .long 7 +; CHECK-NEXT: .byte 0 # string offset=0 +; CHECK-NEXT: .ascii "sk_buff" # string offset=1 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .byte 105 # string offset=9 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii "dev" # string offset=11 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii "int" # string offset=15 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii "net_device" # string offset=19 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii "dev_id" # string offset=30 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii "others" # string offset=37 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii "__ARRAY_SIZE_TYPE__" # string offset=44 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii "ctx" # string offset=64 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii "bpf_prog" # string offset=68 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii ".text" # string offset=77 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii "/tmp/home/yhs/work/tests/llvm/test.c" # string offset=83 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii "0:1:5:0" # string offset=120 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .section .BTF.ext,"",@progbits +; CHECK-NEXT: .short 60319 # 0xeb9f +; CHECK-NEXT: .byte 1 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .long 32 +; CHECK-NEXT: .long 0 +; CHECK-NEXT: .long 20 +; CHECK-NEXT: .long 20 +; CHECK-NEXT: .long {{[0-9]+}} +; CHECK-NEXT: .long {{[0-9]+}} +; CHECK-NEXT: .long 28 +; CHECK-NEXT: .long 8 # FuncInfo + +; CHECK: .long 16 # FieldReloc +; CHECK-NEXT: .long 77 # Field reloc section string offset=77 +; CHECK-NEXT: .long 1 +; CHECK-NEXT: .long .Ltmp{{[0-9]+}} +; CHECK-NEXT: .long 2 +; CHECK-NEXT: .long 120 +; CHECK-NEXT: .long 0 + +; Function Attrs: argmemonly nounwind +declare void @llvm.lifetime.start.p0i8(i64 immarg, i8* nocapture) #1 + +; Function Attrs: nounwind readnone +declare [10 x %struct.net_device]* @llvm.preserve.struct.access.index.p0a10s_struct.net_devices.p0s_struct.sk_buffs(%struct.sk_buff*, i32 immarg, i32 immarg) #2 + +; Function Attrs: nounwind readnone +declare %struct.net_device* @llvm.preserve.array.access.index.p0s_struct.net_devices.p0a10s_struct.net_devices([10 x %struct.net_device]*, i32 immarg, i32 immarg) #2 + +; Function Attrs: nounwind readnone +declare i32* @llvm.preserve.struct.access.index.p0i32.p0s_struct.net_devices(%struct.net_device*, i32 immarg, i32 immarg) #2 + +; Function Attrs: argmemonly nounwind +declare void @llvm.lifetime.end.p0i8(i64 immarg, i8* nocapture) #1 + +; Function Attrs: nounwind readnone speculatable +declare void @llvm.dbg.value(metadata, metadata, metadata) #3 + +attributes #0 = { nounwind "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "frame-pointer"="all" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" } +attributes #1 = { argmemonly nounwind } +attributes #2 = { nounwind readnone } +attributes #3 = { nounwind readnone speculatable } +attributes #4 = { nounwind } + +!llvm.dbg.cu = !{!0} +!llvm.module.flags = !{!11, !12, !13} +!llvm.ident = !{!14} + +!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 9.0.0 (trunk 360739) (llvm/trunk 360747)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, globals: !3, nameTableKind: None) +!1 = !DIFile(filename: "test.c", directory: "/tmp/home/yhs/work/tests/llvm") +!2 = !{} +!3 = !{!4} +!4 = !DIGlobalVariableExpression(var: !5, expr: !DIExpression()) +!5 = distinct !DIGlobalVariable(name: "bpf_probe_read", scope: !0, file: !1, line: 10, type: !6, isLocal: true, isDefinition: true) +!6 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !7, size: 64) +!7 = !DISubroutineType(types: !8) +!8 = !{!9, !10, !9, !10} +!9 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +!10 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: null, size: 64) +!11 = !{i32 2, !"Dwarf Version", i32 4} +!12 = !{i32 2, !"Debug Info Version", i32 3} +!13 = !{i32 1, !"wchar_size", i32 4} +!14 = !{!"clang version 9.0.0 (trunk 360739) (llvm/trunk 360747)"} +!15 = distinct !DISubprogram(name: "bpf_prog", scope: !1, file: !1, line: 13, type: !16, scopeLine: 13, flags: DIFlagPrototyped, isLocal: false, isDefinition: true, isOptimized: true, unit: !0, retainedNodes: !30) +!16 = !DISubroutineType(types: !17) +!17 = !{!9, !18} +!18 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !19, size: 64) +!19 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "sk_buff", file: !1, line: 5, size: 672, elements: !20) +!20 = !{!21, !22} +!21 = !DIDerivedType(tag: DW_TAG_member, name: "i", scope: !19, file: !1, line: 6, baseType: !9, size: 32) +!22 = !DIDerivedType(tag: DW_TAG_member, name: "dev", scope: !19, file: !1, line: 7, baseType: !23, size: 640, offset: 32) +!23 = !DICompositeType(tag: DW_TAG_array_type, baseType: !24, size: 640, elements: !28) +!24 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "net_device", file: !1, line: 1, size: 64, elements: !25) +!25 = !{!26, !27} +!26 = !DIDerivedType(tag: DW_TAG_member, name: "dev_id", scope: !24, file: !1, line: 2, baseType: !9, size: 32) +!27 = !DIDerivedType(tag: DW_TAG_member, name: "others", scope: !24, file: !1, line: 3, baseType: !9, size: 32, offset: 32) +!28 = !{!29} +!29 = !DISubrange(count: 10) +!30 = !{!31, !32} +!31 = !DILocalVariable(name: "ctx", arg: 1, scope: !15, file: !1, line: 13, type: !18) +!32 = !DILocalVariable(name: "dev_id", scope: !15, file: !1, line: 14, type: !9) +!33 = !DILocation(line: 0, scope: !15) +!34 = !DILocation(line: 14, column: 3, scope: !15) +!35 = !DILocation(line: 15, column: 40, scope: !15) +!36 = !DILocation(line: 15, column: 3, scope: !15) +!37 = !DILocation(line: 16, column: 10, scope: !15) +!38 = !{!39, !39, i64 0} +!39 = !{!"int", !40, i64 0} +!40 = !{!"omnipotent char", !41, i64 0} +!41 = !{!"Simple C/C++ TBAA"} +!42 = !DILocation(line: 17, column: 1, scope: !15) +!43 = !DILocation(line: 16, column: 3, scope: !15) diff --git a/llvm/test/CodeGen/SBF/CORE/offset-reloc-typedef-array.ll b/llvm/test/CodeGen/SBF/CORE/offset-reloc-typedef-array.ll new file mode 100644 index 0000000000000..036e8d0e3fb51 --- /dev/null +++ b/llvm/test/CodeGen/SBF/CORE/offset-reloc-typedef-array.ll @@ -0,0 +1,101 @@ +; RUN: opt -O2 %s | llvm-dis > %t1 +; RUN: llc -sbf-enable-btf-emission -filetype=asm -o - %t1 | FileCheck %s +; RUN: llc -sbf-enable-btf-emission -mattr=+alu32 -filetype=asm -o - %t1 | FileCheck %s +; +; Source code: +; typedef const int arr_t[7]; +; typedef arr_t __arr; +; typedef __arr _arr; +; struct __s { _arr a; }; +; typedef struct __s s; +; #define _(x) (__builtin_preserve_access_index(x)) +; int get_value(const void *addr); +; int test(s *arg) { +; return get_value(_(&arg->a[1])); +; } +; clang -target bpf -S -O2 -g -emit-llvm -Xclang -disable-llvm-passes test.c + +target triple = "sbf" + +%struct.__s = type { [7 x i32] } + +; Function Attrs: nounwind +define dso_local i32 @test(%struct.__s* %arg) local_unnamed_addr #0 !dbg !7 { +entry: + call void @llvm.dbg.value(metadata %struct.__s* %arg, metadata !24, metadata !DIExpression()), !dbg !25 + %0 = tail call [7 x i32]* @llvm.preserve.struct.access.index.p0a7i32.p0s_struct.__ss(%struct.__s* elementtype(%struct.__s) %arg, i32 0, i32 0), !dbg !26, !llvm.preserve.access.index !13 + %1 = tail call i32* @llvm.preserve.array.access.index.p0i32.p0a7i32([7 x i32]* elementtype([7 x i32]) %0, i32 1, i32 1), !dbg !26, !llvm.preserve.access.index !19 + %2 = bitcast i32* %1 to i8*, !dbg !26 + %call = tail call i32 @get_value(i8* %2) #4, !dbg !27 + ret i32 %call, !dbg !28 +} + +; CHECK: .cfi_startproc +; CHECK: [[RELOC:.Ltmp[0-9]+]]: +; CHECK: mov64 r2, 4 +; CHECK: add64 r1, r2 +; CHECK: call get_value + +; CHECK: .long {{[0-9]+}} # BTF_KIND_STRUCT(id = [[TYPE_ID:[0-9]+]]) +; CHECK: .ascii ".text" # string offset=[[SEC_INDEX:[0-9]+]] +; CHECK-NEXT: .byte 0 +; CHECK: .ascii "0:0:1" # string offset=[[ACCESS_STR:[0-9]+]] +; CHECK-NEXT: .byte 0 +; CHECK: .long 16 # FieldReloc +; CHECK-NEXT: .long [[SEC_INDEX]] # Field reloc section string offset=[[SEC_INDEX]] +; CHECK-NEXT: .long 1 +; CHECK-NEXT: .long [[RELOC]] +; CHECK-NEXT: .long [[TYPE_ID]] +; CHECK-NEXT: .long [[ACCESS_STR]] +; CHECK-NEXT: .long 0 + +declare dso_local i32 @get_value(i8*) local_unnamed_addr #1 + +; Function Attrs: nounwind readnone +declare [7 x i32]* @llvm.preserve.struct.access.index.p0a7i32.p0s_struct.__ss(%struct.__s*, i32 immarg, i32 immarg) #2 + +; Function Attrs: nounwind readnone +declare i32* @llvm.preserve.array.access.index.p0i32.p0a7i32([7 x i32]*, i32 immarg, i32 immarg) #2 + +; Function Attrs: nounwind readnone speculatable +declare void @llvm.dbg.value(metadata, metadata, metadata) #3 + +attributes #0 = { nounwind "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" } +attributes #1 = { "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" } +attributes #2 = { nounwind readnone } +attributes #3 = { nounwind readnone speculatable } +attributes #4 = { nounwind } + +!llvm.dbg.cu = !{!0} +!llvm.module.flags = !{!3, !4, !5} +!llvm.ident = !{!6} + +!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 10.0.0 (trunk 366831) (llvm/trunk 366867)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, nameTableKind: None) +!1 = !DIFile(filename: "test.c", directory: "/tmp/home/yhs/work/tests/llvm/core-bugs") +!2 = !{} +!3 = !{i32 2, !"Dwarf Version", i32 4} +!4 = !{i32 2, !"Debug Info Version", i32 3} +!5 = !{i32 1, !"wchar_size", i32 4} +!6 = !{!"clang version 10.0.0 (trunk 366831) (llvm/trunk 366867)"} +!7 = distinct !DISubprogram(name: "test", scope: !1, file: !1, line: 8, type: !8, scopeLine: 8, flags: DIFlagPrototyped, isDefinition: true, isOptimized: true, unit: !0, retainedNodes: !23) +!8 = !DISubroutineType(types: !9) +!9 = !{!10, !11} +!10 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +!11 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !12, size: 64) +!12 = !DIDerivedType(tag: DW_TAG_typedef, name: "s", file: !1, line: 5, baseType: !13) +!13 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "__s", file: !1, line: 4, size: 224, elements: !14) +!14 = !{!15} +!15 = !DIDerivedType(tag: DW_TAG_member, name: "a", scope: !13, file: !1, line: 4, baseType: !16, size: 224) +!16 = !DIDerivedType(tag: DW_TAG_typedef, name: "_arr", file: !1, line: 3, baseType: !17) +!17 = !DIDerivedType(tag: DW_TAG_typedef, name: "__arr", file: !1, line: 2, baseType: !18) +!18 = !DIDerivedType(tag: DW_TAG_typedef, name: "arr_t", file: !1, line: 1, baseType: !19) +!19 = !DICompositeType(tag: DW_TAG_array_type, baseType: !20, size: 224, elements: !21) +!20 = !DIDerivedType(tag: DW_TAG_const_type, baseType: !10) +!21 = !{!22} +!22 = !DISubrange(count: 7) +!23 = !{!24} +!24 = !DILocalVariable(name: "arg", arg: 1, scope: !7, file: !1, line: 8, type: !11) +!25 = !DILocation(line: 0, scope: !7) +!26 = !DILocation(line: 9, column: 20, scope: !7) +!27 = !DILocation(line: 9, column: 10, scope: !7) +!28 = !DILocation(line: 9, column: 3, scope: !7) diff --git a/llvm/test/CodeGen/SBF/CORE/offset-reloc-typedef-struct-2.ll b/llvm/test/CodeGen/SBF/CORE/offset-reloc-typedef-struct-2.ll new file mode 100644 index 0000000000000..551978bdccfaf --- /dev/null +++ b/llvm/test/CodeGen/SBF/CORE/offset-reloc-typedef-struct-2.ll @@ -0,0 +1,92 @@ +; RUN: opt -O2 %s | llvm-dis > %t1 +; RUN: llc -sbf-enable-btf-emission -filetype=asm -o - %t1 | FileCheck %s +; RUN: llc -sbf-enable-btf-emission -mattr=+alu32 -filetype=asm -o - %t1 | FileCheck %s +; +; Source code: +; #pragma clang attribute push (__attribute__((preserve_access_index)), apply_to = record) +; typedef struct { +; int a; +; } __t; +; #pragma clang attribute pop +; +; int test(__t *arg) { return arg->a; } +; Compiler flag to generate IR: +; clang -target bpf -S -O2 -g -emit-llvm -Xclang -disable-llvm-passes test.c + +target triple = "sbf" + +%struct.__t = type { i32 } + +; Function Attrs: nounwind readonly +define dso_local i32 @test(%struct.__t* readonly %arg) local_unnamed_addr #0 !dbg !13 { +entry: + call void @llvm.dbg.value(metadata %struct.__t* %arg, metadata !18, metadata !DIExpression()), !dbg !19 + %0 = tail call i32* @llvm.preserve.struct.access.index.p0i32.p0s_struct.__ts(%struct.__t* elementtype(%struct.__t) %arg, i32 0, i32 0), !dbg !20, !llvm.preserve.access.index !4 + %1 = load i32, i32* %0, align 4, !dbg !20, !tbaa !21 + ret i32 %1, !dbg !26 +} + +; CHECK: .long 1 # BTF_KIND_TYPEDEF(id = 2) +; CHECK-NEXT: .long 134217728 # 0x8000000 +; CHECK-NEXT: .long 3 +; CHECK-NEXT: .long 0 # BTF_KIND_STRUCT(id = 3) +; CHECK-NEXT: .long 67108865 # 0x4000001 +; CHECK-NEXT: .long 4 +; CHECK-NEXT: .long 5 +; CHECK-NEXT: .long 4 +; CHECK-NEXT: .long 0 # 0x0 +; +; CHECK: .ascii "__t" # string offset=1 +; CHECK: .byte 97 # string offset=5 +; CHECK: .ascii ".text" # string offset=20 +; CHECK: .ascii "0:0" # string offset=26 +; +; CHECK: .long 16 # FieldReloc +; CHECK-NEXT: .long 20 # Field reloc section string offset=20 +; CHECK-NEXT: .long 1 +; CHECK-NEXT: .long .Ltmp{{[0-9]+}} +; CHECK-NEXT: .long 2 +; CHECK-NEXT: .long 26 +; CHECK-NEXT: .long 0 + +; Function Attrs: nounwind readnone +declare i32* @llvm.preserve.struct.access.index.p0i32.p0s_struct.__ts(%struct.__t*, i32, i32) #1 + +; Function Attrs: nounwind readnone speculatable +declare void @llvm.dbg.value(metadata, metadata, metadata) #2 + +attributes #0 = { nounwind readonly "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" } +attributes #1 = { nounwind readnone } +attributes #2 = { nounwind readnone speculatable} + +!llvm.dbg.cu = !{!0} +!llvm.module.flags = !{!9, !10, !11} +!llvm.ident = !{!12} + +!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 11.0.0 (https://github.com/llvm/llvm-project.git 5125d1c934efa69ffc1902ce3b8f2f288653a92f)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, retainedTypes: !3, splitDebugInlining: false, nameTableKind: None) +!1 = !DIFile(filename: "test.c", directory: "/tmp/home/yhs/work/tests/core_bug") +!2 = !{} +!3 = !{!4} +!4 = !DIDerivedType(tag: DW_TAG_typedef, name: "__t", file: !1, line: 4, baseType: !5) +!5 = distinct !DICompositeType(tag: DW_TAG_structure_type, file: !1, line: 2, size: 32, elements: !6) +!6 = !{!7} +!7 = !DIDerivedType(tag: DW_TAG_member, name: "a", scope: !5, file: !1, line: 3, baseType: !8, size: 32) +!8 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +!9 = !{i32 7, !"Dwarf Version", i32 4} +!10 = !{i32 2, !"Debug Info Version", i32 3} +!11 = !{i32 1, !"wchar_size", i32 4} +!12 = !{!"clang version 11.0.0 (https://github.com/llvm/llvm-project.git 5125d1c934efa69ffc1902ce3b8f2f288653a92f)"} +!13 = distinct !DISubprogram(name: "test", scope: !1, file: !1, line: 7, type: !14, scopeLine: 7, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, isDefinition: true, isOptimized: true, unit: !0, retainedNodes: !17) +!14 = !DISubroutineType(types: !15) +!15 = !{!8, !16} +!16 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !4, size: 64) +!17 = !{!18} +!18 = !DILocalVariable(name: "arg", arg: 1, scope: !13, file: !1, line: 7, type: !16) +!19 = !DILocation(line: 0, scope: !13) +!20 = !DILocation(line: 7, column: 34, scope: !13) +!21 = !{!22, !23, i64 0} +!22 = !{!"", !23, i64 0} +!23 = !{!"int", !24, i64 0} +!24 = !{!"omnipotent char", !25, i64 0} +!25 = !{!"Simple C/C++ TBAA"} +!26 = !DILocation(line: 7, column: 22, scope: !13) diff --git a/llvm/test/CodeGen/SBF/CORE/offset-reloc-typedef-struct.ll b/llvm/test/CodeGen/SBF/CORE/offset-reloc-typedef-struct.ll new file mode 100644 index 0000000000000..26ab10cb05690 --- /dev/null +++ b/llvm/test/CodeGen/SBF/CORE/offset-reloc-typedef-struct.ll @@ -0,0 +1,94 @@ +; RUN: opt -O2 %s | llvm-dis > %t1 +; RUN: llc -sbf-enable-btf-emission -filetype=asm -o - %t1 | FileCheck %s +; RUN: llc -sbf-enable-btf-emission -mattr=+alu32 -filetype=asm -o - %t1 | FileCheck %s +; +; Source code: +; typedef int _int; +; typedef _int __int; +; struct __s { __int a; __int b; }; +; typedef struct __s _s; +; typedef _s s; +; #define _(x) (__builtin_preserve_access_index(x)) +; int get_value(const void *addr); +; int test(s *arg) { +; return get_value(_(&arg->b)); +; } +; clang -target bpf -S -O2 -g -emit-llvm -Xclang -disable-llvm-passes test.c + +target triple = "sbf" + +%struct.__s = type { i32, i32 } + +; Function Attrs: nounwind +define dso_local i32 @test(%struct.__s* %arg) local_unnamed_addr #0 !dbg !7 { +entry: + call void @llvm.dbg.value(metadata %struct.__s* %arg, metadata !21, metadata !DIExpression()), !dbg !22 + %0 = tail call i32* @llvm.preserve.struct.access.index.p0i32.p0s_struct.__ss(%struct.__s* elementtype(%struct.__s) %arg, i32 1, i32 1), !dbg !23, !llvm.preserve.access.index !14 + %1 = bitcast i32* %0 to i8*, !dbg !23 + %call = tail call i32 @get_value(i8* %1) #4, !dbg !24 + ret i32 %call, !dbg !25 +} + +; CHECK: .cfi_startproc +; CHECK: [[RELOC:.Ltmp[0-9]+]]: +; CHECK: mov64 r2, 4 +; CHECK: add64 r1, r2 +; CHECK: call get_value + +; CHECK: .long {{[0-9]+}} # BTF_KIND_STRUCT(id = [[TYPE_ID:[0-9]+]]) +; CHECK: .ascii ".text" # string offset=[[SEC_STR:[0-9]+]] +; CHECK-NEXT: .byte 0 +; CHECK: .ascii "0:1" # string offset=[[ACCESS_STR:[0-9]+]] +; CHECK-NEXT: .byte 0 +; CHECK: .long 16 # FieldReloc +; CHECK-NEXT: .long [[SEC_STR]] # Field reloc section string offset={{[0-9]+}} +; CHECK-NEXT: .long 1 +; CHECK-NEXT: .long [[RELOC]] +; CHECK-NEXT: .long [[TYPE_ID]] +; CHECK-NEXT: .long [[ACCESS_STR]] +; CHECK-NEXT: .long 0 + +declare dso_local i32 @get_value(i8*) local_unnamed_addr #1 + +; Function Attrs: nounwind readnone +declare i32* @llvm.preserve.struct.access.index.p0i32.p0s_struct.__ss(%struct.__s*, i32 immarg, i32 immarg) #2 + +; Function Attrs: nounwind readnone speculatable +declare void @llvm.dbg.value(metadata, metadata, metadata) #3 + +attributes #0 = { nounwind "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" } +attributes #1 = { "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" } +attributes #2 = { nounwind readnone } +attributes #3 = { nounwind readnone speculatable } +attributes #4 = { nounwind } + +!llvm.dbg.cu = !{!0} +!llvm.module.flags = !{!3, !4, !5} +!llvm.ident = !{!6} + +!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 10.0.0 (trunk 366831) (llvm/trunk 366867)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, nameTableKind: None) +!1 = !DIFile(filename: "test.c", directory: "/tmp/home/yhs/work/tests/llvm/core-bugs") +!2 = !{} +!3 = !{i32 2, !"Dwarf Version", i32 4} +!4 = !{i32 2, !"Debug Info Version", i32 3} +!5 = !{i32 1, !"wchar_size", i32 4} +!6 = !{!"clang version 10.0.0 (trunk 366831) (llvm/trunk 366867)"} +!7 = distinct !DISubprogram(name: "test", scope: !1, file: !1, line: 8, type: !8, scopeLine: 8, flags: DIFlagPrototyped, isDefinition: true, isOptimized: true, unit: !0, retainedNodes: !20) +!8 = !DISubroutineType(types: !9) +!9 = !{!10, !11} +!10 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +!11 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !12, size: 64) +!12 = !DIDerivedType(tag: DW_TAG_typedef, name: "s", file: !1, line: 5, baseType: !13) +!13 = !DIDerivedType(tag: DW_TAG_typedef, name: "_s", file: !1, line: 4, baseType: !14) +!14 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "__s", file: !1, line: 3, size: 64, elements: !15) +!15 = !{!16, !19} +!16 = !DIDerivedType(tag: DW_TAG_member, name: "a", scope: !14, file: !1, line: 3, baseType: !17, size: 32) +!17 = !DIDerivedType(tag: DW_TAG_typedef, name: "__int", file: !1, line: 2, baseType: !18) +!18 = !DIDerivedType(tag: DW_TAG_typedef, name: "_int", file: !1, line: 1, baseType: !10) +!19 = !DIDerivedType(tag: DW_TAG_member, name: "b", scope: !14, file: !1, line: 3, baseType: !17, size: 32, offset: 32) +!20 = !{!21} +!21 = !DILocalVariable(name: "arg", arg: 1, scope: !7, file: !1, line: 8, type: !11) +!22 = !DILocation(line: 0, scope: !7) +!23 = !DILocation(line: 9, column: 20, scope: !7) +!24 = !DILocation(line: 9, column: 10, scope: !7) +!25 = !DILocation(line: 9, column: 3, scope: !7) diff --git a/llvm/test/CodeGen/SBF/CORE/offset-reloc-typedef-union-2.ll b/llvm/test/CodeGen/SBF/CORE/offset-reloc-typedef-union-2.ll new file mode 100644 index 0000000000000..c089259b19b8a --- /dev/null +++ b/llvm/test/CodeGen/SBF/CORE/offset-reloc-typedef-union-2.ll @@ -0,0 +1,91 @@ +; RUN: opt -O2 %s | llvm-dis > %t1 +; RUN: llc -sbf-enable-btf-emission -filetype=asm -o - %t1 | FileCheck %s +; RUN: llc -sbf-enable-btf-emission -mattr=+alu32 -filetype=asm -o - %t1 | FileCheck %s +; +; Source code: +; #pragma clang attribute push (__attribute__((preserve_access_index)), apply_to = record) +; typedef union { +; int a; +; } __t; +; #pragma clang attribute pop +; +; int test(__t *arg) { return arg->a; } +; Compiler flag to generate IR: +; clang -target bpf -S -O2 -g -emit-llvm -Xclang -disable-llvm-passes test.c + +target triple = "sbf" + +%union.__t = type { i32 } + +; Function Attrs: nounwind readonly +define dso_local i32 @test(%union.__t* readonly %arg) local_unnamed_addr #0 !dbg !13 { +entry: + call void @llvm.dbg.value(metadata %union.__t* %arg, metadata !18, metadata !DIExpression()), !dbg !19 + %0 = tail call %union.__t* @llvm.preserve.union.access.index.p0s_union.__ts.p0s_union.__ts(%union.__t* %arg, i32 0), !dbg !20, !llvm.preserve.access.index !4 + %a = getelementptr %union.__t, %union.__t* %0, i64 0, i32 0, !dbg !20 + %1 = load i32, i32* %a, align 4, !dbg !20, !tbaa !21 + ret i32 %1, !dbg !24 +} + +; CHECK: .long 1 # BTF_KIND_TYPEDEF(id = 2) +; CHECK-NEXT: .long 134217728 # 0x8000000 +; CHECK-NEXT: .long 3 +; CHECK-NEXT: .long 0 # BTF_KIND_UNION(id = 3) +; CHECK-NEXT: .long 83886081 # 0x5000001 +; CHECK-NEXT: .long 4 +; CHECK-NEXT: .long 5 +; CHECK-NEXT: .long 4 +; CHECK-NEXT: .long 0 # 0x0 +; +; CHECK: .ascii "__t" # string offset=1 +; CHECK: .byte 97 # string offset=5 +; CHECK: .ascii ".text" # string offset=20 +; CHECK: .ascii "0:0" # string offset=26 +; +; CHECK: .long 16 # FieldReloc +; CHECK-NEXT: .long 20 # Field reloc section string offset=20 +; CHECK-NEXT: .long 1 +; CHECK-NEXT: .long .Ltmp{{[0-9]+}} +; CHECK-NEXT: .long 2 +; CHECK-NEXT: .long 26 +; CHECK-NEXT: .long 0 + +; Function Attrs: nounwind readnone +declare %union.__t* @llvm.preserve.union.access.index.p0s_union.__ts.p0s_union.__ts(%union.__t*, i32) #1 + +; Function Attrs: nounwind readnone speculatable +declare void @llvm.dbg.value(metadata, metadata, metadata) #2 + +attributes #0 = { nounwind readonly "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" } +attributes #1 = { nounwind readnone } +attributes #2 = { nounwind readnone speculatable} + +!llvm.dbg.cu = !{!0} +!llvm.module.flags = !{!9, !10, !11} +!llvm.ident = !{!12} + +!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 11.0.0 (https://github.com/llvm/llvm-project.git 5125d1c934efa69ffc1902ce3b8f2f288653a92f)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, retainedTypes: !3, splitDebugInlining: false, nameTableKind: None) +!1 = !DIFile(filename: "test.c", directory: "/tmp/home/yhs/work/tests/core_bug") +!2 = !{} +!3 = !{!4} +!4 = !DIDerivedType(tag: DW_TAG_typedef, name: "__t", file: !1, line: 4, baseType: !5) +!5 = distinct !DICompositeType(tag: DW_TAG_union_type, file: !1, line: 2, size: 32, elements: !6) +!6 = !{!7} +!7 = !DIDerivedType(tag: DW_TAG_member, name: "a", scope: !5, file: !1, line: 3, baseType: !8, size: 32) +!8 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +!9 = !{i32 7, !"Dwarf Version", i32 4} +!10 = !{i32 2, !"Debug Info Version", i32 3} +!11 = !{i32 1, !"wchar_size", i32 4} +!12 = !{!"clang version 11.0.0 (https://github.com/llvm/llvm-project.git 5125d1c934efa69ffc1902ce3b8f2f288653a92f)"} +!13 = distinct !DISubprogram(name: "test", scope: !1, file: !1, line: 7, type: !14, scopeLine: 7, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, isDefinition: true, isOptimized: true, unit: !0, retainedNodes: !17) +!14 = !DISubroutineType(types: !15) +!15 = !{!8, !16} +!16 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !4, size: 64) +!17 = !{!18} +!18 = !DILocalVariable(name: "arg", arg: 1, scope: !13, file: !1, line: 7, type: !16) +!19 = !DILocation(line: 0, scope: !13) +!20 = !DILocation(line: 7, column: 34, scope: !13) +!21 = !{!22, !22, i64 0} +!22 = !{!"omnipotent char", !23, i64 0} +!23 = !{!"Simple C/C++ TBAA"} +!24 = !DILocation(line: 7, column: 22, scope: !13) diff --git a/llvm/test/CodeGen/SBF/CORE/offset-reloc-typedef-union.ll b/llvm/test/CodeGen/SBF/CORE/offset-reloc-typedef-union.ll new file mode 100644 index 0000000000000..feee49e522ada --- /dev/null +++ b/llvm/test/CodeGen/SBF/CORE/offset-reloc-typedef-union.ll @@ -0,0 +1,94 @@ +; RUN: opt -O2 %s | llvm-dis > %t1 +; RUN: llc -sbf-enable-btf-emission -filetype=asm -o - %t1 | FileCheck %s +; RUN: llc -sbf-enable-btf-emission -mattr=+alu32 -filetype=asm -o - %t1 | FileCheck %s +; +; Source code: +; typedef int _int; +; typedef _int __int; +; union __s { __int a; __int b; }; +; typedef union __s _s; +; typedef _s s; +; #define _(x) (__builtin_preserve_access_index(x)) +; int get_value(const void *addr); +; int test(s *arg) { +; return get_value(_(&arg->b)); +; } +; clang -target bpf -S -O2 -g -emit-llvm -Xclang -disable-llvm-passes test.c + +target triple = "sbf" + +%union.__s = type { i32 } + +; Function Attrs: nounwind +define dso_local i32 @test(%union.__s* %arg) local_unnamed_addr #0 !dbg !7 { +entry: + call void @llvm.dbg.value(metadata %union.__s* %arg, metadata !21, metadata !DIExpression()), !dbg !22 + %0 = tail call %union.__s* @llvm.preserve.union.access.index.p0s_union.__ss.p0s_union.__ss(%union.__s* %arg, i32 1), !dbg !23, !llvm.preserve.access.index !14 + %1 = bitcast %union.__s* %0 to i8*, !dbg !23 + %call = tail call i32 @get_value(i8* %1) #4, !dbg !24 + ret i32 %call, !dbg !25 +} + +; CHECK: .cfi_startproc +; CHECK: [[RELOC:.Ltmp[0-9]+]]: +; CHECK: mov64 r2, 0 +; CHECK: add64 r1, r2 +; CHECK: call get_value + +; CHECK: .long {{[0-9]+}} # BTF_KIND_UNION(id = [[TYPE_ID:[0-9]+]]) +; CHECK: .ascii ".text" # string offset=[[SEC_INDEX:[0-9]+]] +; CHECK-NEXT: .byte 0 +; CHECK: .ascii "0:1" # string offset=[[ACCESS_STR:[0-9]+]] +; CHECK-NEXT: .byte 0 +; CHECK: .long 16 # FieldReloc +; CHECK-NEXT: .long [[SEC_INDEX]] # Field reloc section string offset=[[SEC_INDEX]] +; CHECK-NEXT: .long 1 +; CHECK-NEXT: .long [[RELOC]] +; CHECK-NEXT: .long [[TYPE_ID]] +; CHECK-NEXT: .long [[ACCESS_STR]] +; CHECK-NEXT: .long 0 + +declare dso_local i32 @get_value(i8*) local_unnamed_addr #1 + +; Function Attrs: nounwind readnone +declare %union.__s* @llvm.preserve.union.access.index.p0s_union.__ss.p0s_union.__ss(%union.__s*, i32 immarg) #2 + +; Function Attrs: nounwind readnone speculatable +declare void @llvm.dbg.value(metadata, metadata, metadata) #3 + +attributes #0 = { nounwind "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" } +attributes #1 = { "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" } +attributes #2 = { nounwind readnone } +attributes #3 = { nounwind readnone speculatable } +attributes #4 = { nounwind } + +!llvm.dbg.cu = !{!0} +!llvm.module.flags = !{!3, !4, !5} +!llvm.ident = !{!6} + +!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 10.0.0 (trunk 366831) (llvm/trunk 366867)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, nameTableKind: None) +!1 = !DIFile(filename: "test.c", directory: "/tmp/home/yhs/work/tests/llvm/core-bugs") +!2 = !{} +!3 = !{i32 2, !"Dwarf Version", i32 4} +!4 = !{i32 2, !"Debug Info Version", i32 3} +!5 = !{i32 1, !"wchar_size", i32 4} +!6 = !{!"clang version 10.0.0 (trunk 366831) (llvm/trunk 366867)"} +!7 = distinct !DISubprogram(name: "test", scope: !1, file: !1, line: 8, type: !8, scopeLine: 8, flags: DIFlagPrototyped, isDefinition: true, isOptimized: true, unit: !0, retainedNodes: !20) +!8 = !DISubroutineType(types: !9) +!9 = !{!10, !11} +!10 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +!11 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !12, size: 64) +!12 = !DIDerivedType(tag: DW_TAG_typedef, name: "s", file: !1, line: 5, baseType: !13) +!13 = !DIDerivedType(tag: DW_TAG_typedef, name: "_s", file: !1, line: 4, baseType: !14) +!14 = distinct !DICompositeType(tag: DW_TAG_union_type, name: "__s", file: !1, line: 3, size: 32, elements: !15) +!15 = !{!16, !19} +!16 = !DIDerivedType(tag: DW_TAG_member, name: "a", scope: !14, file: !1, line: 3, baseType: !17, size: 32) +!17 = !DIDerivedType(tag: DW_TAG_typedef, name: "__int", file: !1, line: 2, baseType: !18) +!18 = !DIDerivedType(tag: DW_TAG_typedef, name: "_int", file: !1, line: 1, baseType: !10) +!19 = !DIDerivedType(tag: DW_TAG_member, name: "b", scope: !14, file: !1, line: 3, baseType: !17, size: 32) +!20 = !{!21} +!21 = !DILocalVariable(name: "arg", arg: 1, scope: !7, file: !1, line: 8, type: !11) +!22 = !DILocation(line: 0, scope: !7) +!23 = !DILocation(line: 9, column: 20, scope: !7) +!24 = !DILocation(line: 9, column: 10, scope: !7) +!25 = !DILocation(line: 9, column: 3, scope: !7) diff --git a/llvm/test/CodeGen/SBF/CORE/offset-reloc-typedef.ll b/llvm/test/CodeGen/SBF/CORE/offset-reloc-typedef.ll new file mode 100644 index 0000000000000..a07cf0a9bd3b4 --- /dev/null +++ b/llvm/test/CodeGen/SBF/CORE/offset-reloc-typedef.ll @@ -0,0 +1,115 @@ +; RUN: opt -O2 %s | llvm-dis > %t1 +; RUN: llc -sbf-enable-btf-emission -filetype=asm -o - %t1 | FileCheck %s +; RUN: llc -sbf-enable-btf-emission -mattr=+alu32 -filetype=asm -o - %t1 | FileCheck %s +; +; Source code: +; struct s { int a; int b; }; +; typedef struct s __s; +; union u { __s c; __s d; }; +; typedef union u __u; +; typedef __u arr_t[7]; +; typedef arr_t __arr; +; +; #define _(x) (__builtin_preserve_access_index(x)) +; int get_value(const void *addr); +; int test(__arr *arg) { +; return get_value(_(&arg[1]->d.b)); +; } +; clang -target bpf -S -O2 -g -emit-llvm -Xclang -disable-llvm-passes test.c +; The offset reloc offset should be 12 from the base "arg". + +target triple = "sbf" + +%union.u = type { %struct.s } +%struct.s = type { i32, i32 } + +; Function Attrs: nounwind +define dso_local i32 @test([7 x %union.u]* %arg) local_unnamed_addr #0 !dbg !7 { +entry: + call void @llvm.dbg.value(metadata [7 x %union.u]* %arg, metadata !28, metadata !DIExpression()), !dbg !29 + %0 = tail call [7 x %union.u]* @llvm.preserve.array.access.index.p0a7s_union.us.p0a7s_union.us([7 x %union.u]* elementtype([7 x %union.u]) %arg, i32 0, i32 1), !dbg !30, !llvm.preserve.access.index !14 + %arraydecay = getelementptr inbounds [7 x %union.u], [7 x %union.u]* %0, i64 0, i64 0, !dbg !30 + %1 = tail call %union.u* @llvm.preserve.union.access.index.p0s_union.us.p0s_union.us(%union.u* %arraydecay, i32 1), !dbg !30, !llvm.preserve.access.index !16 + %d = getelementptr inbounds %union.u, %union.u* %1, i64 0, i32 0, !dbg !30 + %2 = tail call i32* @llvm.preserve.struct.access.index.p0i32.p0s_struct.ss(%struct.s* elementtype(%struct.s) %d, i32 1, i32 1), !dbg !30, !llvm.preserve.access.index !20 + %3 = bitcast i32* %2 to i8*, !dbg !30 + %call = tail call i32 @get_value(i8* %3) #4, !dbg !31 + ret i32 %call, !dbg !32 +} + +; CHECK: .cfi_startproc +; CHECK: [[RELOC:.Ltmp[0-9]+]]: +; CHECK: mov64 r2, 12 +; CHECK: add64 r1, r2 +; CHECK: call get_value + +; CHECK: .long {{[0-9]+}} # BTF_KIND_UNION(id = [[TYPE_ID:[0-9]+]]) +; CHECK: .ascii ".text" # string offset=[[SEC_STR:[0-9]+]] +; CHECK-NEXT: .byte 0 +; CHECK: .ascii "1:1:1" # string offset=[[ACCESS_STR:[0-9]+]] +; CHECK-NEXT: .byte 0 +; CHECK: .long 16 # FieldReloc +; CHECK-NEXT: .long [[SEC_STR:[0-9]+]] # Field reloc section string offset=[[SEC_STR:[0-9]+]] +; CHECK-NEXT: .long 1 +; CHECK-NEXT: .long [[RELOC:.Ltmp[0-9]+]] +; CHECK-NEXT: .long [[TYPE_ID:[0-9]+]] +; CHECK-NEXT: .long [[ACCESS_STR:[0-9]+]] +; CHECK-NEXT: .long 0 + +declare dso_local i32 @get_value(i8*) local_unnamed_addr #1 + +; Function Attrs: nounwind readnone +declare [7 x %union.u]* @llvm.preserve.array.access.index.p0a7s_union.us.p0a7s_union.us([7 x %union.u]*, i32 immarg, i32 immarg) #2 + +; Function Attrs: nounwind readnone +declare %union.u* @llvm.preserve.union.access.index.p0s_union.us.p0s_union.us(%union.u*, i32 immarg) #2 + +; Function Attrs: nounwind readnone +declare i32* @llvm.preserve.struct.access.index.p0i32.p0s_struct.ss(%struct.s*, i32 immarg, i32 immarg) #2 + +; Function Attrs: nounwind readnone speculatable +declare void @llvm.dbg.value(metadata, metadata, metadata) #3 + +attributes #0 = { nounwind "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" } +attributes #1 = { "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" } +attributes #2 = { nounwind readnone } +attributes #3 = { nounwind readnone speculatable } +attributes #4 = { nounwind } + +!llvm.dbg.cu = !{!0} +!llvm.module.flags = !{!3, !4, !5} +!llvm.ident = !{!6} + +!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 10.0.0 (trunk 366831) (llvm/trunk 366867)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, nameTableKind: None) +!1 = !DIFile(filename: "test.c", directory: "/tmp/home/yhs/work/tests/llvm/core-bugs") +!2 = !{} +!3 = !{i32 2, !"Dwarf Version", i32 4} +!4 = !{i32 2, !"Debug Info Version", i32 3} +!5 = !{i32 1, !"wchar_size", i32 4} +!6 = !{!"clang version 10.0.0 (trunk 366831) (llvm/trunk 366867)"} +!7 = distinct !DISubprogram(name: "test", scope: !1, file: !1, line: 10, type: !8, scopeLine: 10, flags: DIFlagPrototyped, isDefinition: true, isOptimized: true, unit: !0, retainedNodes: !27) +!8 = !DISubroutineType(types: !9) +!9 = !{!10, !11} +!10 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +!11 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !12, size: 64) +!12 = !DIDerivedType(tag: DW_TAG_typedef, name: "__arr", file: !1, line: 6, baseType: !13) +!13 = !DIDerivedType(tag: DW_TAG_typedef, name: "arr_t", file: !1, line: 5, baseType: !14) +!14 = !DICompositeType(tag: DW_TAG_array_type, baseType: !15, size: 448, elements: !25) +!15 = !DIDerivedType(tag: DW_TAG_typedef, name: "__u", file: !1, line: 4, baseType: !16) +!16 = distinct !DICompositeType(tag: DW_TAG_union_type, name: "u", file: !1, line: 3, size: 64, elements: !17) +!17 = !{!18, !24} +!18 = !DIDerivedType(tag: DW_TAG_member, name: "c", scope: !16, file: !1, line: 3, baseType: !19, size: 64) +!19 = !DIDerivedType(tag: DW_TAG_typedef, name: "__s", file: !1, line: 2, baseType: !20) +!20 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "s", file: !1, line: 1, size: 64, elements: !21) +!21 = !{!22, !23} +!22 = !DIDerivedType(tag: DW_TAG_member, name: "a", scope: !20, file: !1, line: 1, baseType: !10, size: 32) +!23 = !DIDerivedType(tag: DW_TAG_member, name: "b", scope: !20, file: !1, line: 1, baseType: !10, size: 32, offset: 32) +!24 = !DIDerivedType(tag: DW_TAG_member, name: "d", scope: !16, file: !1, line: 3, baseType: !19, size: 64) +!25 = !{!26} +!26 = !DISubrange(count: 7) +!27 = !{!28} +!28 = !DILocalVariable(name: "arg", arg: 1, scope: !7, file: !1, line: 10, type: !11) +!29 = !DILocation(line: 0, scope: !7) +!30 = !DILocation(line: 11, column: 20, scope: !7) +!31 = !DILocation(line: 11, column: 10, scope: !7) +!32 = !DILocation(line: 11, column: 3, scope: !7) diff --git a/llvm/test/CodeGen/SBF/CORE/offset-reloc-union.ll b/llvm/test/CodeGen/SBF/CORE/offset-reloc-union.ll new file mode 100644 index 0000000000000..2f2aa7db4f977 --- /dev/null +++ b/llvm/test/CodeGen/SBF/CORE/offset-reloc-union.ll @@ -0,0 +1,222 @@ +; RUN: opt -O2 %s | llvm-dis > %t1 +; RUN: llc -sbf-enable-btf-emission -filetype=asm -o - %t1 | FileCheck -check-prefixes=CHECK %s +; RUN: llc -sbf-enable-btf-emission -mattr=+alu32 -filetype=asm -o - %t1 | FileCheck -check-prefixes=CHECK %s +; Source code: +; union sk_buff { +; int i; +; struct { +; int netid; +; union { +; int dev_id; +; int others; +; } dev; +; } u; +; }; +; #define _(x) (__builtin_preserve_access_index(x)) +; static int (*bpf_probe_read)(void *dst, int size, void *unsafe_ptr) +; = (void *) 4; +; +; int bpf_prog(union sk_buff *ctx) { +; int dev_id; +; bpf_probe_read(&dev_id, sizeof(int), _(&ctx->u.dev.dev_id)); +; return dev_id; +; } +; Compilation flag: +; clang -target bpf -O2 -g -S -emit-llvm -Xclang -disable-llvm-passes test.c + +target triple = "sbf" + +%union.sk_buff = type { %struct.anon } +%struct.anon = type { i32, %union.anon } +%union.anon = type { i32 } + +; Function Attrs: nounwind +define dso_local i32 @bpf_prog(%union.sk_buff*) local_unnamed_addr #0 !dbg !15 { + %2 = alloca i32, align 4 + call void @llvm.dbg.value(metadata %union.sk_buff* %0, metadata !32, metadata !DIExpression()), !dbg !34 + %3 = bitcast i32* %2 to i8*, !dbg !35 + call void @llvm.lifetime.start.p0i8(i64 4, i8* nonnull %3) #4, !dbg !35 + %4 = tail call %union.sk_buff* @llvm.preserve.union.access.index.p0s_union.sk_buffs.p0s_union.sk_buffs(%union.sk_buff* %0, i32 1), !dbg !36, !llvm.preserve.access.index !19 + %5 = getelementptr inbounds %union.sk_buff, %union.sk_buff* %4, i64 0, i32 0, !dbg !36 + %6 = tail call %union.anon* @llvm.preserve.struct.access.index.p0s_union.anons.p0s_struct.anons(%struct.anon* elementtype(%struct.anon) %5, i32 1, i32 1), !dbg !36, !llvm.preserve.access.index !23 + %7 = tail call %union.anon* @llvm.preserve.union.access.index.p0s_union.anons.p0s_union.anons(%union.anon* %6, i32 0), !dbg !36, !llvm.preserve.access.index !27 + %8 = bitcast %union.anon* %7 to i8*, !dbg !36 + %9 = call i32 inttoptr (i64 4 to i32 (i8*, i32, i8*)*)(i8* nonnull %3, i32 4, i8* %8) #4, !dbg !37 + %10 = load i32, i32* %2, align 4, !dbg !38, !tbaa !39 + call void @llvm.dbg.value(metadata i32 %10, metadata !33, metadata !DIExpression()), !dbg !34 + call void @llvm.lifetime.end.p0i8(i64 4, i8* nonnull %3) #4, !dbg !43 + ret i32 %10, !dbg !44 +} + +; CHECK: .section .BTF,"",@progbits +; CHECK-NEXT: .short 60319 # 0xeb9f +; CHECK-NEXT: .byte 1 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .long 24 +; CHECK-NEXT: .long 0 +; CHECK-NEXT: .long 168 +; CHECK-NEXT: .long 168 +; CHECK-NEXT: .long 105 +; CHECK-NEXT: .long 0 # BTF_KIND_PTR(id = 1) +; CHECK-NEXT: .long 33554432 # 0x2000000 +; CHECK-NEXT: .long 2 +; CHECK-NEXT: .long 1 # BTF_KIND_UNION(id = 2) +; CHECK-NEXT: .long 83886082 # 0x5000002 +; CHECK-NEXT: .long 8 +; CHECK-NEXT: .long 9 +; CHECK-NEXT: .long 3 +; CHECK-NEXT: .long 0 # 0x0 +; CHECK-NEXT: .long 11 +; CHECK-NEXT: .long 4 +; CHECK-NEXT: .long 0 # 0x0 +; CHECK-NEXT: .long 13 # BTF_KIND_INT(id = 3) +; CHECK-NEXT: .long 16777216 # 0x1000000 +; CHECK-NEXT: .long 4 +; CHECK-NEXT: .long 16777248 # 0x1000020 +; CHECK-NEXT: .long 0 # BTF_KIND_STRUCT(id = 4) +; CHECK-NEXT: .long 67108866 # 0x4000002 +; CHECK-NEXT: .long 8 +; CHECK-NEXT: .long 17 +; CHECK-NEXT: .long 3 +; CHECK-NEXT: .long 0 # 0x0 +; CHECK-NEXT: .long 23 +; CHECK-NEXT: .long 5 +; CHECK-NEXT: .long 32 # 0x20 +; CHECK-NEXT: .long 0 # BTF_KIND_UNION(id = 5) +; CHECK-NEXT: .long 83886082 # 0x5000002 +; CHECK-NEXT: .long 4 +; CHECK-NEXT: .long 27 +; CHECK-NEXT: .long 3 +; CHECK-NEXT: .long 0 # 0x0 +; CHECK-NEXT: .long 34 +; CHECK-NEXT: .long 3 +; CHECK-NEXT: .long 0 # 0x0 +; CHECK-NEXT: .long 0 # BTF_KIND_FUNC_PROTO(id = 6) +; CHECK-NEXT: .long 218103809 # 0xd000001 +; CHECK-NEXT: .long 3 +; CHECK-NEXT: .long 41 +; CHECK-NEXT: .long 1 +; CHECK-NEXT: .long 45 # BTF_KIND_FUNC(id = 7) +; CHECK-NEXT: .long 201326593 # 0xc000001 +; CHECK-NEXT: .long 6 +; CHECK-NEXT: .byte 0 # string offset=0 +; CHECK-NEXT: .ascii "sk_buff" # string offset=1 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .byte 105 # string offset=9 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .byte 117 # string offset=11 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii "int" # string offset=13 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii "netid" # string offset=17 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii "dev" # string offset=23 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii "dev_id" # string offset=27 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii "others" # string offset=34 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii "ctx" # string offset=41 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii "bpf_prog" # string offset=45 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii ".text" # string offset=54 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii "/tmp/home/yhs/work/tests/llvm/test.c" # string offset=60 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .ascii "0:1:1:0" # string offset=97 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .section .BTF.ext,"",@progbits +; CHECK-NEXT: .short 60319 # 0xeb9f +; CHECK-NEXT: .byte 1 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .long 32 +; CHECK-NEXT: .long 0 +; CHECK-NEXT: .long 20 +; CHECK-NEXT: .long 20 +; CHECK-NEXT: .long {{[0-9]+}} +; CHECK-NEXT: .long {{[0-9]+}} +; CHECK-NEXT: .long 28 +; CHECK-NEXT: .long 8 # FuncInfo + +; CHECK: .long 16 # FieldReloc +; CHECK-NEXT: .long 54 # Field reloc section string offset=54 +; CHECK-NEXT: .long 1 +; CHECK-NEXT: .long .Ltmp{{[0-9]+}} +; CHECK-NEXT: .long 2 +; CHECK-NEXT: .long 97 +; CHECK-NEXT: .long 0 + +; Function Attrs: argmemonly nounwind +declare void @llvm.lifetime.start.p0i8(i64 immarg, i8* nocapture) #1 + +; Function Attrs: nounwind readnone +declare %union.sk_buff* @llvm.preserve.union.access.index.p0s_union.sk_buffs.p0s_union.sk_buffs(%union.sk_buff*, i32 immarg) #2 + +; Function Attrs: nounwind readnone +declare %union.anon* @llvm.preserve.struct.access.index.p0s_union.anons.p0s_struct.anons(%struct.anon*, i32 immarg, i32 immarg) #2 + +; Function Attrs: nounwind readnone +declare %union.anon* @llvm.preserve.union.access.index.p0s_union.anons.p0s_union.anons(%union.anon*, i32 immarg) #2 + +; Function Attrs: argmemonly nounwind +declare void @llvm.lifetime.end.p0i8(i64 immarg, i8* nocapture) #1 + +; Function Attrs: nounwind readnone speculatable +declare void @llvm.dbg.value(metadata, metadata, metadata) #3 + +attributes #0 = { nounwind "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "frame-pointer"="all" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" } +attributes #1 = { argmemonly nounwind } +attributes #2 = { nounwind readnone } +attributes #3 = { nounwind readnone speculatable } +attributes #4 = { nounwind } + +!llvm.dbg.cu = !{!0} +!llvm.module.flags = !{!11, !12, !13} +!llvm.ident = !{!14} + +!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 9.0.0 (trunk 360739) (llvm/trunk 360747)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, globals: !3, nameTableKind: None) +!1 = !DIFile(filename: "test.c", directory: "/tmp/home/yhs/work/tests/llvm") +!2 = !{} +!3 = !{!4} +!4 = !DIGlobalVariableExpression(var: !5, expr: !DIExpression()) +!5 = distinct !DIGlobalVariable(name: "bpf_probe_read", scope: !0, file: !1, line: 12, type: !6, isLocal: true, isDefinition: true) +!6 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !7, size: 64) +!7 = !DISubroutineType(types: !8) +!8 = !{!9, !10, !9, !10} +!9 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +!10 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: null, size: 64) +!11 = !{i32 2, !"Dwarf Version", i32 4} +!12 = !{i32 2, !"Debug Info Version", i32 3} +!13 = !{i32 1, !"wchar_size", i32 4} +!14 = !{!"clang version 9.0.0 (trunk 360739) (llvm/trunk 360747)"} +!15 = distinct !DISubprogram(name: "bpf_prog", scope: !1, file: !1, line: 15, type: !16, scopeLine: 15, flags: DIFlagPrototyped, isLocal: false, isDefinition: true, isOptimized: true, unit: !0, retainedNodes: !31) +!16 = !DISubroutineType(types: !17) +!17 = !{!9, !18} +!18 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !19, size: 64) +!19 = distinct !DICompositeType(tag: DW_TAG_union_type, name: "sk_buff", file: !1, line: 1, size: 64, elements: !20) +!20 = !{!21, !22} +!21 = !DIDerivedType(tag: DW_TAG_member, name: "i", scope: !19, file: !1, line: 2, baseType: !9, size: 32) +!22 = !DIDerivedType(tag: DW_TAG_member, name: "u", scope: !19, file: !1, line: 9, baseType: !23, size: 64) +!23 = distinct !DICompositeType(tag: DW_TAG_structure_type, scope: !19, file: !1, line: 3, size: 64, elements: !24) +!24 = !{!25, !26} +!25 = !DIDerivedType(tag: DW_TAG_member, name: "netid", scope: !23, file: !1, line: 4, baseType: !9, size: 32) +!26 = !DIDerivedType(tag: DW_TAG_member, name: "dev", scope: !23, file: !1, line: 8, baseType: !27, size: 32, offset: 32) +!27 = distinct !DICompositeType(tag: DW_TAG_union_type, scope: !23, file: !1, line: 5, size: 32, elements: !28) +!28 = !{!29, !30} +!29 = !DIDerivedType(tag: DW_TAG_member, name: "dev_id", scope: !27, file: !1, line: 6, baseType: !9, size: 32) +!30 = !DIDerivedType(tag: DW_TAG_member, name: "others", scope: !27, file: !1, line: 7, baseType: !9, size: 32) +!31 = !{!32, !33} +!32 = !DILocalVariable(name: "ctx", arg: 1, scope: !15, file: !1, line: 15, type: !18) +!33 = !DILocalVariable(name: "dev_id", scope: !15, file: !1, line: 16, type: !9) +!34 = !DILocation(line: 0, scope: !15) +!35 = !DILocation(line: 16, column: 3, scope: !15) +!36 = !DILocation(line: 17, column: 40, scope: !15) +!37 = !DILocation(line: 17, column: 3, scope: !15) +!38 = !DILocation(line: 18, column: 10, scope: !15) +!39 = !{!40, !40, i64 0} +!40 = !{!"int", !41, i64 0} +!41 = !{!"omnipotent char", !42, i64 0} +!42 = !{!"Simple C/C++ TBAA"} +!43 = !DILocation(line: 19, column: 1, scope: !15) +!44 = !DILocation(line: 18, column: 3, scope: !15) diff --git a/llvm/test/CodeGen/SBF/CORE/simplifypatable-nullptr.ll b/llvm/test/CodeGen/SBF/CORE/simplifypatable-nullptr.ll new file mode 100644 index 0000000000000..c92249161de63 --- /dev/null +++ b/llvm/test/CodeGen/SBF/CORE/simplifypatable-nullptr.ll @@ -0,0 +1,137 @@ +; RUN: llc -sbf-enable-btf-emission -O2 -march=sbf -mcpu=v3 < %s | FileCheck %s +; Source code: +; struct t3 { +; int i; +; } __attribute__((preserve_access_index)); +; struct t2 { +; void *pad; +; struct t3 *f; +; } __attribute__((preserve_access_index)); +; struct t1 { +; void *pad; +; struct t2 *q; +; } __attribute__((preserve_access_index)); +; +; int g; +; int test(struct t1 *p) { +; struct t2 *q = p->q; +; if (q) +; return 0; +; struct t3 *f = q->f; +; if (!f) g = 5; +; return 0; +; } +; Compilation flag: +; clang -target bpf -O2 -g -S -emit-llvm t.c + +@g = dso_local local_unnamed_addr global i32 0, align 4, !dbg !0 +@"llvm.t2:0:8$0:1" = external global i64, !llvm.preserve.access.index !6 #0 +@"llvm.t1:0:8$0:1" = external global i64, !llvm.preserve.access.index !15 #0 + +; Function Attrs: mustprogress nofree nosync nounwind willreturn +define dso_local i32 @test(ptr noundef readonly %p) local_unnamed_addr #1 !dbg !25 { +entry: + call void @llvm.dbg.value(metadata ptr %p, metadata !30, metadata !DIExpression()), !dbg !33 + %0 = load i64, ptr @"llvm.t1:0:8$0:1", align 8 + %1 = getelementptr i8, ptr %p, i64 %0 + %2 = tail call ptr @llvm.bpf.passthrough.p0.p0(i32 1, ptr %1) + %3 = load ptr, ptr %2, align 8, !dbg !34, !tbaa !35 + call void @llvm.dbg.value(metadata ptr %3, metadata !31, metadata !DIExpression()), !dbg !33 + %tobool.not = icmp eq ptr %3, null, !dbg !40 + br i1 %tobool.not, label %if.end, label %cleanup, !dbg !42 + +; CHECK-LABEL: test +; CHECK: ldxdw r1, [r1 + 0] +; CHECK: jne r1, 0, + +if.end: ; preds = %entry + %4 = load i64, ptr @"llvm.t2:0:8$0:1", align 8 + %5 = getelementptr i8, ptr null, i64 %4 + %6 = tail call ptr @llvm.bpf.passthrough.p0.p0(i32 0, ptr %5) + %7 = load ptr, ptr %6, align 8, !dbg !43, !tbaa !44 + call void @llvm.dbg.value(metadata ptr %7, metadata !32, metadata !DIExpression()), !dbg !33 + %tobool1.not = icmp eq ptr %7, null, !dbg !46 + br i1 %tobool1.not, label %if.then2, label %cleanup, !dbg !48 + +; CHECK: mov32 r1, +; CHECK: hor64 r1, +; CHECK: ldxdw r1, [r1 + 0] +; CHECK: jne r1, 0, + +if.then2: ; preds = %if.end + store i32 5, ptr @g, align 4, !dbg !49, !tbaa !50 + br label %cleanup, !dbg !52 + +cleanup: ; preds = %if.end, %if.then2, %entry + ret i32 0, !dbg !53 +} + +; Function Attrs: nofree nosync nounwind readnone +declare ptr @llvm.bpf.passthrough.p0.p0(i32, ptr) #2 + +; Function Attrs: nocallback nofree nosync nounwind readnone speculatable willreturn +declare void @llvm.dbg.value(metadata, metadata, metadata) #3 + +attributes #0 = { "btf_ama" } +attributes #1 = { mustprogress nofree nosync nounwind willreturn "frame-pointer"="all" "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" } +attributes #2 = { nofree nosync nounwind readnone } +attributes #3 = { nocallback nofree nosync nounwind readnone speculatable willreturn } + +!llvm.dbg.cu = !{!2} +!llvm.module.flags = !{!20, !21, !22, !23} +!llvm.ident = !{!24} + +!0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression()) +!1 = distinct !DIGlobalVariable(name: "g", scope: !2, file: !3, line: 13, type: !5, isLocal: false, isDefinition: true) +!2 = distinct !DICompileUnit(language: DW_LANG_C99, file: !3, producer: "clang version 15.0.0 (https://github.com/llvm/llvm-project.git ca2be81e34a6d87edb8e555dfac94ab68ee20f70)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, globals: !4, splitDebugInlining: false, nameTableKind: None) +!3 = !DIFile(filename: "t.c", directory: "/tmp/home/yhs/work/tests/llvm/nullptr", checksumkind: CSK_MD5, checksum: "2c0ea9b3c647baf31f56992f9142b0df") +!4 = !{!0} +!5 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +!6 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "t2", file: !3, line: 4, size: 128, elements: !7) +!7 = !{!8, !10} +!8 = !DIDerivedType(tag: DW_TAG_member, name: "pad", scope: !6, file: !3, line: 5, baseType: !9, size: 64) +!9 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: null, size: 64) +!10 = !DIDerivedType(tag: DW_TAG_member, name: "f", scope: !6, file: !3, line: 6, baseType: !11, size: 64, offset: 64) +!11 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !12, size: 64) +!12 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "t3", file: !3, line: 1, size: 32, elements: !13) +!13 = !{!14} +!14 = !DIDerivedType(tag: DW_TAG_member, name: "i", scope: !12, file: !3, line: 2, baseType: !5, size: 32) +!15 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "t1", file: !3, line: 8, size: 128, elements: !16) +!16 = !{!17, !18} +!17 = !DIDerivedType(tag: DW_TAG_member, name: "pad", scope: !15, file: !3, line: 9, baseType: !9, size: 64) +!18 = !DIDerivedType(tag: DW_TAG_member, name: "q", scope: !15, file: !3, line: 10, baseType: !19, size: 64, offset: 64) +!19 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !6, size: 64) +!20 = !{i32 7, !"Dwarf Version", i32 5} +!21 = !{i32 2, !"Debug Info Version", i32 3} +!22 = !{i32 1, !"wchar_size", i32 4} +!23 = !{i32 7, !"frame-pointer", i32 2} +!24 = !{!"clang version 15.0.0 (https://github.com/llvm/llvm-project.git ca2be81e34a6d87edb8e555dfac94ab68ee20f70)"} +!25 = distinct !DISubprogram(name: "test", scope: !3, file: !3, line: 14, type: !26, scopeLine: 14, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !2, retainedNodes: !29) +!26 = !DISubroutineType(types: !27) +!27 = !{!5, !28} +!28 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !15, size: 64) +!29 = !{!30, !31, !32} +!30 = !DILocalVariable(name: "p", arg: 1, scope: !25, file: !3, line: 14, type: !28) +!31 = !DILocalVariable(name: "q", scope: !25, file: !3, line: 15, type: !19) +!32 = !DILocalVariable(name: "f", scope: !25, file: !3, line: 18, type: !11) +!33 = !DILocation(line: 0, scope: !25) +!34 = !DILocation(line: 15, column: 21, scope: !25) +!35 = !{!36, !37, i64 8} +!36 = !{!"t1", !37, i64 0, !37, i64 8} +!37 = !{!"any pointer", !38, i64 0} +!38 = !{!"omnipotent char", !39, i64 0} +!39 = !{!"Simple C/C++ TBAA"} +!40 = !DILocation(line: 16, column: 7, scope: !41) +!41 = distinct !DILexicalBlock(scope: !25, file: !3, line: 16, column: 7) +!42 = !DILocation(line: 16, column: 7, scope: !25) +!43 = !DILocation(line: 18, column: 21, scope: !25) +!44 = !{!45, !37, i64 8} +!45 = !{!"t2", !37, i64 0, !37, i64 8} +!46 = !DILocation(line: 19, column: 8, scope: !47) +!47 = distinct !DILexicalBlock(scope: !25, file: !3, line: 19, column: 7) +!48 = !DILocation(line: 19, column: 7, scope: !25) +!49 = !DILocation(line: 19, column: 13, scope: !47) +!50 = !{!51, !51, i64 0} +!51 = !{!"int", !38, i64 0} +!52 = !DILocation(line: 19, column: 11, scope: !47) +!53 = !DILocation(line: 21, column: 1, scope: !25) diff --git a/llvm/test/CodeGen/SBF/CORE/store-addr.ll b/llvm/test/CodeGen/SBF/CORE/store-addr.ll new file mode 100644 index 0000000000000..70290c048e53f --- /dev/null +++ b/llvm/test/CodeGen/SBF/CORE/store-addr.ll @@ -0,0 +1,113 @@ +; RUN: opt -O2 %s | llvm-dis > %t1 +; RUN: llc -sbf-enable-btf-emission -filetype=asm -o - %t1 | FileCheck %s +; RUN: llc -sbf-enable-btf-emission -mattr=+alu32 -filetype=asm -o - %t1 | FileCheck %s +; RUN: opt -passes='default' %s | llvm-dis > %t1 +; RUN: llc -sbf-enable-btf-emission -filetype=asm -o - %t1 | FileCheck %s +; RUN: llc -sbf-enable-btf-emission -mattr=+alu32 -filetype=asm -o - %t1 | FileCheck %s +; Source code: +; struct t { +; int a; +; } __attribute__((preserve_access_index)); +; int foo(void *); +; int test(struct t *arg) { +; long param[1]; +; param[0] = (long)&arg->a; +; return foo(param); +; } +; Compiler flag to generate IR: +; clang -target bpf -S -O2 -g -emit-llvm -Xclang -disable-llvm-passes test.c + +target triple = "sbf" + +%struct.t = type { i32 } + +; Function Attrs: nounwind +define dso_local i32 @test(%struct.t* %arg) local_unnamed_addr #0 !dbg !14 { +entry: + %param = alloca [1 x i64], align 8 + call void @llvm.dbg.value(metadata %struct.t* %arg, metadata !22, metadata !DIExpression()), !dbg !27 + %0 = bitcast [1 x i64]* %param to i8*, !dbg !28 + call void @llvm.lifetime.start.p0i8(i64 8, i8* nonnull %0) #5, !dbg !28 + call void @llvm.dbg.declare(metadata [1 x i64]* %param, metadata !23, metadata !DIExpression()), !dbg !29 + %1 = tail call i32* @llvm.preserve.struct.access.index.p0i32.p0s_struct.ts(%struct.t* elementtype(%struct.t) %arg, i32 0, i32 0), !dbg !30, !llvm.preserve.access.index !18 + %2 = ptrtoint i32* %1 to i64, !dbg !31 + %arrayidx = getelementptr inbounds [1 x i64], [1 x i64]* %param, i64 0, i64 0, !dbg !32 + store i64 %2, i64* %arrayidx, align 8, !dbg !33, !tbaa !34 + %call = call i32 @foo(i8* nonnull %0) #5, !dbg !38 + call void @llvm.lifetime.end.p0i8(i64 8, i8* nonnull %0) #5, !dbg !39 + ret i32 %call, !dbg !40 +} + +; CHECK: mov64 r[[OFFSET:[0-9]+]], 0 +; CHECK: add64 r1, r[[OFFSET]] +; CHECK: stxdw [r10 - 8], r1 + +; Function Attrs: nounwind readnone speculatable +declare void @llvm.dbg.declare(metadata, metadata, metadata) #1 + +; Function Attrs: argmemonly nounwind +declare void @llvm.lifetime.start.p0i8(i64, i8* nocapture) #2 + +; Function Attrs: nounwind readnone +declare i32* @llvm.preserve.struct.access.index.p0i32.p0s_struct.ts(%struct.t*, i32, i32) #3 + +declare !dbg !5 dso_local i32 @foo(i8*) local_unnamed_addr #4 + +; Function Attrs: argmemonly nounwind +declare void @llvm.lifetime.end.p0i8(i64, i8* nocapture) #2 + +; Function Attrs: nounwind readnone speculatable +declare void @llvm.dbg.value(metadata, metadata, metadata) #1 + +attributes #0 = { nounwind "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" } +attributes #1 = { nounwind readnone speculatable } +attributes #2 = { argmemonly nounwind } +attributes #3 = { nounwind readnone } +attributes #4 = { "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" } +attributes #5 = { nounwind } + +!llvm.dbg.cu = !{!0} +!llvm.module.flags = !{!10, !11, !12} +!llvm.ident = !{!13} + +!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 11.0.0 (https://github.com/llvm/llvm-project.git 4f995959a05ae94cc4f9cc80035f7e4b3ecd2d88)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, retainedTypes: !3, splitDebugInlining: false, nameTableKind: None) +!1 = !DIFile(filename: "test.c", directory: "/tmp/home/yhs/work/tests/core") +!2 = !{} +!3 = !{!4, !5} +!4 = !DIBasicType(name: "long int", size: 64, encoding: DW_ATE_signed) +!5 = !DISubprogram(name: "foo", scope: !1, file: !1, line: 4, type: !6, flags: DIFlagPrototyped, spFlags: DISPFlagOptimized, retainedNodes: !2) +!6 = !DISubroutineType(types: !7) +!7 = !{!8, !9} +!8 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +!9 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: null, size: 64) +!10 = !{i32 7, !"Dwarf Version", i32 4} +!11 = !{i32 2, !"Debug Info Version", i32 3} +!12 = !{i32 1, !"wchar_size", i32 4} +!13 = !{!"clang version 11.0.0 (https://github.com/llvm/llvm-project.git 4f995959a05ae94cc4f9cc80035f7e4b3ecd2d88)"} +!14 = distinct !DISubprogram(name: "test", scope: !1, file: !1, line: 5, type: !15, scopeLine: 5, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !21) +!15 = !DISubroutineType(types: !16) +!16 = !{!8, !17} +!17 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !18, size: 64) +!18 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "t", file: !1, line: 1, size: 32, elements: !19) +!19 = !{!20} +!20 = !DIDerivedType(tag: DW_TAG_member, name: "a", scope: !18, file: !1, line: 2, baseType: !8, size: 32) +!21 = !{!22, !23} +!22 = !DILocalVariable(name: "arg", arg: 1, scope: !14, file: !1, line: 5, type: !17) +!23 = !DILocalVariable(name: "param", scope: !14, file: !1, line: 6, type: !24) +!24 = !DICompositeType(tag: DW_TAG_array_type, baseType: !4, size: 64, elements: !25) +!25 = !{!26} +!26 = !DISubrange(count: 1) +!27 = !DILocation(line: 0, scope: !14) +!28 = !DILocation(line: 6, column: 5, scope: !14) +!29 = !DILocation(line: 6, column: 10, scope: !14) +!30 = !DILocation(line: 7, column: 28, scope: !14) +!31 = !DILocation(line: 7, column: 16, scope: !14) +!32 = !DILocation(line: 7, column: 5, scope: !14) +!33 = !DILocation(line: 7, column: 14, scope: !14) +!34 = !{!35, !35, i64 0} +!35 = !{!"long", !36, i64 0} +!36 = !{!"omnipotent char", !37, i64 0} +!37 = !{!"Simple C/C++ TBAA"} +!38 = !DILocation(line: 8, column: 12, scope: !14) +!39 = !DILocation(line: 9, column: 1, scope: !14) +!40 = !DILocation(line: 8, column: 5, scope: !14) diff --git a/llvm/test/CodeGen/SBF/TODO-NOTES b/llvm/test/CodeGen/SBF/TODO-NOTES new file mode 100644 index 0000000000000..89536f32f2d72 --- /dev/null +++ b/llvm/test/CodeGen/SBF/TODO-NOTES @@ -0,0 +1,12 @@ +Note that BTF has been disabled for SBF as of commit +559ff25f978a675230cc2dbcc18851424ace7fb9. + +Moreover, we are tentatively going to completely remove BTF and related +support from SBF. + +We have therefore removed the BTF/ and CORE/ test subdirectories which only +apply when BTF is available. + +Once we determine for certain that BTF will definitely be removed, delete +this TODO-NOTE. If for some reason BTF is deemed necessary, re-instate the +test directories mentioned above. diff --git a/llvm/test/CodeGen/SBF/alu8.ll b/llvm/test/CodeGen/SBF/alu8.ll new file mode 100644 index 0000000000000..3843fab1d8268 --- /dev/null +++ b/llvm/test/CodeGen/SBF/alu8.ll @@ -0,0 +1,45 @@ +; RUN: llc -march=sbf -show-mc-encoding < %s | FileCheck %s + +define i8 @mov(i8 %a, i8 %b) nounwind { +; CHECK-LABEL: mov: +; CHECK: mov64 r0, r2 # encoding: [0xbf,0x20,0x00,0x00,0x00,0x00,0x00,0x00] +; CHECK: exit # encoding: [0x95,0x00,0x00,0x00,0x00,0x00,0x00,0x00] + ret i8 %b +} + +define i8 @add(i8 %a, i8 %b) nounwind { +; CHECK-LABEL: add: +; CHECK: mov64 r0, r1 # encoding: [0xbf,0x10,0x00,0x00,0x00,0x00,0x00,0x00] +; CHECK: add64 r0, r2 # encoding: [0x0f,0x20,0x00,0x00,0x00,0x00,0x00,0x00] + %1 = add i8 %a, %b + ret i8 %1 +} + +define i8 @and(i8 %a, i8 %b) nounwind { +; CHECK-LABEL: and: +; CHECK: and64 r0, r2 # encoding: [0x5f,0x20,0x00,0x00,0x00,0x00,0x00,0x00] + %1 = and i8 %a, %b + ret i8 %1 +} + +define i8 @bis(i8 %a, i8 %b) nounwind { +; CHECK-LABEL: bis: +; CHECK: or64 r0, r2 # encoding: [0x4f,0x20,0x00,0x00,0x00,0x00,0x00,0x00] + %1 = or i8 %a, %b + ret i8 %1 +} + +define i8 @xorand(i8 %a, i8 %b) nounwind { +; CHECK-LABEL: xorand: +; CHECK: xor64 r2, -1 # encoding: [0xa7,0x02,0x00,0x00,0xff,0xff,0xff,0xff] + %1 = xor i8 %b, -1 + %2 = and i8 %a, %1 + ret i8 %2 +} + +define i8 @xor(i8 %a, i8 %b) nounwind { +; CHECK-LABEL: xor: +; CHECK: xor64 r0, r2 # encoding: [0xaf,0x20,0x00,0x00,0x00,0x00,0x00,0x00] + %1 = xor i8 %a, %b + ret i8 %1 +} diff --git a/llvm/test/CodeGen/SBF/atomics_sbf.ll b/llvm/test/CodeGen/SBF/atomics_sbf.ll new file mode 100644 index 0000000000000..f881b1c51f882 --- /dev/null +++ b/llvm/test/CodeGen/SBF/atomics_sbf.ll @@ -0,0 +1,352 @@ +; RUN: llc < %s -march=sbf -mattr=+alu32,+explicit-sext -verify-machineinstrs | tee -i /tmp/log | FileCheck %s +; +; CHECK-LABEL: test_load_add_32 +; CHECK: ldxw w0, [r1 + 0] +; CHECK: mov64 w3, w0 +; CHECK: add32 w3, w2 +; CHECK: stxw [r1 + 0], w3 +define dso_local i32 @test_load_add_32(i32* nocapture %p, i32 %v) local_unnamed_addr { +entry: + %0 = atomicrmw add i32* %p, i32 %v seq_cst + ret i32 %0 +} + +; CHECK-LABEL: test_load_add_64 +; CHECK: ldxdw r0, [r1 + 0] +; CHECK: mov64 r3, r0 +; CHECK: add64 r3, r2 +; CHECK: stxdw [r1 + 0], r3 +define dso_local i32 @test_load_add_64(i64* nocapture %p, i64 %v) local_unnamed_addr { +entry: + %0 = atomicrmw add i64* %p, i64 %v seq_cst + %conv = trunc i64 %0 to i32 + ret i32 %conv +} + +; CHECK-LABEL: test_load_sub_32 +; CHECK: ldxw w0, [r1 + 0] +; CHECK: mov64 w3, w0 +; CHECK: sub32 w3, w2 +; CHECK: stxw [r1 + 0], w3 +define dso_local i32 @test_load_sub_32(i32* nocapture %p, i32 %v) local_unnamed_addr { +entry: + %0 = atomicrmw sub i32* %p, i32 %v seq_cst + ret i32 %0 +} + +; CHECK-LABEL: test_load_sub_64 +; CHECK: ldxdw r0, [r1 + 0] +; CHECK: mov64 r3, r0 +; CHECK: sub64 r3, r2 +; CHECK: stxdw [r1 + 0], r3 +define dso_local i32 @test_load_sub_64(i64* nocapture %p, i64 %v) local_unnamed_addr { +entry: + %0 = atomicrmw sub i64* %p, i64 %v seq_cst + %conv = trunc i64 %0 to i32 + ret i32 %conv +} + +; CHECK-LABEL: test_xchg_32 +; CHECK: ldxw w0, [r1 + 0] +; CHECK: stxw [r1 + 0], w2 +define dso_local i32 @test_xchg_32(i32* nocapture %p, i32 %v) local_unnamed_addr { +entry: + %0 = atomicrmw xchg i32* %p, i32 %v seq_cst + ret i32 %0 +} + +; CHECK-LABEL: test_xchg_64 +; CHECK: ldxdw r0, [r1 + 0] +; CHECK: stxdw [r1 + 0], r2 +define dso_local i32 @test_xchg_64(i64* nocapture %p, i64 %v) local_unnamed_addr { +entry: + %0 = atomicrmw xchg i64* %p, i64 %v seq_cst + %conv = trunc i64 %0 to i32 + ret i32 %conv +} + +; CHECK-LABEL: test_cas_32 +; CHECK: ldxw w0, [r1 + 0] +; CHECK-NOT: mov64 r4, w0 +; CHECK-NOT: mov64 r2, w2 +; CHECK: jeq r0, r2, +; CHECK: mov64 w3, w0 +; CHECK: stxw [r1 + 0], w3 +define dso_local i32 @test_cas_32(i32* nocapture %p, i32 %old, i32 %new) local_unnamed_addr { +entry: + %0 = cmpxchg i32* %p, i32 %old, i32 %new seq_cst seq_cst + %1 = extractvalue { i32, i1 } %0, 0 + ret i32 %1 +} + +; CHECK-LABEL: test_cas_64 +; CHECK: ldxdw r0, [r1 + 0] +; CHECK: jeq r0, r2, +; CHECK: mov64 r3, r0 +; CHECK: stxdw [r1 + 0], r3 +define dso_local i64 @test_cas_64(i64* nocapture %p, i64 %old, i64 %new) local_unnamed_addr { +entry: + %0 = cmpxchg i64* %p, i64 %old, i64 %new seq_cst seq_cst + %1 = extractvalue { i64, i1 } %0, 0 + ret i64 %1 +} + +; CHECK-LABEL: test_load_and_32 +; CHECK: ldxw w0, [r1 + 0] +; CHECK: mov64 w3, w0 +; CHECK: and32 w3, w2 +; CHECK: stxw [r1 + 0], w3 +define dso_local i32 @test_load_and_32(i32* nocapture %p, i32 %v) local_unnamed_addr { +entry: + %0 = atomicrmw and i32* %p, i32 %v seq_cst + ret i32 %0 +} + +; CHECK-LABEL: test_load_and_64 +; CHECK: ldxdw r0, [r1 + 0] +; CHECK: mov64 r3, r0 +; CHECK: and64 r3, r2 +; CHECK: stxdw [r1 + 0], r3 +define dso_local i64 @test_load_and_64(i64* nocapture %p, i64 %v) local_unnamed_addr { +entry: + %0 = atomicrmw and i64* %p, i64 %v seq_cst + ret i64 %0 +} + +; CHECK-LABEL: test_load_nand_32 +; CHECK: ldxw w0, [r1 + 0] +; CHECK: mov64 w3, w0 +; CHECK: and32 w3, w2 +; CHECK: xor32 w3, -1 +; CHECK: stxw [r1 + 0], w3 +define dso_local i32 @test_load_nand_32(i32* nocapture %p, i32 %v) local_unnamed_addr { +entry: + %0 = atomicrmw nand i32* %p, i32 %v seq_cst + ret i32 %0 +} + +; CHECK-LABEL: test_load_nand_64 +; CHECK: ldxdw r0, [r1 + 0] +; CHECK: mov64 r3, r0 +; CHECK: and64 r3, r2 +; CHECK: xor64 r3, -1 +; CHECK: stxdw [r1 + 0], r3 +define dso_local i64 @test_load_nand_64(i64* nocapture %p, i64 %v) local_unnamed_addr { +entry: + %0 = atomicrmw nand i64* %p, i64 %v seq_cst + ret i64 %0 +} + +; CHECK-LABEL: test_load_or_32 +; CHECK: ldxw w0, [r1 + 0] +; CHECK: mov64 w3, w0 +; CHECK: or32 w3, w2 +; CHECK: stxw [r1 + 0], w3 +define dso_local i32 @test_load_or_32(i32* nocapture %p, i32 %v) local_unnamed_addr { +entry: + %0 = atomicrmw or i32* %p, i32 %v seq_cst + ret i32 %0 +} + +; CHECK-LABEL: test_load_or_64 +; CHECK: ldxdw r0, [r1 + 0] +; CHECK: mov64 r3, r0 +; CHECK: or64 r3, r2 +; CHECK: stxdw [r1 + 0], r3 +define dso_local i64 @test_load_or_64(i64* nocapture %p, i64 %v) local_unnamed_addr { +entry: + %0 = atomicrmw or i64* %p, i64 %v seq_cst + ret i64 %0 +} + +; CHECK-LABEL: test_load_xor_32 +; CHECK: ldxw w0, [r1 + 0] +; CHECK: mov64 w3, w0 +; CHECK: xor32 w3, w2 +; CHECK: stxw [r1 + 0], w3 +define dso_local i32 @test_load_xor_32(i32* nocapture %p, i32 %v) local_unnamed_addr { +entry: + %0 = atomicrmw xor i32* %p, i32 %v seq_cst + ret i32 %0 +} + +; CHECK-LABEL: test_load_xor_64 +; CHECK: ldxdw r0, [r1 + 0] +; CHECK: mov64 r3, r0 +; CHECK: xor64 r3, r2 +; CHECK: stxdw [r1 + 0], r3 +define dso_local i64 @test_load_xor_64(i64* nocapture %p, i64 %v) local_unnamed_addr { +entry: + %0 = atomicrmw xor i64* %p, i64 %v seq_cst + ret i64 %0 +} + +; CHECK-LABEL: test_min_32 +; CHECK: ldxw w0, [r1 + 0] +; CHECK: mov32 r4, w2 +; CHECK: mov32 r5, w0 +; CHECK: mov64 w3, w0 +; CHECK: jsgt r4, r5, LBB16_2 +; CHECK: mov64 w3, w2 +; CHECK: stxw [r1 + 0], w3 +define dso_local i32 @test_min_32(i32* nocapture %ptr, i32 %v) local_unnamed_addr #0 { +entry: + %0 = atomicrmw min i32* %ptr, i32 %v release, align 1 + ret i32 %0 +} + +; CHECK-LABEL: test_min_64 +; CHECK: ldxdw r0, [r1 + 0] +; CHECK: mov64 r3, r0 +; CHECK: jsgt r2, r0, +; CHECK: mov64 r3, r2 +; CHECK: stxdw [r1 + 0], r3 +define dso_local i64 @test_min_64(i64* nocapture %ptr, i64 %v) local_unnamed_addr #0 { +entry: + %0 = atomicrmw min i64* %ptr, i64 %v release, align 1 + ret i64 %0 +} + +; CHECK-LABEL: test_max_32 +; CHECK: ldxw w0, [r1 + 0] +; CHECK: mov32 r4, w0 +; CHECK: mov32 r5, w2 +; CHECK: mov64 w3, w0 +; CHECK: jsgt r4, r5, LBB18_2 +; CHECK: mov64 w3, w2 +; CHECK: stxw [r1 + 0], w3 +define dso_local i32 @test_max_32(i32* nocapture %ptr, i32 %v) local_unnamed_addr #0 { +entry: + %0 = atomicrmw max i32* %ptr, i32 %v release, align 1 + ret i32 %0 +} + +; CHECK-LABEL: test_max_64 +; CHECK: ldxdw r0, [r1 + 0] +; CHECK: mov64 r3, r0 +; CHECK: jsgt r0, r2, +; CHECK: mov64 r3, r2 +; CHECK: stxdw [r1 + 0], r3 +define dso_local i64 @test_max_64(i64* nocapture %ptr, i64 %v) local_unnamed_addr #0 { +entry: + %0 = atomicrmw max i64* %ptr, i64 %v release, align 1 + ret i64 %0 +} + +; CHECK-LABEL: test_umin_32 +; CHECK: ldxw w0, [r1 + 0] +; CHECK-NOT: mov64 r4, w2 +; CHECK-NOT: mov64 r5, w0 +; CHECK: mov64 w3, w0 +; CHECK: jgt r2, r0, +; CHECK: mov64 w3, w2 +; CHECK: stxw [r1 + 0], w3 +define dso_local i32 @test_umin_32(i32* nocapture %ptr, i32 %v) local_unnamed_addr #0 { +entry: + %0 = atomicrmw umin i32* %ptr, i32 %v release, align 1 + ret i32 %0 +} + +; CHECK-LABEL: test_umin_64 +; CHECK: ldxdw r0, [r1 + 0] +; CHECK: mov64 r3, r0 +; CHECK: jgt r2, r0, +; CHECK: mov64 r3, r2 +; CHECK: stxdw [r1 + 0], r3 +define dso_local i64 @test_umin_64(i64* nocapture %ptr, i64 %v) local_unnamed_addr #0 { +entry: + %0 = atomicrmw umin i64* %ptr, i64 %v release, align 1 + ret i64 %0 +} + +; CHECK-LABEL: test_umax_32 +; CHECK: ldxw w0, [r1 + 0] +; CHECK-NOT: mov64 r4, w0 +; CHECK-NOT: mov64 r4, w2 +; CHECK: mov64 w3, w0 +; CHECK: jgt r0, r2 +; CHECK: mov64 w3, w2 +; CHECK: stxw [r1 + 0], w3 +define dso_local i32 @test_umax_32(i32* nocapture %ptr, i32 %v) local_unnamed_addr #0 { +entry: + %0 = atomicrmw umax i32* %ptr, i32 %v release, align 1 + ret i32 %0 +} + +; CHECK-LABEL: test_umax_64 +; CHECK: ldxdw r0, [r1 + 0] +; CHECK: mov64 r3, r0 +; CHECK: jgt r0, r2, +; CHECK: mov64 r3, r2 +; CHECK: stxdw [r1 + 0], r3 +define dso_local i64 @test_umax_64(i64* nocapture %ptr, i64 %v) local_unnamed_addr #0 { +entry: + %0 = atomicrmw umax i64* %ptr, i64 %v release, align 1 + ret i64 %0 +} + +; CHECK-LABEL: test_load_64 +; CHECK: ldxdw r0, [r1 + 0] +; CHECK: mov64 r2, 0 +; CHECK: jeq r0, 0, LBB24_2 +; CHECK: mov64 r2, r0 +; CHECK: LBB24_2: +; CHECK: stxdw [r1 + 0], r2 +define dso_local i64 @test_load_64(ptr nocapture %p) local_unnamed_addr { +entry: + %0 = load atomic i64, ptr %p seq_cst, align 8 + ret i64 %0 +} + +; CHECK-LABEL: test_load_32 +; CHECK: ldxw w0, [r1 + 0] +; CHECK: mov32 w2, 0 +; CHECK: mov32 r3, w0 +; CHECK: jeq r3, 0, LBB25_2 +; CHECK: mov64 w2, w0 +; CHECK: LBB25_2: +; CHECK: stxw [r1 + 0], w2 +define dso_local i32 @test_load_32(ptr nocapture %p) local_unnamed_addr { +entry: + %0 = load atomic i32, ptr %p seq_cst, align 8 + ret i32 %0 +} + +; CHECK-LABEL: test_store_64 +; CHECK: stxdw [r1 + 0], r2 +define dso_local void @test_store_64(ptr nocapture %p, i64 %val) local_unnamed_addr { +entry: + store atomic i64 %val, ptr %p seq_cst, align 8 + ret void +} + +; CHECK-LABEL: test_store_32 +; CHECK: stxw [r1 + 0], w2 +define dso_local void @test_store_32(ptr nocapture %p, i32 %val) local_unnamed_addr { +entry: + store atomic i32 %val, ptr %p seq_cst, align 8 + ret void +} + +; CHECK-LABEL: test_weak_cas_32 +; CHECK: ldxw w4, [r1 + 0] +; CHECK-NOT: mov64 r5, w4 +; CHECK-NOT: mov64 r2, w2 +; CHECK: jeq r4, r2, +; CHECK: stxw [r1 + 0], w3 +define dso_local void @test_weak_cas_32(i32* nocapture %p, i32 %old, i32 %new) local_unnamed_addr { +entry: + cmpxchg weak i32* %p, i32 %old, i32 %new seq_cst seq_cst + ret void +} + +; CHECK-LABEL: test_weak_cas_64 +; CHECK: ldxdw r4, [r1 + 0] +; CHECK: jeq r4, r2, +; CHECK: mov64 r3, r4 +; CHECK: stxdw [r1 + 0], r3 +define dso_local void @test_weak_cas_64(i64* nocapture %p, i64 %old, i64 %new) local_unnamed_addr { +entry: + cmpxchg weak i64* %p, i64 %old, i64 %new seq_cst seq_cst + ret void +} \ No newline at end of file diff --git a/llvm/test/CodeGen/SBF/basictest.ll b/llvm/test/CodeGen/SBF/basictest.ll new file mode 100644 index 0000000000000..7af1db977e7ff --- /dev/null +++ b/llvm/test/CodeGen/SBF/basictest.ll @@ -0,0 +1,28 @@ +; RUN: llc < %s -march=sbf | FileCheck %s + +define i32 @test0(i32 %X) { + %tmp.1 = add i32 %X, 1 + ret i32 %tmp.1 +; CHECK-LABEL: test0: +; CHECK: add64 r0, 1 +} + +; CHECK-LABEL: store_imm: +; CHECK: stxw [r1 + 0], r{{[03]}} +; CHECK: stxw [r2 + 4], r{{[03]}} +define i32 @store_imm(i32* %a, i32* %b) { +entry: + store i32 0, i32* %a, align 4 + %0 = getelementptr inbounds i32, i32* %b, i32 1 + store i32 0, i32* %0, align 4 + ret i32 0 +} + +@G = external global i8 +define zeroext i8 @loadG() { + %tmp = load i8, i8* @G + ret i8 %tmp +; CHECK-LABEL: loadG: +; CHECK: lddw r1, G +; CHECK: ldxb r0, [r1 + 0] +} diff --git a/llvm/test/CodeGen/SBF/br_cc_sext.ll b/llvm/test/CodeGen/SBF/br_cc_sext.ll new file mode 100644 index 0000000000000..bca0722fa0163 --- /dev/null +++ b/llvm/test/CodeGen/SBF/br_cc_sext.ll @@ -0,0 +1,129 @@ +; RUN: llc -march=sbf -mattr=+alu32,+explicit-sext -verify-machineinstrs < %s | FileCheck %s + +; ModuleID = 'test.c' +source_filename = "test.c" +target datalayout = "e-m:e-p:64:64-i64:64-n32:64-S128" +target triple = "sbf" + +; Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none) +define dso_local noundef i32 @doThis(i32 noundef %a, i32 noundef %b) local_unnamed_addr #0 { +entry: + %rem = srem i32 %a, %b + ret i32 %rem +} + +; Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none) +define dso_local i32 @test_one(i32 noundef %a, i32 noundef %b, ptr %c) local_unnamed_addr #0 { +entry: +; Sign extension before comparison with immediate value +; CHECK-LABEL: test_one +; CHECK: mov32 r1, w1 +; CHECK: jeq r1, -1, LBB1_2 + %ld = load i32, ptr %c, align 4 + %cmp = icmp ult i32 %ld, -1 + br i1 %cmp, label %if.then, label %if.else + +if.then: ; preds = %entry + %add = add nsw i32 %a, 9 + br label %if.end + +if.else: ; preds = %entry + %rem.i = srem i32 %b, %a + %sub = sub nsw i32 9, %rem.i + br label %if.end + +if.end: ; preds = %if.else, %if.then + %f.0 = phi i32 [ %add, %if.then ], [ %sub, %if.else ] + %add1 = add nsw i32 %f.0, 90 + ret i32 %add1 +} + +; Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none) +define dso_local i32 @test_two(i32 noundef %a, i32 noundef %b, ptr %c) local_unnamed_addr #0 { +entry: +; Sign extension before comparison with immediate value +; CHECK-LABEL: test_two +; CHECK: mov32 r1, w1 +; CHECK: jsgt r1, -2, LBB2_2 + %ld = load i32, ptr %c, align 4 + %cmp = icmp slt i32 %ld, -1 + br i1 %cmp, label %if.then, label %if.else + +if.then: ; preds = %entry + %add = add nsw i32 %a, 9 + br label %if.end + +if.else: ; preds = %entry + %rem.i = srem i32 %b, %a + %sub = sub nsw i32 9, %rem.i + br label %if.end + +if.end: ; preds = %if.else, %if.then + %f.0 = phi i32 [ %add, %if.then ], [ %sub, %if.else ] + %add1 = add nsw i32 %f.0, 90 + ret i32 %add1 +} + +; Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none) +define dso_local i32 @test_three(i32 noundef %a, i32 noundef %b, ptr %c) local_unnamed_addr #0 { +entry: +; Sign extension for signed comparison +; CHECK-LABEL: test_three +; CHECK: mov32 r1, w2 +; CHECK: ldxw w3, [r3 + 0] +; CHECK: mov32 r3, w3 +; CHECK: jsge r3, r1, LBB3_2 + %ld = load i32, ptr %c, align 4 + %cmp = icmp slt i32 %ld, %b + br i1 %cmp, label %if.then, label %if.else + +if.then: ; preds = %entry + %add = add nsw i32 %a, 9 + br label %if.end + +if.else: ; preds = %entry + %rem.i = srem i32 %b, %a + %sub = sub nsw i32 9, %rem.i + br label %if.end + +if.end: ; preds = %if.else, %if.then + %f.0 = phi i32 [ %add, %if.then ], [ %sub, %if.else ] + %add1 = add nsw i32 %f.0, 90 + ret i32 %add1 +} + +; Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none) +define dso_local i32 @test_four(i32 noundef %a, i32 noundef %b, ptr %c) local_unnamed_addr #0 { +entry: +; Zero extension for unsigned comparison +; CHECK-LABEL: test_four +; CHECK: mov64 w0, w1 +; CHECK: ldxw w1, [r3 + 0] +; CHECK: jge r1, r2, LBB4_2 + %ld = load i32, ptr %c, align 4 + %cmp = icmp ult i32 %ld, %b + br i1 %cmp, label %if.then, label %if.else + +if.then: ; preds = %entry + %add = add nsw i32 %a, 9 + br label %if.end + +if.else: ; preds = %entry + %rem.i = srem i32 %b, %a + %sub = sub nsw i32 9, %rem.i + br label %if.end + +if.end: ; preds = %if.else, %if.then + %f.0 = phi i32 [ %add, %if.then ], [ %sub, %if.else ] + %add1 = add nsw i32 %f.0, 90 + ret i32 %add1 +} + +attributes #0 = { mustprogress nofree norecurse nosync nounwind willreturn memory(none) "frame-pointer"="all" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+solana" } + +!llvm.module.flags = !{!0, !1} +!llvm.ident = !{!2} + +!0 = !{i32 1, !"wchar_size", i32 4} +!1 = !{i32 7, !"frame-pointer", i32 2} +!2 = !{!"clang version 18.1.7 (https://github.com/solana-labs/llvm-project.git 9fd466387b898c6e320f31dbb8b7766507d1e6ae)"} diff --git a/llvm/test/CodeGen/SBF/branch_fold.ll b/llvm/test/CodeGen/SBF/branch_fold.ll new file mode 100644 index 0000000000000..d561c8020f649 --- /dev/null +++ b/llvm/test/CodeGen/SBF/branch_fold.ll @@ -0,0 +1,82 @@ +; RUN: llc -march=sbf -O3 < %s | FileCheck %s + +; ModuleID = 'pinocchio.2fd090a2518ac939-cgu.0' +source_filename = "pinocchio.2fd090a2518ac939-cgu.0" +target datalayout = "e-m:e-p:64:64-i64:64-n32:64-S128" +target triple = "sbf" + + +; Function Attrs: nofree noinline norecurse nosync nounwind memory(readwrite, inaccessiblemem: none) +define void @deserialize(ptr dead_on_unwind noalias nocapture noundef writable writeonly sret([24 x i8]) align 8 dereferenceable(24) %_0, ptr noundef %0, ptr noundef %1) unnamed_addr { +start: + %_4 = load i64, ptr %0, align 8 + %_7 = getelementptr inbounds i8, ptr %0, i64 8 + %_9.not = icmp eq i64 %_4, 0 + br i1 %_9.not, label %bb8, label %bb1 + +bb1: ; preds = %start + store ptr %_7, ptr %1, align 8 + %_16 = getelementptr inbounds i8, ptr %0, i64 10344 + %2 = getelementptr inbounds i8, ptr %0, i64 88 + %_21 = load i64, ptr %2, align 8 + %_18 = getelementptr inbounds i8, ptr %_16, i64 %_21 + %_24 = ptrtoint ptr %_18 to i64 + %_23 = add i64 %_24, 7 + %_22 = and i64 %_23, -8 + %3 = inttoptr i64 %_22 to ptr + %to_process.sroa.0.05 = add i64 %_4, -1 + %_26.not6 = icmp eq i64 %to_process.sroa.0.05, 0 + br i1 %_26.not6, label %bb8, label %bb3 + +bb8: ; preds = %bb2.backedge, %bb1, %start + %input.sroa.0.0 = phi ptr [ %_7, %start ], [ %3, %bb1 ], [ %input.sroa.0.1.be, %bb2.backedge ] + %_55 = load i64, ptr %input.sroa.0.0, align 8 + %_58 = getelementptr inbounds i8, ptr %input.sroa.0.0, i64 8 + %_65 = getelementptr inbounds i8, ptr %_58, i64 %_55 + store ptr %_65, ptr %_0, align 8 + %4 = getelementptr inbounds i8, ptr %_0, i64 8 + store ptr %_58, ptr %4, align 8 + %5 = getelementptr inbounds i8, ptr %_0, i64 16 + store i64 %_55, ptr %5, align 8 + ret void + +; CHECK: LBB0_4: +; CHECK-NOT: jeq r4, 0, LBB0_7 +; CHECK-NOT: ja LBB0_3 +; CHECK: jne r4, 0, LBB0_4 + +bb3: ; preds = %bb1, %bb2.backedge + %to_process.sroa.0.09 = phi i64 [ %to_process.sroa.0.0, %bb2.backedge ], [ %to_process.sroa.0.05, %bb1 ] + %input.sroa.0.18 = phi ptr [ %input.sroa.0.1.be, %bb2.backedge ], [ %3, %bb1 ] + %accounts.sroa.0.07 = phi ptr [ %_28, %bb2.backedge ], [ %1, %bb1 ] + %_28 = getelementptr inbounds i8, ptr %accounts.sroa.0.07, i64 8 + %_35 = load i8, ptr %input.sroa.0.18, align 8 + %_34.not = icmp eq i8 %_35, -1 + br i1 %_34.not, label %bb5, label %bb4 + +bb5: ; preds = %bb3 + store ptr %input.sroa.0.18, ptr %_28, align 8 + %_44 = getelementptr inbounds i8, ptr %input.sroa.0.18, i64 10336 + %6 = getelementptr inbounds i8, ptr %input.sroa.0.18, i64 80 + %_49 = load i64, ptr %6, align 8 + %_46 = getelementptr inbounds i8, ptr %_44, i64 %_49 + %_52 = ptrtoint ptr %_46 to i64 + %_51 = add i64 %_52, 7 + %_50 = and i64 %_51, -8 + %7 = inttoptr i64 %_50 to ptr + br label %bb2.backedge + +bb2.backedge: ; preds = %bb5, %bb4 + %input.sroa.0.1.be = phi ptr [ %_32, %bb4 ], [ %7, %bb5 ] + %to_process.sroa.0.0 = add i64 %to_process.sroa.0.09, -1 + %_26.not = icmp eq i64 %to_process.sroa.0.0, 0 + br i1 %_26.not, label %bb8, label %bb3 + +bb4: ; preds = %bb3 + %_32 = getelementptr inbounds i8, ptr %input.sroa.0.18, i64 8 + %_40 = zext i8 %_35 to i64 + %_39 = getelementptr inbounds ptr, ptr %1, i64 %_40 + store ptr %_39, ptr %_28, align 8 + br label %bb2.backedge +} + diff --git a/llvm/test/CodeGen/SBF/byval.ll b/llvm/test/CodeGen/SBF/byval.ll new file mode 100644 index 0000000000000..652b2a88a6ea5 --- /dev/null +++ b/llvm/test/CodeGen/SBF/byval.ll @@ -0,0 +1,31 @@ +; RUN: llc -O2 -march=sbf < %s | FileCheck %s + +%struct.S = type { [10 x i32] } + +; Function Attrs: nounwind uwtable +define void @bar(i32 %a) #0 { +; CHECK-LABEL: bar: +; CHECK: lddw r2, 8589934593 +; CHECK: stxdw [r10 - 40], r2 +; CHECK: mov64 r2, r10 +; CHECK: add64 r2, -40 +; CHECK: call foo +entry: + %.compoundliteral = alloca %struct.S, align 8 + %arrayinit.begin = getelementptr inbounds %struct.S, %struct.S* %.compoundliteral, i64 0, i32 0, i64 0 + store i32 1, i32* %arrayinit.begin, align 8 + %arrayinit.element = getelementptr inbounds %struct.S, %struct.S* %.compoundliteral, i64 0, i32 0, i64 1 + store i32 2, i32* %arrayinit.element, align 4 + %arrayinit.element2 = getelementptr inbounds %struct.S, %struct.S* %.compoundliteral, i64 0, i32 0, i64 2 + store i32 3, i32* %arrayinit.element2, align 8 + %arrayinit.start = getelementptr inbounds %struct.S, %struct.S* %.compoundliteral, i64 0, i32 0, i64 3 + %scevgep4 = bitcast i32* %arrayinit.start to i8* + call void @llvm.memset.p0i8.i64(i8* align 4 %scevgep4, i8 0, i64 28, i1 false) + call void @foo(i32 %a, %struct.S* byval(%struct.S) align 8 %.compoundliteral) #3 + ret void +} + +declare void @foo(i32, %struct.S* byval(%struct.S) align 8) #1 + +; Function Attrs: nounwind +declare void @llvm.memset.p0i8.i64(i8* nocapture, i8, i64, i1) #3 diff --git a/llvm/test/CodeGen/SBF/call_internal.ll b/llvm/test/CodeGen/SBF/call_internal.ll new file mode 100644 index 0000000000000..d4e1dc7844fd4 --- /dev/null +++ b/llvm/test/CodeGen/SBF/call_internal.ll @@ -0,0 +1,49 @@ +; RUN: llc < %s -march=sbf --show-mc-encoding | FileCheck --check-prefixes=CHECK-ASM,CHECK-ASM-V0 %s +; RUN: llc -march=sbf --filetype=obj -o - %s | llvm-objdump -d - | FileCheck --check-prefixes=CHECK-OBJ,CHECK-OBJ-V0 %s +; RUN: llc < %s -march=sbf -mcpu=v3 --show-mc-encoding | FileCheck --check-prefixes=CHECK-ASM,CHECK-ASM-V3 %s +; RUN: llc -march=sbf -mcpu=v3 --filetype=obj -o - %s | llvm-objdump -d - +; | FileCheck --check-prefixes=CHECK-OBJ,CHECK-OBJ-V3 %s + +@.str = private unnamed_addr constant [5 x i8] c"foo\0A\00", align 1 + +; Function Attrs: mustprogress nofree noinline norecurse nosync nounwind willreturn memory(none) +define dso_local i64 @sum(i64 noundef %a, i64 noundef %b) local_unnamed_addr #0 { +entry: + %add = add i64 %b, %a + ret i64 %add +} + +; Function Attrs: nounwind +define dso_local i64 @entrypoint(ptr noundef %input) local_unnamed_addr #1 { +entry: +; CHECK-ASM-V0: call 1811268606 # encoding: [0x85,0x00,0x00,0x00,0xfe,0xc3,0xf5,0x6b] +; CHECK-ASM-V3: syscall 1811268606 # encoding: [0x95,0x00,0x00,0x00,0xfe,0xc3,0xf5,0x6b] + +; CHECK-OBJ-V0: 85 00 00 00 fe c3 f5 6b call 0x6bf5c3fe +; CHECK-OBJ-V3: 95 00 00 00 fe c3 f5 6b syscall 0x6bf5c3fe + + tail call void inttoptr (i64 1811268606 to ptr)(ptr noundef nonnull @.str, i64 noundef 4) #3 + %add.ptr = getelementptr inbounds i8, ptr %input, i64 4 + +; CHECK-ASM: call invoke_c # encoding: [0x85'A',A,A,A,0x00,0x00,0x00,0x00] +; CHECK-ASM: fixup A - offset: 0, value: invoke_c, kind: FK_PCRel_4 +; CHECK-OBJ: 85 10 00 00 ff ff ff ff call -0x1 + + tail call void @invoke_c(ptr noundef %input) #3 + %0 = load i64, ptr %input, align 8, !tbaa !3 + %1 = load i64, ptr %add.ptr, align 8, !tbaa !3 + +; CHECK-ASM: call sum # encoding: [0x85'A',A,A,A,0x00,0x00,0x00,0x00] +; CHECK-ASM: fixup A - offset: 0, value: sum, kind: FK_PCRel_4 +; CHECK-OBJ: 85 10 00 00 ff ff ff ff call -0x1 + + %call = tail call i64 @sum(i64 noundef %0, i64 noundef %1) + ret i64 %call +} + +declare dso_local void @invoke_c(ptr noundef) local_unnamed_addr #2 + + +!3 = !{!4, !4, i64 0} +!4 = !{!"long", !5, i64 0} +!5 = !{!"omnipotent char"} \ No newline at end of file diff --git a/llvm/test/CodeGen/SBF/callx.ll b/llvm/test/CodeGen/SBF/callx.ll new file mode 100644 index 0000000000000..5923cdc155843 --- /dev/null +++ b/llvm/test/CodeGen/SBF/callx.ll @@ -0,0 +1,24 @@ +; RUN: llc < %s -march=sbf --show-mc-encoding \ +; RUN: | FileCheck %s -check-prefixes=CHECK-v0 +; RUN: llc < %s -march=sbf --mcpu=v2 --show-mc-encoding \ +; RUN: | FileCheck %s -check-prefixes=CHECK-v2 +; source: +; int test(int (*f)(void)) { return f(); } + +; Function Attrs: nounwind +define dso_local i32 @test(i32 ()* nocapture %f) local_unnamed_addr #0 { +entry: + %call = tail call i32 %f() #1 +; CHECK-v0: callx r{{[0-9]+}} # encoding: [0x8d,0x00,0x00,0x00,0x0{{[0-9]|a|b}},0x00,0x00,0x00] +; CHECK-v2: callx r{{[0-9]+}} # encoding: [0x8d,0x{{[0-9]}}0,0x00,0x00,0x00,0x00,0x00,0x00] + ret i32 %call +} + +attributes #0 = { nounwind "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" } +attributes #1 = { nounwind } + +!llvm.module.flags = !{!0} +!llvm.ident = !{!1} + +!0 = !{i32 1, !"wchar_size", i32 4} +!1 = !{!"clang version 10.0.0 (https://github.com/llvm/llvm-project.git 7015a5c54b53d8d2297a3aa38bc32aab167bdcfc)"} diff --git a/llvm/test/CodeGen/SBF/cc_args.ll b/llvm/test/CodeGen/SBF/cc_args.ll new file mode 100644 index 0000000000000..8803133f57406 --- /dev/null +++ b/llvm/test/CodeGen/SBF/cc_args.ll @@ -0,0 +1,109 @@ +; RUN: llc < %s -march=sbf -show-mc-encoding | FileCheck --check-prefix=CHECK-v0 %s +; RUN: llc < %s -march=sbf -mcpu=v2 -show-mc-encoding | FileCheck --check-prefix=CHECK-v2 %s + +define void @test() #0 { +entry: +; CHECK-LABEL: test: + +; CHECK-v0: mov64 r1, 123 # encoding: [0xb7,0x01,0x00,0x00,0x7b,0x00,0x00,0x00] +; CHECK-v2: mov32 w1, 123 +; CHECK-v0: call f_i16 + call void @f_i16(i16 123) + +; CHECK-v0: mov64 r1, 12345678 # encoding: [0xb7,0x01,0x00,0x00,0x4e,0x61,0xbc,0x00] +; CHECK-v2: mov32 w1, 12345678 +; CHECK-v0: call f_i32 + call void @f_i32(i32 12345678) + +; 72623859790382856 = 0x0102030405060708 +; 84281096 = 0x05060708 +; 16909060 = 0x01020304 + +; CHECK-v2: mov32 r1, 84281096 # encoding: [0xb4,0x01,0x00,0x00,0x08,0x07,0x06,0x05] +; CHECK-v2: hor64 r1, 16909060 # encoding: [0xf7,0x01,0x00,0x00,0x04,0x03,0x02,0x01] + +; CHECK-v0: lddw r1, 72623859790382856 # encoding: [0x18,0x01,0x00,0x00,0x08,0x07,0x06,0x05,0x00,0x00,0x00,0x00,0x04,0x03,0x02,0x01] +; CHECK-v0: call f_i64 + call void @f_i64(i64 72623859790382856) + +; CHECK-v0: mov64 r1, 1234 +; CHECK-v0: mov64 r2, 5678 +; CHECK-v0: call f_i32_i32 + call void @f_i32_i32(i32 1234, i32 5678) + +; CHECK-v0: mov64 r1, 2 +; CHECK-v0: mov64 r2, 3 +; CHECK-v0: mov64 r3, 4 +; CHECK-v0: call f_i16_i32_i16 + call void @f_i16_i32_i16(i16 2, i32 3, i16 4) + +; 7262385979038285 = 0x0019CD1A00809A4D +; 8428109 = 0x00809A4D +; 1690906 = 0x0019CD1A +; CHECK-v2: mov32 r2, 8428109 +; CHECK-v2: hor64 r2, 1690906 + +; CHECK-v0: mov64 r1, 5 +; CHECK-v0: lddw r2, 7262385979038285 +; CHECK-v0: mov64 r3, 6 +; CHECK-v0: call f_i16_i64_i16 + call void @f_i16_i64_i16(i16 5, i64 7262385979038285, i16 6) + + ret void +} + +@g_i16 = common global i16 0, align 2 +@g_i32 = common global i32 0, align 2 +@g_i64 = common global i64 0, align 4 + +define void @f_i16(i16 %a) #0 { +; CHECK-v0: f_i16: +; CHECK-v0: stxh [r2 + 0], r1 # encoding: [0x6b,0x12,0x00,0x00,0x00,0x00,0x00,0x00] + store volatile i16 %a, i16* @g_i16, align 2 + ret void +} + +define void @f_i32(i32 %a) #0 { +; CHECK-v0: f_i32: +; CHECK-v0: stxw [r2 + 0], r1 # encoding: [0x63,0x12,0x00,0x00,0x00,0x00,0x00,0x00] + store volatile i32 %a, i32* @g_i32, align 2 + ret void +} + +define void @f_i64(i64 %a) #0 { +; CHECK-v0: f_i64: +; CHECK-v0: stxdw [r2 + 0], r1 # encoding: [0x7b,0x12,0x00,0x00,0x00,0x00,0x00,0x00] + store volatile i64 %a, i64* @g_i64, align 2 + ret void +} + +define void @f_i32_i32(i32 %a, i32 %b) #0 { +; CHECK-v0: f_i32_i32: +; CHECK-v0: stxw [r3 + 0], r1 + store volatile i32 %a, i32* @g_i32, align 4 +; CHECK-v0: stxw [r3 + 0], r2 + store volatile i32 %b, i32* @g_i32, align 4 + ret void +} + +define void @f_i16_i32_i16(i16 %a, i32 %b, i16 %c) #0 { +; CHECK-v0: f_i16_i32_i16: +; CHECK-v0: stxh [r4 + 0], r1 + store volatile i16 %a, i16* @g_i16, align 2 +; CHECK-v0: stxw [r1 + 0], r2 + store volatile i32 %b, i32* @g_i32, align 4 +; CHECK-v0: stxh [r4 + 0], r3 + store volatile i16 %c, i16* @g_i16, align 2 + ret void +} + +define void @f_i16_i64_i16(i16 %a, i64 %b, i16 %c) #0 { +; CHECK-v0: f_i16_i64_i16: +; CHECK-v0: stxh [r4 + 0], r1 + store volatile i16 %a, i16* @g_i16, align 2 +; CHECK-v0: stxdw [r1 + 0], r2 # encoding: [0x7b,0x21,0x00,0x00,0x00,0x00,0x00,0x00] + store volatile i64 %b, i64* @g_i64, align 8 +; CHECK-v0: stxh [r4 + 0], r3 + store volatile i16 %c, i16* @g_i16, align 2 + ret void +} diff --git a/llvm/test/CodeGen/SBF/cc_ret.ll b/llvm/test/CodeGen/SBF/cc_ret.ll new file mode 100644 index 0000000000000..12a22e2cb5ace --- /dev/null +++ b/llvm/test/CodeGen/SBF/cc_ret.ll @@ -0,0 +1,48 @@ +; RUN: llc < %s -march=sbf | FileCheck %s + +define void @test() #0 { +entry: +; CHECK: test: + +; CHECK: call f_i16 +; CHECK: stxh [r1 + 0], r0 + %0 = call i16 @f_i16() + store volatile i16 %0, i16* @g_i16 + +; CHECK: call f_i32 +; CHECK: stxw [r1 + 0], r0 + %1 = call i32 @f_i32() + store volatile i32 %1, i32* @g_i32 + +; CHECK: call f_i64 +; CHECK: stxdw [r1 + 0], r0 + %2 = call i64 @f_i64() + store volatile i64 %2, i64* @g_i64 + + ret void +} + +@g_i16 = common global i16 0, align 2 +@g_i32 = common global i32 0, align 2 +@g_i64 = common global i64 0, align 2 + +define i16 @f_i16() #0 { +; CHECK: f_i16: +; CHECK: mov64 r0, 1 +; CHECK: exit + ret i16 1 +} + +define i32 @f_i32() #0 { +; CHECK: f_i32: +; CHECK: mov64 r0, 16909060 +; CHECK: exit + ret i32 16909060 +} + +define i64 @f_i64() #0 { +; CHECK: f_i64: +; CHECK: lddw r0, 72623859790382856 +; CHECK: exit + ret i64 72623859790382856 +} diff --git a/llvm/test/CodeGen/SBF/cmp.ll b/llvm/test/CodeGen/SBF/cmp.ll new file mode 100644 index 0000000000000..7deb32aea1c44 --- /dev/null +++ b/llvm/test/CodeGen/SBF/cmp.ll @@ -0,0 +1,119 @@ +; RUN: llc < %s -march=sbf | FileCheck %s + +; Function Attrs: nounwind readnone uwtable +define signext i8 @foo_cmp1(i8 signext %a, i8 signext %b) #0 { + %1 = icmp sgt i8 %a, %b + br i1 %1, label %2, label %4 + +;