Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-05-10 08:43:54

0001 //===- OrcABISupport.h - ABI support code -----------------------*- C++ -*-===//
0002 //
0003 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
0004 // See https://llvm.org/LICENSE.txt for license information.
0005 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
0006 //
0007 //===----------------------------------------------------------------------===//
0008 //
0009 // ABI specific code for Orc, e.g. callback assembly.
0010 //
0011 // ABI classes should be part of the JIT *target* process, not the host
0012 // process (except where you're doing hosted JITing and the two are one and the
0013 // same).
0014 //
0015 //===----------------------------------------------------------------------===//
0016 
0017 #ifndef LLVM_EXECUTIONENGINE_ORC_ORCABISUPPORT_H
0018 #define LLVM_EXECUTIONENGINE_ORC_ORCABISUPPORT_H
0019 
0020 #include "llvm/ExecutionEngine/Orc/Shared/ExecutorAddress.h"
0021 #include "llvm/Support/Error.h"
0022 #include "llvm/Support/ErrorHandling.h"
0023 #include "llvm/Support/MathExtras.h"
0024 #include <cstdint>
0025 
0026 namespace llvm {
0027 namespace orc {
0028 
0029 struct IndirectStubsAllocationSizes {
0030   uint64_t StubBytes = 0;
0031   uint64_t PointerBytes = 0;
0032   unsigned NumStubs = 0;
0033 };
0034 
0035 template <typename ORCABI>
0036 IndirectStubsAllocationSizes
0037 getIndirectStubsBlockSizes(unsigned MinStubs, unsigned RoundToMultipleOf = 0) {
0038   assert(
0039       (RoundToMultipleOf == 0 || (RoundToMultipleOf % ORCABI::StubSize == 0)) &&
0040       "RoundToMultipleOf is not a multiple of stub size");
0041   uint64_t StubBytes = MinStubs * ORCABI::StubSize;
0042   if (RoundToMultipleOf)
0043     StubBytes = alignTo(StubBytes, RoundToMultipleOf);
0044   unsigned NumStubs = StubBytes / ORCABI::StubSize;
0045   uint64_t PointerBytes = NumStubs * ORCABI::PointerSize;
0046   return {StubBytes, PointerBytes, NumStubs};
0047 }
0048 
0049 /// Generic ORC ABI support.
0050 ///
0051 /// This class can be substituted as the target architecture support class for
0052 /// ORC templates that require one (e.g. IndirectStubsManagers). It does not
0053 /// support lazy JITing however, and any attempt to use that functionality
0054 /// will result in execution of an llvm_unreachable.
0055 class OrcGenericABI {
0056 public:
0057   static constexpr unsigned PointerSize = sizeof(uintptr_t);
0058   static constexpr unsigned TrampolineSize = 1;
0059   static constexpr unsigned StubSize = 1;
0060   static constexpr unsigned StubToPointerMaxDisplacement = 1;
0061   static constexpr unsigned ResolverCodeSize = 1;
0062 
0063   static void writeResolverCode(char *ResolveWorkingMem,
0064                                 ExecutorAddr ResolverTargetAddr,
0065                                 ExecutorAddr ReentryFnAddr,
0066                                 ExecutorAddr ReentryCtxAddr) {
0067     llvm_unreachable("writeResolverCode is not supported by the generic host "
0068                      "support class");
0069   }
0070 
0071   static void writeTrampolines(char *TrampolineBlockWorkingMem,
0072                                ExecutorAddr TrampolineBlockTargetAddr,
0073                                ExecutorAddr ResolverAddr,
0074                                unsigned NumTrampolines) {
0075     llvm_unreachable("writeTrampolines is not supported by the generic host "
0076                      "support class");
0077   }
0078 
0079   static void writeIndirectStubsBlock(char *StubsBlockWorkingMem,
0080                                       ExecutorAddr StubsBlockTargetAddress,
0081                                       ExecutorAddr PointersBlockTargetAddress,
0082                                       unsigned NumStubs) {
0083     llvm_unreachable(
0084         "writeIndirectStubsBlock is not supported by the generic host "
0085         "support class");
0086   }
0087 };
0088 
0089 class OrcAArch64 {
0090 public:
0091   static constexpr unsigned PointerSize = 8;
0092   static constexpr unsigned TrampolineSize = 12;
0093   static constexpr unsigned StubSize = 8;
0094   static constexpr unsigned StubToPointerMaxDisplacement = 1U << 27;
0095   static constexpr unsigned ResolverCodeSize = 0x120;
0096 
0097   /// Write the resolver code into the given memory. The user is
0098   /// responsible for allocating the memory and setting permissions.
0099   ///
0100   /// ReentryFnAddr should be the address of a function whose signature matches
0101   /// void* (*)(void *TrampolineAddr, void *ReentryCtxAddr). The ReentryCtxAddr
0102   /// argument of writeResolverCode will be passed as the second argument to
0103   /// the function at ReentryFnAddr.
0104   static void writeResolverCode(char *ResolverWorkingMem,
0105                                 ExecutorAddr ResolverTargetAddress,
0106                                 ExecutorAddr ReentryFnAddr,
0107                                 ExecutorAddr RentryCtxAddr);
0108 
0109   /// Write the requested number of trampolines into the given memory,
0110   /// which must be big enough to hold 1 pointer, plus NumTrampolines
0111   /// trampolines.
0112   static void writeTrampolines(char *TrampolineBlockWorkingMem,
0113                                ExecutorAddr TrampolineBlockTargetAddress,
0114                                ExecutorAddr ResolverAddr,
0115                                unsigned NumTrampolines);
0116 
0117   /// Write NumStubs indirect stubs to working memory at StubsBlockWorkingMem.
0118   /// Stubs will be written as if linked at StubsBlockTargetAddress, with the
0119   /// Nth stub using the Nth pointer in memory starting at
0120   /// PointersBlockTargetAddress.
0121   static void writeIndirectStubsBlock(char *StubsBlockWorkingMem,
0122                                       ExecutorAddr StubsBlockTargetAddress,
0123                                       ExecutorAddr PointersBlockTargetAddress,
0124                                       unsigned MinStubs);
0125 };
0126 
0127 /// X86_64 code that's common to all ABIs.
0128 ///
0129 /// X86_64 supports lazy JITing.
0130 class OrcX86_64_Base {
0131 public:
0132   static constexpr unsigned PointerSize = 8;
0133   static constexpr unsigned TrampolineSize = 8;
0134   static constexpr unsigned StubSize = 8;
0135   static constexpr unsigned StubToPointerMaxDisplacement = 1 << 31;
0136 
0137   /// Write the requested number of trampolines into the given memory,
0138   /// which must be big enough to hold 1 pointer, plus NumTrampolines
0139   /// trampolines.
0140   static void writeTrampolines(char *TrampolineBlockWorkingMem,
0141                                ExecutorAddr TrampolineBlockTargetAddress,
0142                                ExecutorAddr ResolverAddr,
0143                                unsigned NumTrampolines);
0144 
0145   /// Write NumStubs indirect stubs to working memory at StubsBlockWorkingMem.
0146   /// Stubs will be written as if linked at StubsBlockTargetAddress, with the
0147   /// Nth stub using the Nth pointer in memory starting at
0148   /// PointersBlockTargetAddress.
0149   static void writeIndirectStubsBlock(char *StubsBlockWorkingMem,
0150                                       ExecutorAddr StubsBlockTargetAddress,
0151                                       ExecutorAddr PointersBlockTargetAddress,
0152                                       unsigned NumStubs);
0153 };
0154 
0155 /// X86_64 support for SysV ABI (Linux, MacOSX).
0156 ///
0157 /// X86_64_SysV supports lazy JITing.
0158 class OrcX86_64_SysV : public OrcX86_64_Base {
0159 public:
0160   static constexpr unsigned ResolverCodeSize = 0x6C;
0161 
0162   /// Write the resolver code into the given memory. The user is
0163   /// responsible for allocating the memory and setting permissions.
0164   ///
0165   /// ReentryFnAddr should be the address of a function whose signature matches
0166   /// void* (*)(void *TrampolineAddr, void *ReentryCtxAddr). The ReentryCtxAddr
0167   /// argument of writeResolverCode will be passed as the second argument to
0168   /// the function at ReentryFnAddr.
0169   static void writeResolverCode(char *ResolverWorkingMem,
0170                                 ExecutorAddr ResolverTargetAddress,
0171                                 ExecutorAddr ReentryFnAddr,
0172                                 ExecutorAddr ReentryCtxAddr);
0173 };
0174 
0175 /// X86_64 support for Win32.
0176 ///
0177 /// X86_64_Win32 supports lazy JITing.
0178 class OrcX86_64_Win32 : public OrcX86_64_Base {
0179 public:
0180   static constexpr unsigned ResolverCodeSize = 0x74;
0181 
0182   /// Write the resolver code into the given memory. The user is
0183   /// responsible for allocating the memory and setting permissions.
0184   ///
0185   /// ReentryFnAddr should be the address of a function whose signature matches
0186   /// void* (*)(void *TrampolineAddr, void *ReentryCtxAddr). The ReentryCtxAddr
0187   /// argument of writeResolverCode will be passed as the second argument to
0188   /// the function at ReentryFnAddr.
0189   static void writeResolverCode(char *ResolverWorkingMem,
0190                                 ExecutorAddr ResolverTargetAddress,
0191                                 ExecutorAddr ReentryFnAddr,
0192                                 ExecutorAddr ReentryCtxAddr);
0193 };
0194 
0195 /// I386 support.
0196 ///
0197 /// I386 supports lazy JITing.
0198 class OrcI386 {
0199 public:
0200   static constexpr unsigned PointerSize = 4;
0201   static constexpr unsigned TrampolineSize = 8;
0202   static constexpr unsigned StubSize = 8;
0203   static constexpr unsigned StubToPointerMaxDisplacement = 1 << 31;
0204   static constexpr unsigned ResolverCodeSize = 0x4a;
0205 
0206   /// Write the resolver code into the given memory. The user is
0207   /// responsible for allocating the memory and setting permissions.
0208   ///
0209   /// ReentryFnAddr should be the address of a function whose signature matches
0210   /// void* (*)(void *TrampolineAddr, void *ReentryCtxAddr). The ReentryCtxAddr
0211   /// argument of writeResolverCode will be passed as the second argument to
0212   /// the function at ReentryFnAddr.
0213   static void writeResolverCode(char *ResolverWorkingMem,
0214                                 ExecutorAddr ResolverTargetAddress,
0215                                 ExecutorAddr ReentryFnAddr,
0216                                 ExecutorAddr ReentryCtxAddr);
0217 
0218   /// Write the requested number of trampolines into the given memory,
0219   /// which must be big enough to hold 1 pointer, plus NumTrampolines
0220   /// trampolines.
0221   static void writeTrampolines(char *TrampolineBlockWorkingMem,
0222                                ExecutorAddr TrampolineBlockTargetAddress,
0223                                ExecutorAddr ResolverAddr,
0224                                unsigned NumTrampolines);
0225 
0226   /// Write NumStubs indirect stubs to working memory at StubsBlockWorkingMem.
0227   /// Stubs will be written as if linked at StubsBlockTargetAddress, with the
0228   /// Nth stub using the Nth pointer in memory starting at
0229   /// PointersBlockTargetAddress.
0230   static void writeIndirectStubsBlock(char *StubsBlockWorkingMem,
0231                                       ExecutorAddr StubsBlockTargetAddress,
0232                                       ExecutorAddr PointersBlockTargetAddress,
0233                                       unsigned NumStubs);
0234 };
0235 
0236 // @brief Mips32 support.
0237 //
0238 // Mips32 supports lazy JITing.
0239 class OrcMips32_Base {
0240 public:
0241   static constexpr unsigned PointerSize = 4;
0242   static constexpr unsigned TrampolineSize = 20;
0243   static constexpr unsigned StubSize = 8;
0244   static constexpr unsigned StubToPointerMaxDisplacement = 1 << 31;
0245   static constexpr unsigned ResolverCodeSize = 0xfc;
0246 
0247   /// Write the requested number of trampolines into the given memory,
0248   /// which must be big enough to hold 1 pointer, plus NumTrampolines
0249   /// trampolines.
0250   static void writeTrampolines(char *TrampolineBlockWorkingMem,
0251                                ExecutorAddr TrampolineBlockTargetAddress,
0252                                ExecutorAddr ResolverAddr,
0253                                unsigned NumTrampolines);
0254 
0255   /// Write the resolver code into the given memory. The user is
0256   /// responsible for allocating the memory and setting permissions.
0257   ///
0258   /// ReentryFnAddr should be the address of a function whose signature matches
0259   /// void* (*)(void *TrampolineAddr, void *ReentryCtxAddr). The ReentryCtxAddr
0260   /// argument of writeResolverCode will be passed as the second argument to
0261   /// the function at ReentryFnAddr.
0262   static void writeResolverCode(char *ResolverBlockWorkingMem,
0263                                 ExecutorAddr ResolverBlockTargetAddress,
0264                                 ExecutorAddr ReentryFnAddr,
0265                                 ExecutorAddr ReentryCtxAddr, bool isBigEndian);
0266   /// Write NumStubs indirect stubs to working memory at StubsBlockWorkingMem.
0267   /// Stubs will be written as if linked at StubsBlockTargetAddress, with the
0268   /// Nth stub using the Nth pointer in memory starting at
0269   /// PointersBlockTargetAddress.
0270   static void writeIndirectStubsBlock(char *StubsBlockWorkingMem,
0271                                       ExecutorAddr StubsBlockTargetAddress,
0272                                       ExecutorAddr PointersBlockTargetAddress,
0273                                       unsigned NumStubs);
0274 };
0275 
0276 class OrcMips32Le : public OrcMips32_Base {
0277 public:
0278   static void writeResolverCode(char *ResolverWorkingMem,
0279                                 ExecutorAddr ResolverTargetAddress,
0280                                 ExecutorAddr ReentryFnAddr,
0281                                 ExecutorAddr ReentryCtxAddr) {
0282     OrcMips32_Base::writeResolverCode(ResolverWorkingMem, ResolverTargetAddress,
0283                                       ReentryFnAddr, ReentryCtxAddr, false);
0284   }
0285 };
0286 
0287 class OrcMips32Be : public OrcMips32_Base {
0288 public:
0289   static void writeResolverCode(char *ResolverWorkingMem,
0290                                 ExecutorAddr ResolverTargetAddress,
0291                                 ExecutorAddr ReentryFnAddr,
0292                                 ExecutorAddr ReentryCtxAddr) {
0293     OrcMips32_Base::writeResolverCode(ResolverWorkingMem, ResolverTargetAddress,
0294                                       ReentryFnAddr, ReentryCtxAddr, true);
0295   }
0296 };
0297 
0298 // @brief Mips64 support.
0299 //
0300 // Mips64 supports lazy JITing.
0301 class OrcMips64 {
0302 public:
0303   static constexpr unsigned PointerSize = 8;
0304   static constexpr unsigned TrampolineSize = 40;
0305   static constexpr unsigned StubSize = 32;
0306   static constexpr unsigned StubToPointerMaxDisplacement = 1 << 31;
0307   static constexpr unsigned ResolverCodeSize = 0x120;
0308 
0309   /// Write the resolver code into the given memory. The user is
0310   /// responsible for allocating the memory and setting permissions.
0311   ///
0312   /// ReentryFnAddr should be the address of a function whose signature matches
0313   /// void* (*)(void *TrampolineAddr, void *ReentryCtxAddr). The ReentryCtxAddr
0314   /// argument of writeResolverCode will be passed as the second argument to
0315   /// the function at ReentryFnAddr.
0316   static void writeResolverCode(char *ResolverWorkingMem,
0317                                 ExecutorAddr ResolverTargetAddress,
0318                                 ExecutorAddr ReentryFnAddr,
0319                                 ExecutorAddr ReentryCtxAddr);
0320 
0321   /// Write the requested number of trampolines into the given memory,
0322   /// which must be big enough to hold 1 pointer, plus NumTrampolines
0323   /// trampolines.
0324   static void writeTrampolines(char *TrampolineBlockWorkingMem,
0325                                ExecutorAddr TrampolineBlockTargetAddress,
0326                                ExecutorAddr ResolverFnAddr,
0327                                unsigned NumTrampolines);
0328   /// Write NumStubs indirect stubs to working memory at StubsBlockWorkingMem.
0329   /// Stubs will be written as if linked at StubsBlockTargetAddress, with the
0330   /// Nth stub using the Nth pointer in memory starting at
0331   /// PointersBlockTargetAddress.
0332   static void writeIndirectStubsBlock(char *StubsBlockWorkingMem,
0333                                       ExecutorAddr StubsBlockTargetAddress,
0334                                       ExecutorAddr PointersBlockTargetAddress,
0335                                       unsigned NumStubs);
0336 };
0337 
0338 // @brief riscv64 support.
0339 //
0340 // RISC-V 64 supports lazy JITing.
0341 class OrcRiscv64 {
0342 public:
0343   static constexpr unsigned PointerSize = 8;
0344   static constexpr unsigned TrampolineSize = 16;
0345   static constexpr unsigned StubSize = 16;
0346   static constexpr unsigned StubToPointerMaxDisplacement = 1 << 31;
0347   static constexpr unsigned ResolverCodeSize = 0x148;
0348 
0349   /// Write the resolver code into the given memory. The user is
0350   /// responsible for allocating the memory and setting permissions.
0351   ///
0352   /// ReentryFnAddr should be the address of a function whose signature matches
0353   /// void* (*)(void *TrampolineAddr, void *ReentryCtxAddr). The ReentryCtxAddr
0354   /// argument of writeResolverCode will be passed as the second argument to
0355   /// the function at ReentryFnAddr.
0356   static void writeResolverCode(char *ResolverWorkingMem,
0357                                 ExecutorAddr ResolverTargetAddress,
0358                                 ExecutorAddr ReentryFnAddr,
0359                                 ExecutorAddr ReentryCtxAddr);
0360 
0361   /// Write the requested number of trampolines into the given memory,
0362   /// which must be big enough to hold 1 pointer, plus NumTrampolines
0363   /// trampolines.
0364   static void writeTrampolines(char *TrampolineBlockWorkingMem,
0365                                ExecutorAddr TrampolineBlockTargetAddress,
0366                                ExecutorAddr ResolverFnAddr,
0367                                unsigned NumTrampolines);
0368   /// Write NumStubs indirect stubs to working memory at StubsBlockWorkingMem.
0369   /// Stubs will be written as if linked at StubsBlockTargetAddress, with the
0370   /// Nth stub using the Nth pointer in memory starting at
0371   /// PointersBlockTargetAddress.
0372   static void writeIndirectStubsBlock(char *StubsBlockWorkingMem,
0373                                       ExecutorAddr StubsBlockTargetAddress,
0374                                       ExecutorAddr PointersBlockTargetAddress,
0375                                       unsigned NumStubs);
0376 };
0377 
0378 // @brief loongarch64 support.
0379 //
0380 // LoongArch 64 supports lazy JITing.
0381 class OrcLoongArch64 {
0382 public:
0383   static constexpr unsigned PointerSize = 8;
0384   static constexpr unsigned TrampolineSize = 16;
0385   static constexpr unsigned StubSize = 16;
0386   static constexpr unsigned StubToPointerMaxDisplacement = 1 << 31;
0387   static constexpr unsigned ResolverCodeSize = 0xc8;
0388 
0389   /// Write the resolver code into the given memory. The user is
0390   /// responsible for allocating the memory and setting permissions.
0391   ///
0392   /// ReentryFnAddr should be the address of a function whose signature matches
0393   /// void* (*)(void *TrampolineAddr, void *ReentryCtxAddr). The ReentryCtxAddr
0394   /// argument of writeResolverCode will be passed as the second argument to
0395   /// the function at ReentryFnAddr.
0396   static void writeResolverCode(char *ResolverWorkingMem,
0397                                 ExecutorAddr ResolverTargetAddress,
0398                                 ExecutorAddr ReentryFnAddr,
0399                                 ExecutorAddr ReentryCtxAddr);
0400 
0401   /// Write the requested number of trampolines into the given memory,
0402   /// which must be big enough to hold 1 pointer, plus NumTrampolines
0403   /// trampolines.
0404   static void writeTrampolines(char *TrampolineBlockWorkingMem,
0405                                ExecutorAddr TrampolineBlockTargetAddress,
0406                                ExecutorAddr ResolverFnAddr,
0407                                unsigned NumTrampolines);
0408 
0409   /// Write NumStubs indirect stubs to working memory at StubsBlockWorkingMem.
0410   /// Stubs will be written as if linked at StubsBlockTargetAddress, with the
0411   /// Nth stub using the Nth pointer in memory starting at
0412   /// PointersBlockTargetAddress.
0413   static void writeIndirectStubsBlock(char *StubsBlockWorkingMem,
0414                                       ExecutorAddr StubsBlockTargetAddress,
0415                                       ExecutorAddr PointersBlockTargetAddress,
0416                                       unsigned NumStubs);
0417 };
0418 
0419 } // end namespace orc
0420 } // end namespace llvm
0421 
0422 #endif // LLVM_EXECUTIONENGINE_ORC_ORCABISUPPORT_H