diff --git a/.github/workflows/clang-tests.yml b/.github/workflows/clang-tests.yml index d37637e4b9271..94756447d86f3 100644 --- a/.github/workflows/clang-tests.yml +++ b/.github/workflows/clang-tests.yml @@ -23,7 +23,7 @@ jobs: matrix: os: - ubuntu-latest - - windows-latest + # - windows-latest - macOS-latest steps: - name: Setup Windows @@ -39,5 +39,5 @@ jobs: - name: Test clang uses: llvm/actions/build-test-llvm-project@main with: - cmake_args: -G Ninja -DLLVM_ENABLE_PROJECTS="clang" -DCMAKE_BUILD_TYPE=Release + cmake_args: -G Ninja -DLLVM_ENABLE_PROJECTS="clang" -DCMAKE_BUILD_TYPE=Release -DLLVM_TARGETS_TO_BUILD='X86;BPF' build_target: check-clang diff --git a/.github/workflows/lld-tests.yml b/.github/workflows/lld-tests.yml index 1e5540d2fc4de..d040216dc26ca 100644 --- a/.github/workflows/lld-tests.yml +++ b/.github/workflows/lld-tests.yml @@ -23,7 +23,7 @@ jobs: matrix: os: - ubuntu-latest - - windows-latest + # - windows-latest - macOS-latest steps: - name: Setup Windows @@ -39,5 +39,5 @@ jobs: - name: Test lld uses: llvm/actions/build-test-llvm-project@main with: - cmake_args: -G Ninja -DLLVM_ENABLE_PROJECTS="lld" -DCMAKE_BUILD_TYPE=Release + cmake_args: -G Ninja -DLLVM_ENABLE_PROJECTS="lld" -DCMAKE_BUILD_TYPE=Release -DLLVM_TARGETS_TO_BUILD='X86;BPF' build_target: check-lld diff --git a/.github/workflows/llvm-tests.yml b/.github/workflows/llvm-tests.yml index bb011c0dafbb2..5815fe6805037 100644 --- a/.github/workflows/llvm-tests.yml +++ b/.github/workflows/llvm-tests.yml @@ -21,7 +21,7 @@ jobs: matrix: os: - ubuntu-latest - - windows-latest + # - windows-latest - macOS-latest steps: - name: Setup Windows @@ -37,9 +37,11 @@ jobs: - name: Test llvm uses: llvm/actions/build-test-llvm-project@main with: - cmake_args: -G Ninja -DCMAKE_BUILD_TYPE=Release + cmake_args: -G Ninja -DCMAKE_BUILD_TYPE=Release -DLLVM_ENABLE_PROJECTS='clang;lld' -DLLVM_TARGETS_TO_BUILD='X86;BPF' + # disable ABI compare abi-dump-setup: + if: false runs-on: ubuntu-latest outputs: BASELINE_REF: ${{ steps.vars.outputs.BASELINE_REF }} @@ -70,6 +72,7 @@ jobs: fi abi-dump: + if: false needs: abi-dump-setup runs-on: ubuntu-latest strategy: @@ -140,6 +143,7 @@ jobs: path: llvm.symbols abi-compare: + if: false runs-on: ubuntu-latest needs: - abi-dump-setup diff --git a/README.md b/README.md index 6e02ee378eb35..eb4df48ddd6b3 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,9 @@ +# 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/solana-labs/rust) + +--- + # The LLVM Compiler Infrastructure This directory and its sub-directories contain source code for LLVM, diff --git a/clang/lib/Basic/Targets/BPF.h b/clang/lib/Basic/Targets/BPF.h index 43e55dfbfb2b2..fd481b413250f 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; static const Builtin::Info BuiltinInfo[]; 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,24 @@ class LLVM_LIBRARY_VISIBILITY BPFTargetInfo : public TargetInfo { IntMaxType = SignedLong; Int64Type = SignedLong; RegParmMax = 5; + 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; @@ -48,7 +63,8 @@ class LLVM_LIBRARY_VISIBILITY BPFTargetInfo : public TargetInfo { MacroBuilder &Builder) const override; bool hasFeature(StringRef Feature) const override { - return Feature == "bpf" || Feature == "alu32" || Feature == "dwarfris"; + return Feature == "bpf" || Feature == "alu32" || Feature == "dwarfris" || + Feature == "solana"; } void setFeatureEnabled(llvm::StringMap &Features, StringRef Name, @@ -96,6 +112,8 @@ class LLVM_LIBRARY_VISIBILITY BPFTargetInfo : public TargetInfo { StringRef CPUName(Name); return isValidCPUName(CPUName); } + + bool hasExtIntType() const override { return HasSolanaFeature; } }; } // namespace targets } // namespace clang diff --git a/clang/lib/Driver/CMakeLists.txt b/clang/lib/Driver/CMakeLists.txt index aeffcf0bb43ae..c07e4922ea4d8 100644 --- a/clang/lib/Driver/CMakeLists.txt +++ b/clang/lib/Driver/CMakeLists.txt @@ -26,6 +26,7 @@ add_clang_library(clangDriver ToolChain.cpp ToolChains/Arch/AArch64.cpp ToolChains/Arch/ARM.cpp + ToolChains/Arch/BPF.cpp ToolChains/Arch/Mips.cpp ToolChains/Arch/PPC.cpp ToolChains/Arch/RISCV.cpp diff --git a/clang/lib/Driver/ToolChains/Arch/BPF.cpp b/clang/lib/Driver/ToolChains/Arch/BPF.cpp new file mode 100644 index 0000000000000..05d1c8e763448 --- /dev/null +++ b/clang/lib/Driver/ToolChains/Arch/BPF.cpp @@ -0,0 +1,53 @@ +//===--- BPF.cpp - Tools Implementations ------------------------*- 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 "BPF.h" +#include "clang/Driver/Driver.h" +#include "clang/Driver/DriverDiagnostic.h" +#include "clang/Driver/Options.h" +#include "llvm/Option/ArgList.h" + +using namespace clang::driver; +using namespace clang::driver::tools; +using namespace clang; +using namespace llvm::opt; + +static bool DecodeBPFFeatures(const Driver &D, StringRef text, + std::vector &Features) { + SmallVector Split; + text.split(Split, StringRef("+"), -1, false); + + for (StringRef Feature : Split) { + if (Feature == "solana") + Features.push_back("+solana"); + else + return false; + } + return true; +} + +static bool +getBPFArchFeaturesFromMarch(const Driver &D, StringRef March, + const ArgList &Args, + std::vector &Features) { + std::string MarchLowerCase = March.lower(); + std::pair Split = StringRef(MarchLowerCase).split("+"); + + return (Split.first == "bpfel" || Split.first == "bpfeb") && + (Split.second.size() == 0 || DecodeBPFFeatures(D, Split.second, Features)); +} + +void bpf::getBPFTargetFeatures(const Driver &D, const ArgList &Args, + std::vector &Features) { + Arg *A; + bool success = true; + if ((A = Args.getLastArg(options::OPT_march_EQ))) + success = getBPFArchFeaturesFromMarch(D, A->getValue(), Args, Features); + if (!success) + D.Diag(diag::err_drv_clang_unsupported) << A->getAsString(Args); +} diff --git a/clang/lib/Driver/ToolChains/Arch/BPF.h b/clang/lib/Driver/ToolChains/Arch/BPF.h new file mode 100644 index 0000000000000..cc5e1de285e7b --- /dev/null +++ b/clang/lib/Driver/ToolChains/Arch/BPF.h @@ -0,0 +1,31 @@ +//===--- BPF.h - BPF-specific Tool Helpers ----------------------*- 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_CLANG_LIB_DRIVER_TOOLCHAINS_ARCH_BPF_H +#define LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_ARCH_BPF_H + +#include "clang/Driver/Driver.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Option/Option.h" +#include +#include + +namespace clang { +namespace driver { +namespace tools { +namespace bpf { + +void getBPFTargetFeatures(const Driver &D, const llvm::opt::ArgList &Args, + std::vector &Features); + +} // end namespace bpf +} // namespace tools +} // end namespace driver +} // end namespace clang + +#endif // LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_ARCH_BPF_H diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp index 1976b48e0f6a4..ad7ab988830f3 100644 --- a/clang/lib/Driver/ToolChains/Clang.cpp +++ b/clang/lib/Driver/ToolChains/Clang.cpp @@ -10,6 +10,7 @@ #include "AMDGPU.h" #include "Arch/AArch64.h" #include "Arch/ARM.h" +#include "Arch/BPF.h" #include "Arch/Mips.h" #include "Arch/PPC.h" #include "Arch/RISCV.h" @@ -345,6 +346,10 @@ static void getTargetFeatures(const Driver &D, const llvm::Triple &Triple, case llvm::Triple::aarch64_be: aarch64::getAArch64TargetFeatures(D, Triple, Args, Features); break; + case llvm::Triple::bpfeb: + case llvm::Triple::bpfel: + bpf::getBPFTargetFeatures(D, Args, Features); + break; case llvm::Triple::x86: case llvm::Triple::x86_64: x86::getX86TargetFeatures(D, Triple, Args, Features); diff --git a/clang/test/CodeGen/ext-int-cc.c b/clang/test/CodeGen/ext-int-cc.c index 954ebf231218b..ce43083523568 100644 --- a/clang/test/CodeGen/ext-int-cc.c +++ b/clang/test/CodeGen/ext-int-cc.c @@ -28,6 +28,7 @@ // RUN: %clang_cc1 -triple arm64_32-apple-ios -O3 -disable-llvm-passes -emit-llvm -o - %s | FileCheck %s --check-prefixes=AARCH64 // RUN: %clang_cc1 -triple arm64_32-apple-ios -target-abi darwinpcs -O3 -disable-llvm-passes -emit-llvm -o - %s | FileCheck %s --check-prefixes=AARCH64DARWIN // RUN: %clang_cc1 -triple arm -O3 -disable-llvm-passes -emit-llvm -o - %s | FileCheck %s --check-prefixes=ARM +// RUN: %clang_cc1 -triple bpf -target-feature +solana -O3 -disable-llvm-passes -emit-llvm -o - %s | FileCheck %s --check-prefixes=BPF // Make sure 128 and 64 bit versions are passed like integers, and that >128 // is passed indirectly. @@ -59,6 +60,7 @@ void ParamPassing(_ExtInt(129) a, _ExtInt(128) b, _ExtInt(64) c) {} // AARCH64: define{{.*}} void @ParamPassing(i129* byval(i129) align 8 %{{.+}}, i128 %{{.+}}, i64 %{{.+}}) // AARCH64DARWIN: define{{.*}} void @ParamPassing(i129* byval(i129) align 8 %{{.+}}, i128 %{{.+}}, i64 %{{.+}}) // ARM: define{{.*}} arm_aapcscc void @ParamPassing(i129* byval(i129) align 8 %{{.+}}, i128* byval(i128) align 8 %{{.+}}, i64 %{{.+}}) +// BPF: define{{.*}} void @ParamPassing(i129* byval(i129) align 8 %{{.+}}, i128 %{{.+}}, i64 %{{.+}}) void ParamPassing2(_ExtInt(129) a, _ExtInt(127) b, _ExtInt(63) c) {} // LIN64: define{{.*}} void @ParamPassing2(i129* byval(i129) align 8 %{{.+}}, i64 %{{.+}}, i64 %{{.+}}, i64 %{{.+}}) @@ -88,6 +90,7 @@ void ParamPassing2(_ExtInt(129) a, _ExtInt(127) b, _ExtInt(63) c) {} // AARCH64: define{{.*}} void @ParamPassing2(i129* byval(i129) align 8 %{{.+}}, i127 %{{.+}}, i63 %{{.+}}) // AARCH64DARWIN: define{{.*}} void @ParamPassing2(i129* byval(i129) align 8 %{{.+}}, i127 %{{.+}}, i63 %{{.+}}) // ARM: define{{.*}} arm_aapcscc void @ParamPassing2(i129* byval(i129) align 8 %{{.+}}, i127* byval(i127) align 8 %{{.+}}, i63 %{{.+}}) +// BPF: define{{.*}} void @ParamPassing2(i129* byval(i129) align 8 %{{.+}}, i127 %{{.+}}, i63 %{{.+}}) // Make sure we follow the signext rules for promotable integer types. void ParamPassing3(_ExtInt(15) a, _ExtInt(31) b) {} @@ -118,6 +121,7 @@ void ParamPassing3(_ExtInt(15) a, _ExtInt(31) b) {} // AARCH64: define{{.*}} void @ParamPassing3(i15 %{{.+}}, i31 %{{.+}}) // AARCH64DARWIN: define{{.*}} void @ParamPassing3(i15 signext %{{.+}}, i31 signext %{{.+}}) // ARM: define{{.*}} arm_aapcscc void @ParamPassing3(i15 signext %{{.+}}, i31 signext %{{.+}}) +// BPF: define{{.*}} void @ParamPassing3(i15 signext %{{.+}}, i31 signext %{{.+}}) _ExtInt(63) ReturnPassing(){} // LIN64: define{{.*}} i64 @ReturnPassing( @@ -147,6 +151,7 @@ _ExtInt(63) ReturnPassing(){} // AARCH64: define{{.*}} i63 @ReturnPassing( // AARCH64DARWIN: define{{.*}} i63 @ReturnPassing( // ARM: define{{.*}} arm_aapcscc i63 @ReturnPassing( +// BPF: define{{.*}} i63 @ReturnPassing( _ExtInt(64) ReturnPassing2(){} // LIN64: define{{.*}} i64 @ReturnPassing2( @@ -176,6 +181,7 @@ _ExtInt(64) ReturnPassing2(){} // AARCH64: define{{.*}} i64 @ReturnPassing2( // AARCH64DARWIN: define{{.*}} i64 @ReturnPassing2( // ARM: define{{.*}} arm_aapcscc i64 @ReturnPassing2( +// BPF: define{{.*}} i64 @ReturnPassing2( _ExtInt(127) ReturnPassing3(){} // LIN64: define{{.*}} { i64, i64 } @ReturnPassing3( @@ -207,6 +213,7 @@ _ExtInt(127) ReturnPassing3(){} // AARCH64: define{{.*}} i127 @ReturnPassing3( // AARCH64DARWIN: define{{.*}} i127 @ReturnPassing3( // ARM: define{{.*}} arm_aapcscc void @ReturnPassing3(i127* noalias sret +// BPF: define{{.*}} i127 @ReturnPassing3( _ExtInt(128) ReturnPassing4(){} // LIN64: define{{.*}} { i64, i64 } @ReturnPassing4( @@ -236,6 +243,7 @@ _ExtInt(128) ReturnPassing4(){} // AARCH64: define{{.*}} i128 @ReturnPassing4( // AARCH64DARWIN: define{{.*}} i128 @ReturnPassing4( // ARM: define{{.*}} arm_aapcscc void @ReturnPassing4(i128* noalias sret +// BPF: define{{.*}} i128 @ReturnPassing4( _ExtInt(129) ReturnPassing5(){} // LIN64: define{{.*}} void @ReturnPassing5(i129* noalias sret @@ -265,6 +273,7 @@ _ExtInt(129) ReturnPassing5(){} // AARCH64: define{{.*}} void @ReturnPassing5(i129* noalias sret // AARCH64DARWIN: define{{.*}} void @ReturnPassing5(i129* noalias sret // ARM: define{{.*}} arm_aapcscc void @ReturnPassing5(i129* noalias sret +// BPF: define{{.*}} void @ReturnPassing5(i129* noalias sret // SparcV9 is odd in that it has a return-size limit of 256, not 128 or 64 // like other platforms, so test to make sure this behavior will still work. diff --git a/clang/test/CodeGen/target-data.c b/clang/test/CodeGen/target-data.c index d12facda24a9d..af1186fc11bb2 100644 --- a/clang/test/CodeGen/target-data.c +++ b/clang/test/CodeGen/target-data.c @@ -283,6 +283,14 @@ // 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 bpfel -target-feature +solana -o - -emit-llvm %s | \ +// RUN: FileCheck %s -check-prefix=BPFELSOL +// BPFELSOL: target datalayout = "e-m:e-p:64:64-i64:64-n32:64-S128" + +// RUN: %clang_cc1 -triple bpfeb -target-feature +solana -o - -emit-llvm %s | \ +// RUN: FileCheck %s -check-prefix=BPFEBSOL +// BPFEBSOL: 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/compiler-rt/lib/builtins/bpf/udivmodti4.c b/compiler-rt/lib/builtins/bpf/udivmodti4.c new file mode 100644 index 0000000000000..eb54334d8041a --- /dev/null +++ b/compiler-rt/lib/builtins/bpf/udivmodti4.c @@ -0,0 +1,195 @@ +//===-- udivmodti4.c - Implement __udivmodti4 -----------------------------===// +// +// 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 __udivmodti4 for the compiler_rt library. +// +//===----------------------------------------------------------------------===// + +#include "../int_lib.h" + +#ifdef CRT_HAS_128BIT + +// Effects: if rem != 0, *rem = a % b +// Returns: a / b + +// Translated from Figure 3-40 of The PowerPC Compiler Writer's Guide + +COMPILER_RT_ABI tu_int __udivmodti4(tu_int a, tu_int b, tu_int *rem) { + const unsigned n_udword_bits = sizeof(du_int) * CHAR_BIT; + const unsigned n_utword_bits = sizeof(tu_int) * CHAR_BIT; + utwords n; + n.all = a; + utwords d; + d.all = b; + utwords q; + utwords r; + unsigned sr; + // special cases, X is unknown, K != 0 + if (n.s.high == 0) { + if (d.s.high == 0) { + // 0 X + // --- + // 0 X + if (rem) + *rem = n.s.low % d.s.low; + return n.s.low / d.s.low; + } + // 0 X + // --- + // K X + if (rem) + *rem = n.s.low; + return 0; + } + // n.s.high != 0 + if (d.s.low == 0) { + if (d.s.high == 0) { + // K X + // --- + // 0 0 + if (rem) + *rem = n.s.high % d.s.low; + return n.s.high / d.s.low; + } + // d.s.high != 0 + if (n.s.low == 0) { + // K 0 + // --- + // K 0 + if (rem) { + r.s.high = n.s.high % d.s.high; + r.s.low = 0; + *rem = r.all; + } + return n.s.high / d.s.high; + } + // K K + // --- + // K 0 + if ((d.s.high & (d.s.high - 1)) == 0) /* if d is a power of 2 */ { + if (rem) { + r.s.low = n.s.low; + r.s.high = n.s.high & (d.s.high - 1); + *rem = r.all; + } + return n.s.high >> __builtin_ctzll(d.s.high); + } + // K K + // --- + // K 0 + sr = __builtin_clzll(d.s.high) - __builtin_clzll(n.s.high); + // 0 <= sr <= n_udword_bits - 2 or sr large + if (sr > n_udword_bits - 2) { + if (rem) + *rem = n.all; + return 0; + } + ++sr; + // 1 <= sr <= n_udword_bits - 1 + // q.all = n.all << (n_utword_bits - sr); + q.s.low = 0; + q.s.high = n.s.low << (n_udword_bits - sr); + // r.all = n.all >> sr; + r.s.high = n.s.high >> sr; + r.s.low = (n.s.high << (n_udword_bits - sr)) | (n.s.low >> sr); + } else /* d.s.low != 0 */ { + if (d.s.high == 0) { + // K X + // --- + // 0 K + if ((d.s.low & (d.s.low - 1)) == 0) /* if d is a power of 2 */ { + if (rem) + *rem = n.s.low & (d.s.low - 1); + if (d.s.low == 1) + return n.all; + sr = __builtin_ctzll(d.s.low); + q.s.high = n.s.high >> sr; + q.s.low = (n.s.high << (n_udword_bits - sr)) | (n.s.low >> sr); + return q.all; + } + // K X + // --- + // 0 K + sr = 1 + n_udword_bits + __builtin_clzll(d.s.low) - + __builtin_clzll(n.s.high); + // 2 <= sr <= n_utword_bits - 1 + // q.all = n.all << (n_utword_bits - sr); + // r.all = n.all >> sr; + if (sr == n_udword_bits) { + q.s.low = 0; + q.s.high = n.s.low; + r.s.high = 0; + r.s.low = n.s.high; + } else if (sr < n_udword_bits) /* 2 <= sr <= n_udword_bits - 1 */ { + q.s.low = 0; + q.s.high = n.s.low << (n_udword_bits - sr); + r.s.high = n.s.high >> sr; + r.s.low = (n.s.high << (n_udword_bits - sr)) | (n.s.low >> sr); + } else /* n_udword_bits + 1 <= sr <= n_utword_bits - 1 */ { + q.s.low = n.s.low << (n_utword_bits - sr); + q.s.high = (n.s.high << (n_utword_bits - sr)) | + (n.s.low >> (sr - n_udword_bits)); + r.s.high = 0; + r.s.low = n.s.high >> (sr - n_udword_bits); + } + } else { + // K X + // --- + // K K + sr = __builtin_clzll(d.s.high) - __builtin_clzll(n.s.high); + // 0 <= sr <= n_udword_bits - 1 or sr large + if (sr > n_udword_bits - 1) { + if (rem) + *rem = n.all; + return 0; + } + ++sr; + // 1 <= sr <= n_udword_bits + // q.all = n.all << (n_utword_bits - sr); + // r.all = n.all >> sr; + q.s.low = 0; + if (sr == n_udword_bits) { + q.s.high = n.s.low; + r.s.high = 0; + r.s.low = n.s.high; + } else { + r.s.high = n.s.high >> sr; + r.s.low = (n.s.high << (n_udword_bits - sr)) | (n.s.low >> sr); + q.s.high = n.s.low << (n_udword_bits - sr); + } + } + } + // Not a special case + // q and r are initialized with: + // q.all = n.all << (n_utword_bits - sr); + // r.all = n.all >> sr; + // 1 <= sr <= n_utword_bits - 1 + su_int carry = 0; + for (; sr > 0; --sr) { + // r:q = ((r:q) << 1) | carry + r.s.high = (r.s.high << 1) | (r.s.low >> (n_udword_bits - 1)); + r.s.low = (r.s.low << 1) | (q.s.high >> (n_udword_bits - 1)); + q.s.high = (q.s.high << 1) | (q.s.low >> (n_udword_bits - 1)); + q.s.low = (q.s.low << 1) | carry; + // carry = 0; + // if (r.all >= d.all) + // { + // r.all -= d.all; + // carry = 1; + // } + const ti_int s = (ti_int)(d.all - r.all - 1) >> (n_utword_bits - 1); + carry = s & 1; + r.all -= d.all & s; + } + q.all = (q.all << 1) | carry; + if (rem) + *rem = r.all; + return q.all; +} + +#endif // CRT_HAS_128BIT diff --git a/lld/COFF/Driver.cpp b/lld/COFF/Driver.cpp index 96ac7957f5576..49cae54c3155e 100644 --- a/lld/COFF/Driver.cpp +++ b/lld/COFF/Driver.cpp @@ -1200,13 +1200,6 @@ Optional getReproduceFile(const opt::InputArgList &args) { void LinkerDriver::linkerMain(ArrayRef argsArr) { ScopedTimer rootTimer(Timer::root()); - // Needed for LTO. - InitializeAllTargetInfos(); - InitializeAllTargets(); - InitializeAllTargetMCs(); - InitializeAllAsmParsers(); - InitializeAllAsmPrinters(); - // If the first command line argument is "/lib", link.exe acts like lib.exe. // We call our own implementation of lib.exe that understands bitcode files. if (argsArr.size() > 1 && StringRef(argsArr[1]).equals_lower("/lib")) { diff --git a/lld/ELF/Arch/BPF.cpp b/lld/ELF/Arch/BPF.cpp new file mode 100644 index 0000000000000..5611692d28590 --- /dev/null +++ b/lld/ELF/Arch/BPF.cpp @@ -0,0 +1,85 @@ +//===- BPF.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 BPF final : public TargetInfo { +public: + BPF(); + RelExpr getRelExpr(RelType type, const Symbol &s, + const uint8_t *loc) const override; + RelType getDynRel(RelType type) const override; + void relocate(uint8_t *loc, const Relocation &rel, uint64_t val) const override; +}; +} // namespace + +BPF::BPF() { + noneRel = R_BPF_NONE; + relativeRel = R_BPF_64_RELATIVE; + symbolicRel = R_BPF_64_64; +} + +RelExpr BPF::getRelExpr(RelType type, const Symbol &s, + const uint8_t *loc) const { + switch (type) { + case R_BPF_64_32: + return R_PC; + case R_BPF_64_64: + return R_ABS; + default: + error(getErrorLocation(loc) + "unrecognized reloc " + toString(type)); + } + return R_NONE; +} + +RelType BPF::getDynRel(RelType type) const { + return type; +} + +void BPF::relocate(uint8_t *loc, const Relocation &rel, uint64_t val) const { + switch (rel.type) { + case R_BPF_64_32: { + // Relocation of a symbol + write32le(loc + 4, ((val - 8) / 8) & 0xFFFFFFFF); + break; + } + case R_BPF_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; + } + default: + error(getErrorLocation(loc) + "unrecognized reloc " + toString(rel.type)); + } +} + +TargetInfo *getBPFTargetInfo() { + static BPF target; + return ⌖ +} + +} // namespace elf +} // namespace lld diff --git a/lld/ELF/CMakeLists.txt b/lld/ELF/CMakeLists.txt index f85d0fb9f55e3..00031c23b499e 100644 --- a/lld/ELF/CMakeLists.txt +++ b/lld/ELF/CMakeLists.txt @@ -8,6 +8,7 @@ add_lld_library(lldELF Arch/AMDGPU.cpp Arch/ARM.cpp Arch/AVR.cpp + Arch/BPF.cpp Arch/Hexagon.cpp Arch/Mips.cpp Arch/MipsArchTree.cpp diff --git a/lld/ELF/Driver.cpp b/lld/ELF/Driver.cpp index 3b2a8ba192933..ce6c6ab8632bc 100644 --- a/lld/ELF/Driver.cpp +++ b/lld/ELF/Driver.cpp @@ -295,17 +295,6 @@ void LinkerDriver::addLibrary(StringRef name) { error("unable to find library -l" + name, ErrorTag::LibNotFound, {name}); } -// 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(); -} - // Some command line options or some combinations of them are not allowed. // This function checks for such errors. static void checkOptions() { @@ -536,7 +525,6 @@ void LinkerDriver::linkerMain(ArrayRef argsArr) { { llvm::TimeTraceScope timeScope("ExecuteLinker"); - initLLVM(); createFiles(args); if (errorCount()) return; diff --git a/lld/ELF/Target.cpp b/lld/ELF/Target.cpp index cb816d8ed12d1..51b0b0c7f92f2 100644 --- a/lld/ELF/Target.cpp +++ b/lld/ELF/Target.cpp @@ -60,6 +60,8 @@ TargetInfo *elf::getTarget() { return getARMTargetInfo(); case EM_AVR: return getAVRTargetInfo(); + case EM_BPF: + return getBPFTargetInfo(); case EM_HEXAGON: return getHexagonTargetInfo(); case EM_MIPS: diff --git a/lld/ELF/Target.h b/lld/ELF/Target.h index 68b6c5d2ca351..d761435af355e 100644 --- a/lld/ELF/Target.h +++ b/lld/ELF/Target.h @@ -174,6 +174,7 @@ TargetInfo *getAArch64TargetInfo(); TargetInfo *getAMDGPUTargetInfo(); TargetInfo *getARMTargetInfo(); TargetInfo *getAVRTargetInfo(); +TargetInfo *getBPFTargetInfo(); TargetInfo *getHexagonTargetInfo(); TargetInfo *getMSP430TargetInfo(); TargetInfo *getPPC64TargetInfo(); diff --git a/lld/tools/lld/lld.cpp b/lld/tools/lld/lld.cpp index 77d7792451f24..d8a0fa22eab7e 100644 --- a/lld/tools/lld/lld.cpp +++ b/lld/tools/lld/lld.cpp @@ -40,6 +40,7 @@ #include "llvm/Support/Path.h" #include "llvm/Support/PluginLoader.h" #include "llvm/Support/Signals.h" +#include "llvm/Support/TargetSelect.h" #include #if !defined(_MSC_VER) && !defined(__MINGW32__) @@ -141,10 +142,22 @@ static Flavor parseFlavor(std::vector &v) { return parseProgname(arg0); } +// 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(); +} + /// Universal linker main(). This linker emulates the gnu, darwin, or /// windows linker based on the argv[0] or -flavor option. static int lldMain(int argc, const char **argv, llvm::raw_ostream &stdoutOS, llvm::raw_ostream &stderrOS, bool exitEarly = true) { + initLLVM(); std::vector args(argv, argv + argc); switch (parseFlavor(args)) { case Gnu: diff --git a/lld/wasm/Driver.cpp b/lld/wasm/Driver.cpp index 830e4bf1744ff..c14dbb8f8e3fc 100644 --- a/lld/wasm/Driver.cpp +++ b/lld/wasm/Driver.cpp @@ -55,17 +55,6 @@ enum { #undef OPTION }; -// 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(); -} - class LinkerDriver { public: void linkerMain(ArrayRef argsArr); @@ -98,7 +87,6 @@ bool link(ArrayRef args, bool canExitEarly, raw_ostream &stdoutOS, config = make(); symtab = make(); - initLLVM(); LinkerDriver().linkerMain(args); // Exit immediately if we don't need to return to the caller. diff --git a/llvm/include/llvm/ADT/Triple.h b/llvm/include/llvm/ADT/Triple.h index eed315c929adf..ccc8ae4a3fe47 100644 --- a/llvm/include/llvm/ADT/Triple.h +++ b/llvm/include/llvm/ADT/Triple.h @@ -735,6 +735,11 @@ class Triple { : PointerWidth == 64; } + /// Tests whether the target is BPF (little and big endian). + bool isBPF() const { + return getArch() == Triple::bpfel || getArch() == Triple::bpfeb; + } + /// Tests whether the target is MIPS 32-bit (little and big endian). bool isMIPS32() const { return getArch() == Triple::mips || getArch() == Triple::mipsel; diff --git a/llvm/include/llvm/BinaryFormat/ELFRelocs/BPF.def b/llvm/include/llvm/BinaryFormat/ELFRelocs/BPF.def index 5dd7f70b6963a..83e4d60832c73 100644 --- a/llvm/include/llvm/BinaryFormat/ELFRelocs/BPF.def +++ b/llvm/include/llvm/BinaryFormat/ELFRelocs/BPF.def @@ -5,4 +5,5 @@ // No relocation ELF_RELOC(R_BPF_NONE, 0) ELF_RELOC(R_BPF_64_64, 1) +ELF_RELOC(R_BPF_64_RELATIVE, 8) // B + A ELF_RELOC(R_BPF_64_32, 10) diff --git a/llvm/lib/Analysis/TargetLibraryInfo.cpp b/llvm/lib/Analysis/TargetLibraryInfo.cpp index 7e90e8ca2948c..2db35e0fafef9 100644 --- a/llvm/lib/Analysis/TargetLibraryInfo.cpp +++ b/llvm/lib/Analysis/TargetLibraryInfo.cpp @@ -559,6 +559,12 @@ static void initialize(TargetLibraryInfoImpl &TLI, const Triple &T, TLI.setUnavailable(LibFunc_vec_free); } + if (T.isBPF()) { + TLI.setUnavailable(LibFunc_rust_alloc); + TLI.setUnavailable(LibFunc_rust_dealloc); + TLI.setUnavailable(LibFunc_rust_realloc); + } + TLI.addVectorizableFunctionsFromVecLib(ClVectorLibrary); } diff --git a/llvm/lib/Target/BPF/BPF.td b/llvm/lib/Target/BPF/BPF.td index fad966ff5a137..38f033b800187 100644 --- a/llvm/lib/Target/BPF/BPF.td +++ b/llvm/lib/Target/BPF/BPF.td @@ -32,6 +32,9 @@ def ALU32 : SubtargetFeature<"alu32", "HasAlu32", "true", def DwarfRIS: SubtargetFeature<"dwarfris", "UseDwarfRIS", "true", "Disable MCAsmInfo DwarfUsesRelocationsAcrossSections">; +def FeatureSolana : SubtargetFeature<"solana", "IsSolana", "true", + "Enable Solana extensions">; + def BPFInstPrinter : AsmWriter { string AsmWriterClassName = "InstPrinter"; bit isMCAsmWriter = 1; diff --git a/llvm/lib/Target/BPF/BPFCallingConv.td b/llvm/lib/Target/BPF/BPFCallingConv.td index ef4ef1930aa8f..42953984fbec9 100644 --- a/llvm/lib/Target/BPF/BPFCallingConv.td +++ b/llvm/lib/Target/BPF/BPFCallingConv.td @@ -25,6 +25,15 @@ def CC_BPF64 : CallingConv<[ CCAssignToStack<8, 8> ]>; +def CC_BPF64_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_BPF32 : CallingConv<[ CCIfType<[i32], CCAssignToRegWithShadow<[W0], [R0]>>, @@ -45,4 +54,15 @@ def CC_BPF32 : CallingConv<[ CCAssignToStack<8, 8> ]>; +def CC_BPF32_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/BPF/BPFISelLowering.cpp b/llvm/lib/Target/BPF/BPFISelLowering.cpp index 3322b8d93b3a6..48294d940151f 100644 --- a/llvm/lib/Target/BPF/BPFISelLowering.cpp +++ b/llvm/lib/Target/BPF/BPFISelLowering.cpp @@ -13,6 +13,7 @@ #include "BPFISelLowering.h" #include "BPF.h" +#include "BPFRegisterInfo.h" #include "BPFSubtarget.h" #include "BPFTargetMachine.h" #include "llvm/CodeGen/CallingConvLower.h" @@ -55,7 +56,7 @@ static void fail(const SDLoc &DL, SelectionDAG &DAG, const char *Msg, BPFTargetLowering::BPFTargetLowering(const TargetMachine &TM, const BPFSubtarget &STI) - : TargetLowering(TM) { + : TargetLowering(TM), Subtarget(&STI) { // Set up the register classes. addRegisterClass(MVT::i64, &BPF::GPRRegClass); @@ -82,6 +83,9 @@ BPFTargetLowering::BPFTargetLowering(const TargetMachine &TM, if (VT == MVT::i32 && !STI.getHasAlu32()) continue; + if (Subtarget->isSolana()) { + setOperationAction(ISD::SDIV, VT, Expand); + } setOperationAction(ISD::SDIVREM, VT, Expand); setOperationAction(ISD::UDIVREM, VT, Expand); setOperationAction(ISD::SREM, VT, Expand); @@ -108,10 +112,17 @@ BPFTargetLowering::BPFTargetLowering(const TargetMachine &TM, STI.getHasJmp32() ? Custom : Promote); } - setOperationAction(ISD::CTTZ, MVT::i64, Custom); - setOperationAction(ISD::CTLZ, MVT::i64, Custom); - setOperationAction(ISD::CTTZ_ZERO_UNDEF, MVT::i64, Custom); - setOperationAction(ISD::CTLZ_ZERO_UNDEF, MVT::i64, Custom); + if (Subtarget->isSolana()) { + setOperationAction(ISD::CTTZ, MVT::i64, Expand); + setOperationAction(ISD::CTLZ, MVT::i64, Expand); + setOperationAction(ISD::CTTZ_ZERO_UNDEF, MVT::i64, Expand); + setOperationAction(ISD::CTLZ_ZERO_UNDEF, MVT::i64, Expand); + } else { + setOperationAction(ISD::CTTZ, MVT::i64, Custom); + setOperationAction(ISD::CTLZ, MVT::i64, Custom); + setOperationAction(ISD::CTTZ_ZERO_UNDEF, MVT::i64, Custom); + setOperationAction(ISD::CTLZ_ZERO_UNDEF, MVT::i64, Custom); + } setOperationAction(ISD::SIGN_EXTEND_INREG, MVT::i1, Expand); setOperationAction(ISD::SIGN_EXTEND_INREG, MVT::i8, Expand); @@ -164,6 +175,19 @@ BPFTargetLowering::BPFTargetLowering(const TargetMachine &TM, HasAlu32 = STI.getHasAlu32(); HasJmp32 = STI.getHasJmp32(); HasJmpExt = STI.getHasJmpExt(); + BPFRegisterInfo::FrameLength = STI.isSolana() ? 4096 : 512; +} + +bool BPFTargetLowering::allowsMisalignedMemoryAccesses( + EVT VT, unsigned, unsigned, MachineMemOperand::Flags, bool *Fast) const { + if (!VT.isSimple()) { + return false; + } + bool isSolana = Subtarget->isSolana(); + if (isSolana && Fast) { + *Fast = true; + } + return isSolana; } bool BPFTargetLowering::isOffsetFoldingLegal(const GlobalAddressSDNode *GA) const { @@ -254,11 +278,17 @@ SDValue BPFTargetLowering::LowerFormalArguments( // Assign locations to all of the incoming arguments. SmallVector ArgLocs; CCState CCInfo(CallConv, IsVarArg, MF, ArgLocs, *DAG.getContext()); - CCInfo.AnalyzeFormalArguments(Ins, getHasAlu32() ? CC_BPF32 : CC_BPF64); + if (Subtarget->isSolana() && Ins.size() > MaxArgs) { + // Pass args 1-4 via registers, remaining args via stack, referenced via BPF::R5 + CCInfo.AnalyzeFormalArguments(Ins, getHasAlu32() ? CC_BPF32_X : CC_BPF64_X); + } else { + // Pass all args via registers + CCInfo.AnalyzeFormalArguments(Ins, getHasAlu32() ? CC_BPF32 : CC_BPF64); + } for (auto &VA : ArgLocs) { if (VA.isRegLoc()) { - // Arguments passed in registers + // Argument passed in registers EVT RegVT = VA.getLocVT(); MVT::SimpleValueType SimpleTy = RegVT.getSimpleVT().SimpleTy; switch (SimpleTy) { @@ -274,7 +304,7 @@ SDValue BPFTargetLowering::LowerFormalArguments( RegInfo.addLiveIn(VA.getLocReg(), VReg); SDValue ArgValue = DAG.getCopyFromReg(Chain, DL, VReg, RegVT); - // If this is an value that has been promoted to wider types, insert an + // 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, @@ -288,18 +318,38 @@ SDValue BPFTargetLowering::LowerFormalArguments( InVals.push_back(ArgValue); - break; + break; } + } else if (Subtarget->isSolana()) { + // Argument passed via stack + assert(VA.isMemLoc() && "Should be isMemLoc"); + + EVT PtrVT = DAG.getTargetLoweringInfo().getPointerTy(DAG.getDataLayout()); + EVT LocVT = VA.getLocVT(); + + // Arguments relative to BPF::R5 + unsigned reg = MF.addLiveIn(BPF::R5, &BPF::GPRRegClass); + SDValue Const = DAG.getConstant(BPFRegisterInfo::FrameLength - VA.getLocMemOffset(), DL, MVT::i64); + SDValue 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(), 0); + InVals.push_back(SDV); } else { fail(DL, DAG, "defined with too many args"); InVals.push_back(DAG.getConstant(0, DL, VA.getLocVT())); } } - if (IsVarArg || MF.getFunction().hasStructRetAttr()) { + if (Subtarget->isSolana()) { + if (IsVarArg) { + fail(DL, DAG, "Functions with VarArgs are not supported"); + assert(false); + } + } else if (IsVarArg || MF.getFunction().hasStructRetAttr()) { fail(DL, DAG, "functions with VarArgs or StructRet are not supported"); } + return Chain; } @@ -332,20 +382,27 @@ SDValue BPFTargetLowering::LowerCall(TargetLowering::CallLoweringInfo &CLI, // Analyze operands of the call, assigning locations to each operand. SmallVector ArgLocs; CCState CCInfo(CallConv, IsVarArg, MF, ArgLocs, *DAG.getContext()); - - CCInfo.AnalyzeCallOperands(Outs, getHasAlu32() ? CC_BPF32 : CC_BPF64); + if (Subtarget->isSolana() && Outs.size() > MaxArgs) { + // Pass args 1-4 via registers, remaining args via stack, referenced via BPF::R5 + CCInfo.AnalyzeCallOperands(Outs, getHasAlu32() ? CC_BPF32_X : CC_BPF64_X); + } else { + // Pass all args via registers + CCInfo.AnalyzeCallOperands(Outs, getHasAlu32() ? CC_BPF32 : CC_BPF64); + } unsigned NumBytes = CCInfo.getNextStackOffset(); - if (Outs.size() > MaxArgs) - fail(CLI.DL, DAG, "too many args to ", Callee); + if (!Subtarget->isSolana()) { + if (Outs.size() > MaxArgs) + fail(CLI.DL, DAG, "too many args to ", Callee); - for (auto &Arg : Outs) { - ISD::ArgFlagsTy Flags = Arg.Flags; - if (!Flags.isByVal()) - continue; + for (auto &Arg : Outs) { + ISD::ArgFlagsTy Flags = Arg.Flags; + if (!Flags.isByVal()) + continue; - fail(CLI.DL, DAG, "pass by value not supported ", Callee); + fail(CLI.DL, DAG, "pass by value not supported ", Callee); + } } auto PtrVT = getPointerTy(MF.getDataLayout()); @@ -354,9 +411,9 @@ SDValue BPFTargetLowering::LowerCall(TargetLowering::CallLoweringInfo &CLI, SmallVector, MaxArgs> RegsToPass; // Walk arg assignments - for (unsigned i = 0, - e = std::min(static_cast(ArgLocs.size()), MaxArgs); - i != e; ++i) { + bool HasStackArgs = false; + unsigned e, i, ae = ArgLocs.size(); + for (i = 0, e = (Subtarget->isSolana()) ? ae : std::min(ae, MaxArgs); i != e; ++i) { CCValAssign &VA = ArgLocs[i]; SDValue Arg = OutVals[i]; @@ -377,6 +434,11 @@ SDValue BPFTargetLowering::LowerCall(TargetLowering::CallLoweringInfo &CLI, break; } + if (Subtarget->isSolana() && VA.isMemLoc()) { + HasStackArgs = true; + break; + } + // Push arguments into RegsToPass vector if (VA.isRegLoc()) RegsToPass.push_back(std::make_pair(VA.getLocReg(), Arg)); @@ -384,10 +446,34 @@ SDValue BPFTargetLowering::LowerCall(TargetLowering::CallLoweringInfo &CLI, llvm_unreachable("call arg pass bug"); } + if (HasStackArgs) { + SDValue FramePtr = DAG.getCopyFromReg(Chain, CLI.DL, BPF::R10, getPointerTy(MF.getDataLayout())); + + // Stack arguments have to be walked in reverse order by inserting + // chained stores, this ensures their order is not changed by the scheduler + // and that the push instruction sequence generated is correct, otherwise they + // can be freely intermixed. + for (ae = i, i = ArgLocs.size(); i != ae; --i) { + unsigned Loc = i - 1; + CCValAssign &VA = ArgLocs[Loc]; + SDValue Arg = OutVals[Loc]; + + assert(VA.isMemLoc()); + + EVT PtrVT = DAG.getTargetLoweringInfo().getPointerTy(DAG.getDataLayout()); + SDValue Const = DAG.getConstant(BPFRegisterInfo::FrameLength - VA.getLocMemOffset(), CLI.DL, MVT::i64); + SDValue PtrOff = DAG.getNode(ISD::SUB, CLI.DL, PtrVT, FramePtr, Const); + Chain = DAG.getStore(Chain, CLI.DL, Arg, PtrOff, MachinePointerInfo()); + } + + // Pass the current stack frame pointer via BPF::R5 + Chain = DAG.getCopyToReg(Chain, CLI.DL, BPF::R5, FramePtr); + } + SDValue InFlag; // Build a sequence of copy-to-reg nodes chained together with token chain and - // flag operands which copy the outgoing args into registers. The InFlag in + // flag operands which copy the outgoing args into registers. The InFlag is // necessary since all emitted instructions must be stuck together. for (auto &Reg : RegsToPass) { Chain = DAG.getCopyToReg(Chain, CLI.DL, Reg.first, Reg.second, InFlag); @@ -402,9 +488,12 @@ SDValue BPFTargetLowering::LowerCall(TargetLowering::CallLoweringInfo &CLI, G->getOffset(), 0); } else if (ExternalSymbolSDNode *E = dyn_cast(Callee)) { Callee = DAG.getTargetExternalSymbol(E->getSymbol(), PtrVT, 0); - fail(CLI.DL, DAG, Twine("A call to built-in function '" - + StringRef(E->getSymbol()) - + "' is not supported.")); + // This is not a warning but info, will be resolved on load + if (!Subtarget->isSolana()) { + fail(CLI.DL, DAG, Twine("A call to built-in function '" + + StringRef(E->getSymbol()) + + "' remains unresolved")); + } } // Returns a chain & a flag for retval copy to use. @@ -418,6 +507,10 @@ SDValue BPFTargetLowering::LowerCall(TargetLowering::CallLoweringInfo &CLI, for (auto &Reg : RegsToPass) Ops.push_back(DAG.getRegister(Reg.first, Reg.second.getValueType())); + if (HasStackArgs) { + Ops.push_back(DAG.getRegister(BPF::R5, MVT::i64)); + } + if (InFlag.getNode()) Ops.push_back(InFlag); @@ -436,6 +529,18 @@ SDValue BPFTargetLowering::LowerCall(TargetLowering::CallLoweringInfo &CLI, InVals); } +bool BPFTargetLowering::CanLowerReturn( + CallingConv::ID CallConv, MachineFunction &MF, bool IsVarArg, + const SmallVectorImpl &Outs, LLVMContext &Context) const { + if (!Subtarget->isSolana()) { + return true; + } + // 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_BPF32 : RetCC_BPF64); +} + SDValue BPFTargetLowering::LowerReturn(SDValue Chain, CallingConv::ID CallConv, bool IsVarArg, @@ -451,7 +556,12 @@ BPFTargetLowering::LowerReturn(SDValue Chain, CallingConv::ID CallConv, // CCState - Info about the registers and stack slot. CCState CCInfo(CallConv, IsVarArg, MF, RVLocs, *DAG.getContext()); - if (MF.getFunction().getReturnType()->isAggregateType()) { + if (Subtarget->isSolana()) { + if (Outs.size() > 1) { + fail(DL, DAG, "Only a single return supported"); + assert(false); + } + } else if (MF.getFunction().getReturnType()->isAggregateType()) { fail(DL, DAG, "only integer returns supported"); return DAG.getNode(Opc, DL, MVT::Other, Chain); } @@ -494,7 +604,12 @@ SDValue BPFTargetLowering::LowerCallResult( SmallVector RVLocs; CCState CCInfo(CallConv, IsVarArg, MF, RVLocs, *DAG.getContext()); - if (Ins.size() >= 2) { + if (Subtarget->isSolana()) { + if (Ins.size() > 1) { + fail(DL, DAG, "Only a single return supported"); + assert(false); + } + } else if (Ins.size() >= 2) { fail(DL, DAG, "only small returns supported"); for (unsigned i = 0, e = Ins.size(); i != e; ++i) InVals.push_back(DAG.getConstant(0, DL, Ins[i].VT)); diff --git a/llvm/lib/Target/BPF/BPFISelLowering.h b/llvm/lib/Target/BPF/BPFISelLowering.h index cc752dda87b02..647d476dd0849 100644 --- a/llvm/lib/Target/BPF/BPFISelLowering.h +++ b/llvm/lib/Target/BPF/BPFISelLowering.h @@ -33,9 +33,14 @@ enum NodeType : unsigned { } class BPFTargetLowering : public TargetLowering { + const BPFSubtarget *Subtarget; public: explicit BPFTargetLowering(const TargetMachine &TM, const BPFSubtarget &STI); + bool allowsMisalignedMemoryAccesses(EVT VT, unsigned, unsigned, + MachineMemOperand::Flags, + bool *) const override; + // Provide custom lowering hooks for some operations. SDValue LowerOperation(SDValue Op, SelectionDAG &DAG) const override; @@ -94,6 +99,11 @@ class BPFTargetLowering : public TargetLowering { const SDLoc &DL, SelectionDAG &DAG, SmallVectorImpl &InVals) const override; + bool CanLowerReturn(CallingConv::ID CallConv, MachineFunction &MF, + bool IsVarArg, + const SmallVectorImpl &Outs, + LLVMContext &Context) const override; + SDValue LowerReturn(SDValue Chain, CallingConv::ID CallConv, bool IsVarArg, const SmallVectorImpl &Outs, const SmallVectorImpl &OutVals, const SDLoc &DL, diff --git a/llvm/lib/Target/BPF/BPFRegisterInfo.cpp b/llvm/lib/Target/BPF/BPFRegisterInfo.cpp index 8de81a469b844..96bd1e213e753 100644 --- a/llvm/lib/Target/BPF/BPFRegisterInfo.cpp +++ b/llvm/lib/Target/BPF/BPFRegisterInfo.cpp @@ -26,6 +26,8 @@ #include "BPFGenRegisterInfo.inc" using namespace llvm; +unsigned BPFRegisterInfo::FrameLength = 512; + BPFRegisterInfo::BPFRegisterInfo() : BPFGenRegisterInfo(BPF::R0) {} @@ -43,13 +45,29 @@ BitVector BPFRegisterInfo::getReservedRegs(const MachineFunction &MF) const { static void WarnSize(int Offset, MachineFunction &MF, DebugLoc& DL) { - if (Offset <= -512) { - const Function &F = MF.getFunction(); - DiagnosticInfoUnsupported DiagStackSize(F, - "Looks like the BPF stack limit of 512 bytes is exceeded. " + static Function *OldMF = nullptr; + if (&(MF.getFunction()) == OldMF) { + return; + } + OldMF = &(MF.getFunction()); + int MaxOffset = -1 * BPFRegisterInfo::FrameLength; + if (Offset <= MaxOffset) { + if (MF.getSubtarget().isSolana()) { + dbgs() << "Error:"; + if (DL) { + dbgs() << " "; + DL.print(dbgs()); + } + dbgs() << " Function " << MF.getFunction().getName() << " Stack offset of " << Offset + << " exceeded max offset of " << MaxOffset << " by " + << -(Offset - MaxOffset) << " bytes, please minimize large stack variables\n"; + } else { + DiagnosticInfoUnsupported DiagStackSize(MF.getFunction(), + "BPF stack limit of 512 bytes is exceeded. " "Please move large on stack variables into BPF per-cpu array map.\n", DL); - F.getContext().diagnose(DiagStackSize); + MF.getFunction().getContext().diagnose(DiagStackSize); + } } } @@ -68,7 +86,7 @@ void BPFRegisterInfo::eliminateFrameIndex(MachineBasicBlock::iterator II, /* try harder to get some debug loc */ for (auto &I : MBB) if (I.getDebugLoc()) { - DL = I.getDebugLoc(); + DL = I.getDebugLoc().getFnDebugLoc(); break; } diff --git a/llvm/lib/Target/BPF/BPFRegisterInfo.h b/llvm/lib/Target/BPF/BPFRegisterInfo.h index e7b870b720a4e..7062dc8899e95 100644 --- a/llvm/lib/Target/BPF/BPFRegisterInfo.h +++ b/llvm/lib/Target/BPF/BPFRegisterInfo.h @@ -21,6 +21,7 @@ namespace llvm { struct BPFRegisterInfo : public BPFGenRegisterInfo { + static unsigned FrameLength; BPFRegisterInfo(); diff --git a/llvm/lib/Target/BPF/BPFSubtarget.cpp b/llvm/lib/Target/BPF/BPFSubtarget.cpp index fac02e6476b7e..e7dc9a429b8ff 100644 --- a/llvm/lib/Target/BPF/BPFSubtarget.cpp +++ b/llvm/lib/Target/BPF/BPFSubtarget.cpp @@ -34,6 +34,7 @@ BPFSubtarget &BPFSubtarget::initializeSubtargetDependencies(StringRef CPU, } void BPFSubtarget::initializeEnvironment() { + IsSolana = false; HasJmpExt = false; HasJmp32 = false; HasAlu32 = false; diff --git a/llvm/lib/Target/BPF/BPFSubtarget.h b/llvm/lib/Target/BPF/BPFSubtarget.h index 7649e0e922223..6b737f31a07a5 100644 --- a/llvm/lib/Target/BPF/BPFSubtarget.h +++ b/llvm/lib/Target/BPF/BPFSubtarget.h @@ -44,6 +44,9 @@ class BPFSubtarget : public BPFGenSubtargetInfo { // unused bool isDummyMode; + // whether to enable Solana extensions. + bool IsSolana; + // whether the cpu supports jmp ext bool HasJmpExt; @@ -68,6 +71,7 @@ class BPFSubtarget : public BPFGenSubtargetInfo { // 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 isSolana() const { return IsSolana; } bool getHasJmpExt() const { return HasJmpExt; } bool getHasJmp32() const { return HasJmp32; } bool getHasAlu32() const { return HasAlu32; } diff --git a/llvm/lib/Target/BPF/BPFTargetMachine.cpp b/llvm/lib/Target/BPF/BPFTargetMachine.cpp index a8fef2517b03e..d89dccbb5223e 100644 --- a/llvm/lib/Target/BPF/BPFTargetMachine.cpp +++ b/llvm/lib/Target/BPF/BPFTargetMachine.cpp @@ -50,11 +50,15 @@ extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeBPFTarget() { } // DataLayout: little or big endian -static std::string computeDataLayout(const Triple &TT) { - if (TT.getArch() == Triple::bpfeb) - return "E-m:e-p:64:64-i64:64-i128:128-n32:64-S128"; - else - return "e-m:e-p:64:64-i64:64-i128:128-n32:64-S128"; +static std::string computeDataLayout(const Triple &TT, StringRef FS) { + bool isSolana = FS.contains("solana"); + if (TT.getArch() == Triple::bpfeb) { + return isSolana ? "E-m:e-p:64:64-i64:64-n32:64-S128" + : "E-m:e-p:64:64-i64:64-i128:128-n32:64-S128"; + } else { + return isSolana ? "e-m:e-p:64:64-i64:64-n32:64-S128" + : "e-m:e-p:64:64-i64:64-i128:128-n32:64-S128"; + } } static Reloc::Model getEffectiveRelocModel(Optional RM) { @@ -67,7 +71,7 @@ BPFTargetMachine::BPFTargetMachine(const Target &T, const Triple &TT, Optional RM, Optional CM, CodeGenOpt::Level OL, bool JIT) - : LLVMTargetMachine(T, computeDataLayout(TT), TT, CPU, FS, Options, + : LLVMTargetMachine(T, computeDataLayout(TT, FS), TT, CPU, FS, Options, getEffectiveRelocModel(RM), getEffectiveCodeModel(CM, CodeModel::Small), OL), TLOF(std::make_unique()), @@ -77,6 +81,7 @@ BPFTargetMachine::BPFTargetMachine(const Target &T, const Triple &TT, BPFMCAsmInfo *MAI = static_cast(const_cast(AsmInfo.get())); MAI->setDwarfUsesRelocationsAcrossSections(!Subtarget.getUseDwarfRIS()); + MAI->setSupportsDebugInformation(!FS.contains("solana")); } namespace { diff --git a/llvm/lib/Target/BPF/BTFDebug.cpp b/llvm/lib/Target/BPF/BTFDebug.cpp index f9bdffe7cbaea..3ef31fef60934 100644 --- a/llvm/lib/Target/BPF/BTFDebug.cpp +++ b/llvm/lib/Target/BPF/BTFDebug.cpp @@ -1087,11 +1087,12 @@ void BTFDebug::beginInstruction(const MachineInstr *MI) { // been generated, construct one based on function signature. if (LineInfoGenerated == false) { auto *S = MI->getMF()->getFunction().getSubprogram(); - MCSymbol *FuncLabel = Asm->getFunctionBegin(); - constructLineInfo(S, FuncLabel, S->getLine(), 0); - LineInfoGenerated = true; + if (S) { + MCSymbol *FuncLabel = Asm->getFunctionBegin(); + constructLineInfo(S, FuncLabel, S->getLine(), 0); + LineInfoGenerated = true; + } } - return; } diff --git a/llvm/lib/Target/BPF/MCTargetDesc/BPFAsmBackend.cpp b/llvm/lib/Target/BPF/MCTargetDesc/BPFAsmBackend.cpp index 29e9d5da08364..dfab71c400c42 100644 --- a/llvm/lib/Target/BPF/MCTargetDesc/BPFAsmBackend.cpp +++ b/llvm/lib/Target/BPF/MCTargetDesc/BPFAsmBackend.cpp @@ -23,7 +23,8 @@ namespace { class BPFAsmBackend : public MCAsmBackend { public: - BPFAsmBackend(support::endianness Endian) : MCAsmBackend(Endian) {} + BPFAsmBackend(support::endianness Endian, const MCSubtargetInfo &STI) + : MCAsmBackend(Endian), isSolana(STI.hasFeature(BPF::FeatureSolana)) {} ~BPFAsmBackend() override = default; void applyFixup(const MCAssembler &Asm, const MCFixup &Fixup, @@ -44,6 +45,8 @@ class BPFAsmBackend : public MCAsmBackend { unsigned getNumFixupKinds() const override { return 1; } bool writeNopData(raw_ostream &OS, uint64_t Count) const override; +private: + bool isSolana; }; } // end anonymous namespace @@ -93,19 +96,19 @@ void BPFAsmBackend::applyFixup(const MCAssembler &Asm, const MCFixup &Fixup, std::unique_ptr BPFAsmBackend::createObjectTargetWriter() const { - return createBPFELFObjectWriter(0); + return createBPFELFObjectWriter(0, isSolana); } MCAsmBackend *llvm::createBPFAsmBackend(const Target &T, const MCSubtargetInfo &STI, const MCRegisterInfo &MRI, const MCTargetOptions &) { - return new BPFAsmBackend(support::little); + return new BPFAsmBackend(support::little, STI); } MCAsmBackend *llvm::createBPFbeAsmBackend(const Target &T, const MCSubtargetInfo &STI, const MCRegisterInfo &MRI, const MCTargetOptions &) { - return new BPFAsmBackend(support::big); + return new BPFAsmBackend(support::big, STI); } diff --git a/llvm/lib/Target/BPF/MCTargetDesc/BPFELFObjectWriter.cpp b/llvm/lib/Target/BPF/MCTargetDesc/BPFELFObjectWriter.cpp index ef4e324c3bdd3..671e02088eeb4 100644 --- a/llvm/lib/Target/BPF/MCTargetDesc/BPFELFObjectWriter.cpp +++ b/llvm/lib/Target/BPF/MCTargetDesc/BPFELFObjectWriter.cpp @@ -21,19 +21,34 @@ namespace { class BPFELFObjectWriter : public MCELFObjectTargetWriter { public: - BPFELFObjectWriter(uint8_t OSABI); + BPFELFObjectWriter(uint8_t OSABI, bool isSolana); ~BPFELFObjectWriter() override = default; protected: unsigned getRelocType(MCContext &Ctx, const MCValue &Target, const MCFixup &Fixup, bool IsPCRel) const override; + + bool needsRelocateWithSymbol(const MCSymbol &Sym, + unsigned Type) const override; +private: + bool isSolana; }; } // end anonymous namespace -BPFELFObjectWriter::BPFELFObjectWriter(uint8_t OSABI) +// Avoid section relocations because the BPF 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 BPFELFObjectWriter::needsRelocateWithSymbol(const MCSymbol &Sym, + unsigned Type) const { + return isSolana; +} + +BPFELFObjectWriter::BPFELFObjectWriter(uint8_t OSABI, bool isSolana) : MCELFObjectTargetWriter(/*Is64Bit*/ true, OSABI, ELF::EM_BPF, - /*HasRelocationAddend*/ false) {} + /*HasRelocationAddend*/ false), + isSolana(isSolana) {} unsigned BPFELFObjectWriter::getRelocType(MCContext &Ctx, const MCValue &Target, const MCFixup &Fixup, @@ -42,13 +57,6 @@ unsigned BPFELFObjectWriter::getRelocType(MCContext &Ctx, const MCValue &Target, switch (Fixup.getKind()) { default: llvm_unreachable("invalid fixup kind!"); - case FK_SecRel_8: - return ELF::R_BPF_64_64; - case FK_PCRel_4: - case FK_SecRel_4: - return ELF::R_BPF_64_32; - case FK_Data_8: - return ELF::R_BPF_64_64; case FK_Data_4: if (const MCSymbolRefExpr *A = Target.getSymA()) { const MCSymbol &Sym = A->getSymbol(); @@ -79,11 +87,16 @@ unsigned BPFELFObjectWriter::getRelocType(MCContext &Ctx, const MCValue &Target, } } } + case FK_PCRel_4: + case FK_SecRel_4: return ELF::R_BPF_64_32; + case FK_SecRel_8: + case FK_Data_8: + return ELF::R_BPF_64_64; } } std::unique_ptr -llvm::createBPFELFObjectWriter(uint8_t OSABI) { - return std::make_unique(OSABI); +llvm::createBPFELFObjectWriter(uint8_t OSABI, bool isSolana) { + return std::make_unique(OSABI, isSolana); } diff --git a/llvm/lib/Target/BPF/MCTargetDesc/BPFMCAsmInfo.h b/llvm/lib/Target/BPF/MCTargetDesc/BPFMCAsmInfo.h index 3292c3e5ebb51..9ec7de1758347 100644 --- a/llvm/lib/Target/BPF/MCTargetDesc/BPFMCAsmInfo.h +++ b/llvm/lib/Target/BPF/MCTargetDesc/BPFMCAsmInfo.h @@ -48,6 +48,10 @@ class BPFMCAsmInfo : public MCAsmInfo { void setDwarfUsesRelocationsAcrossSections(bool enable) { DwarfUsesRelocationsAcrossSections = enable; } + + void setSupportsDebugInformation(bool enable) { + SupportsDebugInformation = enable; + } }; } diff --git a/llvm/lib/Target/BPF/MCTargetDesc/BPFMCTargetDesc.h b/llvm/lib/Target/BPF/MCTargetDesc/BPFMCTargetDesc.h index a426a132cf47d..025993c1eac36 100644 --- a/llvm/lib/Target/BPF/MCTargetDesc/BPFMCTargetDesc.h +++ b/llvm/lib/Target/BPF/MCTargetDesc/BPFMCTargetDesc.h @@ -43,7 +43,8 @@ MCAsmBackend *createBPFbeAsmBackend(const Target &T, const MCSubtargetInfo &STI, const MCRegisterInfo &MRI, const MCTargetOptions &Options); -std::unique_ptr createBPFELFObjectWriter(uint8_t OSABI); +std::unique_ptr createBPFELFObjectWriter(uint8_t OSABI, + bool isSolana); } // Defines symbolic names for BPF registers. This defines a mapping from diff --git a/llvm/test/CodeGen/X86/stack-clash-medium.ll b/llvm/test/CodeGen/X86/stack-clash-medium.ll index c4e2e86d5e17c..593e3c06245d6 100644 --- a/llvm/test/CodeGen/X86/stack-clash-medium.ll +++ b/llvm/test/CodeGen/X86/stack-clash-medium.ll @@ -2,31 +2,6 @@ ; RUN: llc -mtriple=i686-linux-android < %s | FileCheck -check-prefix=CHECK-X86-32 %s define i32 @foo() local_unnamed_addr #0 { -; CHECK-X86-64-LABEL: foo: -; CHECK-X86-64: # %bb.0: -; CHECK-X86-64-NEXT: subq $4096, %rsp # imm = 0x1000 -; CHECK-X86-64-NEXT: .cfi_adjust_cfa_offset 4096 -; CHECK-X86-64-NEXT: movq $0, (%rsp) -; CHECK-X86-64-NEXT: subq $3784, %rsp # imm = 0xEC8 -; CHECK-X86-64-NEXT: .cfi_def_cfa_offset 7888 -; CHECK-X86-64-NEXT: movl $1, 672(%rsp) -; CHECK-X86-64-NEXT: movl -128(%rsp), %eax -; CHECK-X86-64-NEXT: addq $7880, %rsp # imm = 0x1EC8 -; CHECK-X86-64-NEXT: .cfi_def_cfa_offset 8 -; CHECK-X86-64-NEXT: retq -; -; CHECK-X86-32-LABEL: foo: -; CHECK-X86-32: # %bb.0: -; CHECK-X86-32-NEXT: subl $4096, %esp # imm = 0x1000 -; CHECK-X86-32-NEXT: .cfi_adjust_cfa_offset 4096 -; CHECK-X86-32-NEXT: movl $0, (%esp) -; CHECK-X86-32-NEXT: subl $3916, %esp # imm = 0xF4C -; CHECK-X86-32-NEXT: .cfi_def_cfa_offset 8016 -; CHECK-X86-32-NEXT: movl $1, 800(%esp) -; CHECK-X86-32-NEXT: movl (%esp), %eax -; CHECK-X86-32-NEXT: addl $8012, %esp # imm = 0x1F4C -; CHECK-X86-32-NEXT: .cfi_def_cfa_offset 4 -; CHECK-X86-32-NEXT: retl %a = alloca i32, i64 2000, align 16 %b = getelementptr inbounds i32, i32* %a, i64 200 store volatile i32 1, i32* %b @@ -39,6 +14,7 @@ attributes #0 = {"probe-stack"="inline-asm"} ; CHECK-X86-64-LABEL: foo: ; CHECK-X86-64: # %bb.0: ; CHECK-X86-64-NEXT: subq $4096, %rsp # imm = 0x1000 +; CHECK-X86-64-NEXT: .cfi_adjust_cfa_offset 4096 ; CHECK-X86-64-NEXT: movq $0, (%rsp) ; CHECK-X86-64-NEXT: subq $3784, %rsp # imm = 0xEC8 ; CHECK-X86-64-NEXT: .cfi_def_cfa_offset 7888 @@ -48,10 +24,10 @@ attributes #0 = {"probe-stack"="inline-asm"} ; CHECK-X86-64-NEXT: .cfi_def_cfa_offset 8 ; CHECK-X86-64-NEXT: retq - -; CHECK-X86-32-LABEL: foo: +; CHECK-X86-32-LABEL: foo:{{.*}} ; CHECK-X86-32: # %bb.0: ; CHECK-X86-32-NEXT: subl $4096, %esp # imm = 0x1000 +; CHECK-X86-32-NEXT: .cfi_adjust_cfa_offset 4096 ; CHECK-X86-32-NEXT: movl $0, (%esp) ; CHECK-X86-32-NEXT: subl $3916, %esp # imm = 0xF4C ; CHECK-X86-32-NEXT: .cfi_def_cfa_offset 8016 diff --git a/llvm/test/Transforms/LICM/promote-atomic.ll b/llvm/test/Transforms/LICM/promote-atomic.ll index 86107d738cea6..edf3fb03165a4 100644 --- a/llvm/test/Transforms/LICM/promote-atomic.ll +++ b/llvm/test/Transforms/LICM/promote-atomic.ll @@ -13,7 +13,7 @@ define void @test(%class.LiveThread* %live_thread) { ; CHECK-NEXT: br label [[LOOP:%.*]] ; CHECK: loop: ; CHECK-NEXT: store %class.LiveThread* undef, %class.LiveThread** [[NEXT_UNPROCESSED_]], align 8 -; CHECK-NEXT: [[XCHG:%.*]] = cmpxchg weak i64* @globallive, i64 undef, i64 undef release monotonic, align 8 +; CHECK-NEXT: [[XCHG:%.*]] = cmpxchg weak i64* @globallive, i64 undef, i64 undef release monotonic ; CHECK-NEXT: [[DONE:%.*]] = extractvalue { i64, i1 } [[XCHG]], 1 ; CHECK-NEXT: br i1 [[DONE]], label [[EXIT:%.*]], label [[LOOP]] ; CHECK: exit: @@ -24,7 +24,7 @@ define void @test(%class.LiveThread* %live_thread) { loop: store %class.LiveThread* undef, %class.LiveThread** %next_unprocessed_, align 8 - %xchg = cmpxchg weak i64* @globallive, i64 undef, i64 undef release monotonic, align 8 + %xchg = cmpxchg weak i64* @globallive, i64 undef, i64 undef release monotonic %done = extractvalue { i64, i1 } %xchg, 1 br i1 %done, label %exit, label %loop diff --git a/llvm/unittests/Analysis/TargetLibraryInfoTest.cpp b/llvm/unittests/Analysis/TargetLibraryInfoTest.cpp index f7829a99e59f8..c096b1e993f83 100644 --- a/llvm/unittests/Analysis/TargetLibraryInfoTest.cpp +++ b/llvm/unittests/Analysis/TargetLibraryInfoTest.cpp @@ -586,6 +586,11 @@ TEST_F(TargetLibraryInfoTest, ValidProto) { "declare i8* @vec_malloc(i64)\n" "declare i8* @vec_realloc(i8*, i64)\n" "declare void @vec_free(i8*)\n" + + // rust memory management + "declare i8* @__rust_alloc(i64, i64, i8*)\n" + "declare void @__rust_dealloc(i8*, i64, i64)\n" + "declare i8* @__rust_realloc(i8*, i64, i64, i64, i64, i8*)\n" ); for (unsigned FI = 0; FI != LibFunc::NumLibFuncs; ++FI) {