Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
56 commits
Select commit Hold shift + click to select a range
ad0ecbd
add lambda analysis pass
johnbowen42 Mar 27, 2026
40a86c2
add lambda functors
johnbowen42 Mar 27, 2026
3eceb39
Cleanup after rebase, rename __jit_ to __proteus_
johnbowen42 Apr 17, 2026
91e4f0c
Fix unused function warnings
johnbowen42 Apr 17, 2026
160e5e2
fix LLVM 20 build
johnbowen42 Apr 17, 2026
8faf39f
fix unused function
johnbowen42 Apr 17, 2026
dbc6271
Fix unused variable compiler warnings and includes
johnbowen42 Apr 20, 2026
f21009d
Fix lambda analysis failure
johnbowen42 Apr 20, 2026
e858f88
add runtime device side dispatch to lambda IR transformation
johnbowen42 Apr 23, 2026
b559268
Get lambda factory test passing
johnbowen42 Apr 24, 2026
9af220f
add visitor for kernel arg analysis
johnbowen42 May 1, 2026
349c750
tmp
johnbowen42 May 2, 2026
3731b6f
Add kernel args visitor. Get Lambda factory test working
johnbowen42 May 2, 2026
b1cfba8
tmp
johnbowen42 May 5, 2026
de40bdb
HIP unit tests passing
johnbowen42 May 5, 2026
2bbe786
Fix host lambda specialization
johnbowen42 May 5, 2026
3c2b302
move analysis to compile time
johnbowen42 May 6, 2026
a5e548e
merge
johnbowen42 May 6, 2026
35fb9cc
Clang format and fix merge in visitor pattern
johnbowen42 May 6, 2026
7cdc689
add several tests
johnbowen42 May 11, 2026
3b9c8c6
Cleanup rebase
johnbowen42 May 11, 2026
9dc3fbd
remove cloning changes
johnbowen42 May 11, 2026
b978ac4
Remove usage of macro
johnbowen42 May 11, 2026
47b3010
Add kernel arg layout analysis
johnbowen42 May 12, 2026
e9df3b1
cleanup and fix test output ordering
johnbowen42 May 12, 2026
b0fc8c9
Add extra support for MFEM, fix static assert in JitInterface, add te…
johnbowen42 May 15, 2026
c9765ad
tmp: debuging performance regressions
johnbowen42 May 15, 2026
1b0784c
tmp: fix regressions discovered in CEED benchmark. Not clean commit:…
johnbowen42 May 20, 2026
aef926a
Rework host side jit specialization to reduce runtime overhead
johnbowen42 May 22, 2026
1c894b7
Fix all host-side unit tests after host lambda specialization redesign
johnbowen42 May 22, 2026
90432d7
Fix device specialization, move all kernel reading to C instrumentation
johnbowen42 May 22, 2026
3a13cf7
Fix cuda build, remove unused variables and methods
johnbowen42 May 26, 2026
8039eb8
Fix CUDA tests
johnbowen42 May 27, 2026
5e57269
Fix test
johnbowen42 May 27, 2026
eb3cc2e
fix deprecation warnings
johnbowen42 May 27, 2026
39d821a
remove storage cache checks from ptrtoint
johnbowen42 May 28, 2026
78bc07e
Fix test
johnbowen42 May 28, 2026
fb63478
Fix bug where GPU lambdas without jit_variables causes errors through…
johnbowen42 Jun 4, 2026
cda65ef
Trim lambda llvm.global.annotations to avoid warnings
johnbowen42 Jun 9, 2026
5e05867
init commit for handling RAJA callbases in memory use analysis
johnbowen42 Jun 16, 2026
cb8248c
tmp
johnbowen42 Jun 17, 2026
b4c0117
Init indirect launch with lambdas support
johnbowen42 Jun 18, 2026
37f0f20
Add new indirect kernel launch support for kernels with lambdas
johnbowen42 Jun 18, 2026
5182c32
initial SSA test
johnbowen42 Jun 18, 2026
4761dd8
Initial support for RAJA IR shapes
johnbowen42 Jul 1, 2026
2ad4054
Add support for thread privatizer methods in RAJA by adding extract_v…
johnbowen42 Jul 2, 2026
eb05768
add thread safety to lambda registry
johnbowen42 Jul 2, 2026
6f024c9
Remove unused fields from pointer use analysis
johnbowen42 Jul 2, 2026
7d48240
fix use of hiplaunchkernel instead of generic
johnbowen42 Jul 2, 2026
b3f5ad0
fix matrix build
johnbowen42 Jul 2, 2026
b74d12b
Remove separate lambda pass. Register lambda analysis at pipeline st…
johnbowen42 Jul 6, 2026
7f61eff
clang tidy
johnbowen42 Jul 7, 2026
dca103e
clang format
johnbowen42 Jul 7, 2026
c2a889e
Clang format
johnbowen42 Jul 7, 2026
9a5a988
Clang format
johnbowen42 Jul 8, 2026
37978a0
Add legacy lambda pass, fix phi analysis bug, cleanup LambdaAnalysis
johnbowen42 Aug 10, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions include/proteus/CompilerInterfaceTypes.h
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,10 @@ struct RuntimeConstant {
ArrayInfo ArrInfo{0, RuntimeConstantType::NONE, nullptr};
ObjectInfo ObjInfo{0, false, nullptr};

// We need a trivial constructor to use RuntimeConstant in DenseMap keys
explicit RuntimeConstant()
: Type(RuntimeConstantType::NONE), Pos(-1), Offset(-1) {}

explicit RuntimeConstant(RuntimeConstantType Type, int32_t Pos)
: Type(Type), Pos(Pos) {
std::memset(&Value, 0, sizeof(RuntimeConstantValue));
Expand Down
109 changes: 73 additions & 36 deletions include/proteus/JitInterface.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,17 +17,28 @@
#include "proteus/Init.h"

#include <cassert>
#include <cstdint>
#include <cstring>
#include <type_traits>
#include <utility>

extern "C" void __proteus_register_variable(proteus::RuntimeConstant RC,
const char *AssociatedLambda);
extern "C" void __proteus_register_lambda(const char *Symbol);
extern "C" __attribute__((used)) void
__proteus_register_lambda_runtime_constant(int32_t Type, int32_t Pos,
int32_t Offset, const void *ValuePtr,
uint64_t functor_id);

extern "C" void __proteus_take_address(void const *) noexcept;
extern "C" __attribute__((used)) void
__proteus_finalize_register(uint64_t Tag) noexcept;

namespace proteus {

#if defined(__CUDACC__) || defined(__HIP__)
#define PROTEUS_HOST_DEVICE __host__ __device__
#else
#define PROTEUS_HOST_DEVICE
#endif

template <typename T> __attribute__((noinline)) void jit_arg(T V) noexcept;
#if defined(__CUDACC__) || defined(__HIP__)
template <typename T>
Expand Down Expand Up @@ -75,51 +86,77 @@ __attribute__((noinline)) __device__ std::enable_if_t<
jit_object(T &V, size_t Size = sizeof(T)) noexcept;
#endif

template <typename T> inline static RuntimeConstantType convertCTypeToRCType() {
if constexpr (std::is_same_v<T, bool>) {
return RuntimeConstantType::BOOL;
} else if constexpr (std::is_integral_v<T> && sizeof(T) == sizeof(int8_t)) {
return RuntimeConstantType::INT8;
} else if constexpr (std::is_integral_v<T> && sizeof(T) == sizeof(int32_t)) {
return RuntimeConstantType::INT32;
} else if constexpr (std::is_integral_v<T> && sizeof(T) == sizeof(int64_t)) {
return RuntimeConstantType::INT64;
} else if constexpr (std::is_same_v<T, float>) {
return RuntimeConstantType::FLOAT;
} else if constexpr (std::is_same_v<T, double>) {
return RuntimeConstantType::DOUBLE;
} else if constexpr (std::is_same_v<T, long double>) {
return RuntimeConstantType::LONG_DOUBLE;
} else if constexpr (std::is_pointer_v<T>) {
return RuntimeConstantType::PTR;
} else {
return RuntimeConstantType::NONE;
namespace detail {
// todo: use LLVM hashing?
constexpr std::uint64_t fnv1a64(const char *s) {
std::uint64_t h = 14695981039346656037ull;
for (; *s; ++s) {
h ^= (unsigned char)(*s);
h *= 1099511628211ull;
}
return h;
}

template <typename T>
static __attribute__((noinline)) T
jit_variable(T V, int Pos = -1, int Offset = -1,
const char *AssociatedLambda = "") noexcept {
RuntimeConstant RC{convertCTypeToRCType<T>(), Pos, Offset};
std::memcpy(static_cast<void *>(&RC), &V, sizeof(T));
__proteus_register_variable(RC, AssociatedLambda);
// todo: make a test with lambda factory in a header, two separate cpp files
template <class Lambda> constexpr std::uint64_t functor_id() {
return fnv1a64(__PRETTY_FUNCTION__); // includes Lambda + Ctr in the text
}

return V;
template <uint64_t FunctorID, typename Lambda> struct LambdaFunctorWrapper {
using LambdaType = Lambda;
static constexpr std::uint64_t functor_id = FunctorID;
LambdaType lambda;

template <typename... Args>
PROTEUS_HOST_DEVICE __attribute__((annotate("jit")))
__attribute__((annotate("proteus.wrapper_call", functor_id))) decltype(auto)
operator()(Args &&...args) const noexcept {
return lambda(std::forward<Args>(args)...);
}
};

template <typename... T> struct is_lambda_functor_wrapper : std::false_type {};

template <uint64_t FunctorID, typename Lambda>
struct is_lambda_functor_wrapper<LambdaFunctorWrapper<FunctorID, Lambda>>
: std::true_type {};

template <std::uint64_t FunctorId, typename L>
PROTEUS_HOST_DEVICE inline auto tag_functor(L &&lambda) {
return LambdaFunctorWrapper<FunctorId, std::decay_t<L>>{
std::forward<L>(lambda)};
}

template <typename T>
static __attribute__((noinline)) T &&
register_lambda(T &&t, const char *Symbol = "") noexcept {
assert(Symbol && "Expected non-null Symbol");
__proteus_register_lambda(Symbol);
template <uint64_t ID, typename T>
[[nodiscard]] static __attribute__((noinline))
__attribute__((annotate("proteus.register_call_impl", ID))) auto
__register_lambda_impl(T &&t) noexcept {
static_assert(!detail::is_lambda_functor_wrapper<std::decay_t<T>>::value);
// Force LLVM to generate an AllocaInst of the underlying Clang--generated
// anonymous class for T. We remove this after recording the demangled
// lambda name.
using LambdaType = std::decay_t<T>;
LambdaType local = t;
__proteus_take_address(&local);
return std::forward<T>(t);
auto result = tag_functor<ID>(std::forward<T>(t));
return result;
}

} // namespace detail

template <class L>
[[nodiscard]] inline auto __attribute__((annotate("proteus.register_call")))
register_lambda(L &&lambda) noexcept {
auto registered_lambda = ::proteus::detail::__register_lambda_impl<
::proteus::detail::functor_id<std::decay_t<L>>()>(
std::forward<L>(lambda));
__proteus_take_address(&registered_lambda);
return registered_lambda;
}

template <typename T>
static __attribute__((noinline)) T jit_variable(T V) noexcept {
return V;
}

#if defined(__CUDACC__) || defined(__HIP__)
Expand Down
14 changes: 9 additions & 5 deletions src/include/proteus/impl/CompilationTask.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
#include "proteus/impl/CoreLLVMDevice.h"
#include "proteus/impl/Debug.h"
#include "proteus/impl/Hashing.h"
#include "proteus/impl/LambdaCallsite.h"
#include "proteus/impl/Utils.h"

#include <llvm/Bitcode/BitcodeReader.h>
Expand All @@ -25,7 +26,8 @@ class CompilationTask {
dim3 BlockDim;
dim3 GridDim;
SmallVector<RuntimeConstant> RCVec;
SmallVector<std::pair<std::string, StringRef>> LambdaCalleeInfo;
SmallVector<uint64_t> LambdaCalleeInfo;
LambdaCallsiteRuntimeConstantsMap LambdaCallsiteRuntimeConstants;
std::unordered_map<std::string, GlobalVarInfo> VarNameToGlobalInfo;
SmallPtrSet<void *, 8> GlobalLinkedBinaries;
std::string DeviceArch;
Expand Down Expand Up @@ -71,14 +73,16 @@ class CompilationTask {
MemoryBufferRef Bitcode, HashT HashValue, const std::string &KernelName,
std::string &Suffix, dim3 BlockDim, dim3 GridDim,
const SmallVector<RuntimeConstant> &RCVec,
const SmallVector<std::pair<std::string, StringRef>> &LambdaCalleeInfo,
const SmallVector<uint64_t> &LambdaCalleeInfo,
const LambdaCallsiteRuntimeConstantsMap &LambdaCallsiteRuntimeConstants,
const std::unordered_map<std::string, GlobalVarInfo> &VarNameToGlobalInfo,
const SmallPtrSet<void *, 8> &GlobalLinkedBinaries,
const std::string &DeviceArch, const CodeGenerationConfig &CGConfig,
bool DumpIR, bool RelinkGlobalsByCopy)
: Bitcode(Bitcode), HashValue(HashValue), KernelName(KernelName),
Suffix(Suffix), BlockDim(BlockDim), GridDim(GridDim), RCVec(RCVec),
LambdaCalleeInfo(LambdaCalleeInfo),
LambdaCallsiteRuntimeConstants(LambdaCallsiteRuntimeConstants),
VarNameToGlobalInfo(VarNameToGlobalInfo),
GlobalLinkedBinaries(GlobalLinkedBinaries), DeviceArch(DeviceArch),
CGOption(CGConfig.codeGenOption()), DumpIR(DumpIR),
Expand Down Expand Up @@ -143,9 +147,9 @@ class CompilationTask {
PROTEUS_DBG(Logger::logfile(HashValue.toString() + ".input.ll", *M));

proteus::specializeIR(*M, KernelName, Suffix, BlockDim, GridDim, RCVec,
LambdaCalleeInfo, SpecializeArgs, SpecializeDims,
SpecializeDimsRange, SpecializeLaunchBounds,
MinBlocksPerSM);
LambdaCalleeInfo, LambdaCallsiteRuntimeConstants,
SpecializeArgs, SpecializeDims, SpecializeDimsRange,
SpecializeLaunchBounds, MinBlocksPerSM);

PROTEUS_DBG(Logger::logfile(HashValue.toString() + ".specialized.ll", *M));

Expand Down
59 changes: 59 additions & 0 deletions src/include/proteus/impl/CoreLLVM.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,11 @@ static_assert(__cplusplus >= 201703L,
#include "proteus/impl/JITPassPluginRegistry.h"
#include "proteus/impl/Logger.h"

#include <llvm/Analysis/ValueTracking.h>
#include <llvm/CodeGen/CommandFlags.h>
#include <llvm/IR/Constants.h>
#include <llvm/IR/DebugInfo.h>
#include <llvm/IR/Metadata.h>
#include <llvm/IR/Module.h>
#include <llvm/IR/PassManager.h>
#include <llvm/Linker/Linker.h>
Expand Down Expand Up @@ -387,6 +390,48 @@ inline void runCleanupPassPipeline(Module &M) {
StripDebugInfo(M);
}

inline void findFunctionsWithU64Metadata(
llvm::Module &M, llvm::StringRef Key,
llvm::SmallVectorImpl<std::pair<llvm::Function *, std::uint64_t>> &Out) {
llvm::SmallDenseMap<llvm::Function *, std::uint64_t, 32> Seen;
for (llvm::Function &F : M) {
llvm::MDNode *Node = F.getMetadata(Key);
if (!Node || Node->getNumOperands() < 1)
continue;
auto *CAM = llvm::dyn_cast<llvm::ConstantAsMetadata>(Node->getOperand(0));
auto *CI =
CAM ? llvm::dyn_cast<llvm::ConstantInt>(CAM->getValue()) : nullptr;
if (!CI)
continue;
std::uint64_t Id = CI->getZExtValue();
if (Seen.try_emplace(&F, Id).second)
Out.emplace_back(&F, Id);
}
}

inline void
findFunctionsWithU64Metadata(llvm::Module &M, llvm::StringRef Key,
llvm::SmallVectorImpl<std::uint64_t> &Out) {
llvm::SmallDenseMap<llvm::Function *, std::uint64_t, 32> Seen;
for (llvm::Function &F : M) {
llvm::MDNode *Node = F.getMetadata(Key);
if (!Node || Node->getNumOperands() < 1)
continue;
auto *CAM = llvm::dyn_cast<llvm::ConstantAsMetadata>(Node->getOperand(0));
auto *CI =
CAM ? llvm::dyn_cast<llvm::ConstantInt>(CAM->getValue()) : nullptr;
if (!CI)
continue;
std::uint64_t Id = CI->getZExtValue();
if (Seen.try_emplace(&F, Id).second)
Out.emplace_back(Id);
}
}

inline bool hasU64Metadata(Function *F, StringRef Key) {
return F->getMetadata(Key) != nullptr;
}

inline void pruneIR(Module &M, bool UnsetExternallyInitialized = true) {
// Remove llvm.global.annotations now that we have read them.
if (auto *GlobalAnnotations = M.getGlobalVariable("llvm.global.annotations"))
Expand Down Expand Up @@ -435,6 +480,20 @@ inline void internalize(Module &M, StringRef PreserveFunctionName) {
});
}

inline std::optional<uint64_t> getFunctionU64Metadata(Function &F,
StringRef Key) {
MDNode *Node = F.getMetadata(Key);
if (!Node || Node->getNumOperands() < 1)
return std::nullopt;

auto *CAM = dyn_cast<ConstantAsMetadata>(Node->getOperand(0));
auto *CI = CAM ? dyn_cast<ConstantInt>(CAM->getValue()) : nullptr;
if (!CI)
return std::nullopt;

return CI->getZExtValue();
}

} // namespace proteus

#endif
15 changes: 7 additions & 8 deletions src/include/proteus/impl/CoreLLVMDevice.h
Original file line number Diff line number Diff line change
Expand Up @@ -286,7 +286,8 @@ inline void relinkGlobalsObject(
inline void specializeIR(
Module &M, StringRef FnName, StringRef Suffix, dim3 &BlockDim,
dim3 &GridDim, ArrayRef<RuntimeConstant> RCArray,
const SmallVector<std::pair<std::string, StringRef>> LambdaCalleeInfo,
const SmallVector<uint64_t> LambdaCalleeInfo,
const LambdaCallsiteRuntimeConstantsMap &LambdaCallsiteRuntimeConstants,
bool SpecializeArgs, bool SpecializeDims, bool SpecializeDimsRange,
bool SpecializeLaunchBounds, int MinBlocksPerSM) {
TIMESCOPE("proteus::specializeIR");
Expand All @@ -298,13 +299,11 @@ inline void specializeIR(
if (SpecializeArgs)
TransformArgumentSpecialization::transform(M, *F, RCArray);

auto &LR = LambdaRegistry::instance();
for (auto &[FnName, LambdaType] : LambdaCalleeInfo) {
const SmallVector<RuntimeConstant> &RCVec = LR.getJitVariables(LambdaType);
Function *F = M.getFunction(FnName);
if (!F)
reportFatalError("Expected non-null Function");
TransformLambdaSpecialization::transform(M, *F, RCVec);
// We add a per-function cache for memory ssa so that we don't have to
// duplicate results. TransformLambdaSpecialization LambdaTransformer;
for (auto &ID : LambdaCalleeInfo) {
TransformLambdaSpecialization::transformDeviceKernel(
M, ID, LambdaCallsiteRuntimeConstants);
}

// Run the shared array transform after any value specialization (arguments,
Expand Down
Loading
Loading