Skip to content

Commit

Permalink
llvm-jit: patch lddw helpers at compile time (#323)
Browse files Browse the repository at this point in the history
* update

* update

* update

* update
  • Loading branch information
Officeyutong authored Aug 10, 2024
1 parent 611ff5a commit dd95d8e
Show file tree
Hide file tree
Showing 4 changed files with 238 additions and 209 deletions.
2 changes: 2 additions & 0 deletions vm/llvm-jit/src/compat/compat_llvm.cpp
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
#include "spdlog/spdlog.h"
#include <bpftime_vm_compat.hpp>
#include <cerrno>
#include <cstdint>
#include <memory>
#include <ebpf_inst.h>
#include "compat_llvm.hpp"
#include "../llvm/llvm_jit_context.hpp"

namespace bpftime::vm::compat
{

Expand Down
236 changes: 127 additions & 109 deletions vm/llvm-jit/src/llvm/compiler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -86,8 +86,11 @@ const size_t MAX_LOCAL_FUNC_DEPTH = 32;
*/
Expected<ThreadSafeModule> llvm_bpf_jit_context::generateModule(
const std::vector<std::string> &extFuncNames,
const std::vector<std::string> &lddwHelpers)
const std::vector<std::string> &lddwHelpers,
bool patch_map_val_at_compile_time)
{
SPDLOG_DEBUG("Generating module: patch_map_val_at_compile_time={}",
patch_map_val_at_compile_time);
auto context = std::make_unique<LLVMContext>();
auto jitModule = std::make_unique<Module>("bpf-jit", *context);
const auto &insts = vm->instructions;
Expand Down Expand Up @@ -155,17 +158,15 @@ Expected<ThreadSafeModule> llvm_bpf_jit_context::generateModule(
// The main function
Function *bpf_func = Function::Create(
FunctionType::get(Type::getInt64Ty(*context),
{ llvm::PointerType::getUnqual(llvm::Type::getInt8Ty(*context)),
{ llvm::PointerType::getUnqual(
llvm::Type::getInt8Ty(*context)),
Type::getInt64Ty(*context) },
false),
Function::ExternalLinkage, "bpf_main", jitModule.get());

// Get args of uint64_t bpf_main(uint64_t, uint64_t)
llvm::Argument* mem = bpf_func->getArg(0);
llvm::Argument* mem_len = bpf_func->getArg(1);



// Get args of uint64_t bpf_main(uint64_t, uint64_t)
llvm::Argument *mem = bpf_func->getArg(0);
llvm::Argument *mem_len = bpf_func->getArg(1);

std::vector<Value *> regs;
std::vector<BasicBlock *> allBlocks;
Expand Down Expand Up @@ -631,173 +632,190 @@ Expected<ThreadSafeModule> llvm_bpf_jit_context::generateModule(
(((uint64_t)((uint32_t)nextInst.imm)) << 32);
pc++;

SPDLOG_TRACE("Load LDDW val= {} part1={:x} part2={:x}",
SPDLOG_DEBUG("Load LDDW val= {} part1={:x} part2={:x}",
val, (uint64_t)inst.imm,
(uint64_t)nextInst.imm);
if (inst.src_reg == 0) {
SPDLOG_DEBUG("Emit lddw helper 0 at pc {}", pc);
builder.CreateStore(builder.getInt64(val),
regs[inst.dst_reg]);
} else if (inst.src_reg == 1) {
if (auto itr = lddwHelper.find(
LDDW_HELPER_MAP_BY_FD);
itr != lddwHelper.end())

{
SPDLOG_DEBUG(
"Emit lddw helper 1 (map_by_fd) at pc {}, imm={}",
pc, inst.imm);
SPDLOG_DEBUG(
"Emit lddw helper 1 (map_by_fd) at pc {}, imm={}, patched at compile time",
pc, inst.imm);
if (vm->map_by_fd) {
builder.CreateStore(
builder.CreateCall(
lddwHelperWithUint32,
itr->second,
{ builder.getInt32(
inst.imm) }),
builder.getInt64(vm->map_by_fd(
inst.imm)),
regs[inst.dst_reg]);
} else {
return llvm::make_error<
llvm::StringError>(
"Using lddw helper 1, which requires map_by_fd",
llvm::inconvertibleErrorCode());
SPDLOG_INFO(
"map_by_fd is called in eBPF code, but is not provided, will use the default behavior");
// Default: input value
builder.CreateStore(
builder.getInt64(
(int64_t)inst.imm),
regs[inst.dst_reg]);
}

} else if (inst.src_reg == 2) {
if (auto itrMapByFd = lddwHelper.find(
LDDW_HELPER_MAP_BY_FD);
itrMapByFd != lddwHelper.end()) {
SPDLOG_DEBUG(
"Emit lddw helper 2 (map_by_fd + map_val) at pc {}, imm1={}, imm2={}",
pc, inst.imm, nextInst.imm);
uint64_t mapPtr;
if (vm->map_by_fd) {
mapPtr = vm->map_by_fd(inst.imm);
} else {
SPDLOG_INFO(
"map_by_fd is called in eBPF code, but is not provided, will use the default behavior");
// Default: returns the input value
mapPtr = (uint64_t)inst.imm;
}
if (patch_map_val_at_compile_time) {
SPDLOG_DEBUG(
"map_val is required to be evaluated at compile time");
if (!vm->map_val) {
return llvm::make_error<
llvm::StringError>(
"map_val is not provided, unable to compile",
llvm::inconvertibleErrorCode());
}
builder.CreateStore(
builder.getInt64(
vm->map_val(mapPtr) +
nextInst.imm),
regs[inst.dst_reg]);
} else {
SPDLOG_DEBUG(
"map_val is required to be evaluated at runtime, emitting calling instructions");

if (auto itrMapVal = lddwHelper.find(
LDDW_HELPER_MAP_VAL);
itrMapVal != lddwHelper.end()) {
auto retMapByFd = builder.CreateCall(
lddwHelperWithUint32,
itrMapByFd->second,
{ builder.getInt32(
inst.imm) });
auto retMapVal = builder.CreateCall(
lddwHelperWithUint64,
itrMapVal->second,
{ retMapByFd });
{ builder.getInt64(
mapPtr) });
auto finalRet = builder.CreateAdd(
retMapVal,
builder.getInt64(
nextInst.imm));
builder.CreateStore(
finalRet,
regs[inst.dst_reg]);
SPDLOG_DEBUG(
"Emit lddw helper 2 (map_by_fd + map_val) at pc {}, imm1={}, imm2={}",
pc, inst.imm,
nextInst.imm);

} else {
return llvm::make_error<
llvm::StringError>(
"Using lddw helper 2, which requires map_val",
"Using lddw helper 2, which requires map_val to be defined.",
llvm::inconvertibleErrorCode());
}

} else {
return llvm::make_error<
llvm::StringError>(
"Using lddw helper 2, which requires map_by_fd",
llvm::inconvertibleErrorCode());
}

} else if (inst.src_reg == 3) {
if (auto itr = lddwHelper.find(
LDDW_HELPER_VAR_ADDR);
itr != lddwHelper.end()) {
builder.CreateStore(
builder.CreateCall(
lddwHelperWithUint32,
itr->second,
{ builder.getInt32(
inst.imm) }),
regs[inst.dst_reg]);
SPDLOG_DEBUG(
"Emit lddw helper 3 (var_addr) at pc {}, imm1={}",
pc, inst.imm);
} else {
SPDLOG_DEBUG(
"Emit lddw helper 3 (var_addr) at pc {}, imm1={}",
pc, inst.imm);
if (!vm->var_addr) {
return llvm::make_error<
llvm::StringError>(
"Using lddw helper 3, which requires var_addr",
"var_addr is not provided, unable to compile",
llvm::inconvertibleErrorCode());
}
builder.CreateStore(
builder.getInt64(
vm->var_addr(inst.imm)),
regs[inst.dst_reg]);
} else if (inst.src_reg == 4) {
if (auto itr = lddwHelper.find(
LDDW_HELPER_CODE_ADDR);
itr != lddwHelper.end()) {
builder.CreateStore(
builder.CreateCall(
lddwHelperWithUint32,
itr->second,
{ builder.getInt32(
inst.imm) }),
regs[inst.dst_reg]);
SPDLOG_DEBUG(
"Emit lddw helper 4 (code_addr) at pc {}, imm1={}",
pc, inst.imm);
} else {
SPDLOG_DEBUG(
"Emit lddw helper 4 (code_addr) at pc {}, imm1={}",
pc, inst.imm);
if (!vm->code_addr) {
return llvm::make_error<
llvm::StringError>(
"Using lddw helper 4, which requires code_addr",
"code_addr is not provided, unable to compile",
llvm::inconvertibleErrorCode());
}
builder.CreateStore(
builder.getInt64(
vm->code_addr(inst.imm)),
regs[inst.dst_reg]);
} else if (inst.src_reg == 5) {
if (auto itr = lddwHelper.find(
LDDW_HELPER_MAP_BY_IDX);
itr != lddwHelper.end()) {
SPDLOG_DEBUG(
"Emit lddw helper 4 (map_by_idx) at pc {}, imm1={}",
pc, inst.imm);
if (vm->map_by_idx) {
builder.CreateStore(
builder.CreateCall(
lddwHelperWithUint32,
itr->second,
{ builder.getInt32(
inst.imm) }),
builder.getInt64(vm->map_by_idx(
inst.imm)),
regs[inst.dst_reg]);
SPDLOG_DEBUG(
"Emit lddw helper 4 (map_by_idx) at pc {}, imm1={}",
pc, inst.imm);
} else {
return llvm::make_error<
llvm::StringError>(
"Using lddw helper 5, which requires map_by_idx",
llvm::inconvertibleErrorCode());
SPDLOG_INFO(
"map_by_idx is called in eBPF code, but it's not provided, will use the default behavior");
// Default: returns the input value
builder.CreateStore(
builder.getInt64(
(int64_t)inst.imm),
regs[inst.dst_reg]);
}

} else if (inst.src_reg == 6) {
if (auto itrMapByIdx = lddwHelper.find(
LDDW_HELPER_MAP_BY_IDX);
itrMapByIdx != lddwHelper.end()) {
SPDLOG_DEBUG(
"Emit lddw helper 6 (map_by_idx + map_val) at pc {}, imm1={}, imm2={}",
pc, inst.imm, nextInst.imm);

uint64_t mapPtr;
if (vm->map_by_idx) {
mapPtr = vm->map_by_idx(inst.imm);
} else {
SPDLOG_DEBUG(
"map_by_idx is called in eBPF code, but it's not provided, will use the default behavior");
// Default: returns the input value
mapPtr = (int64_t)inst.imm;
}
if (patch_map_val_at_compile_time) {
SPDLOG_DEBUG(
"Required to evaluate map_val at compile time");
if (vm->map_val) {
builder.CreateStore(
builder.getInt64(
vm->map_val(
mapPtr) +
nextInst.imm),
regs[inst.dst_reg]);
} else {
return llvm::make_error<
llvm::StringError>(
"map_val is not provided, unable to compile",
llvm::inconvertibleErrorCode());
}

} else {
SPDLOG_DEBUG(
"Required to evaluate map_val at runtime time");
if (auto itrMapVal = lddwHelper.find(
LDDW_HELPER_MAP_VAL);
itrMapVal != lddwHelper.end()) {
auto retMapByIdx = builder.CreateCall(
lddwHelperWithUint32,
itrMapByIdx->second,
{ builder.getInt32(
inst.imm) });
auto retMapVal = builder.CreateCall(
lddwHelperWithUint64,
itrMapVal->second,
{ retMapByIdx });
{ builder.getInt64(
mapPtr) });
auto finalRet = builder.CreateAdd(
retMapVal,
builder.getInt64(
nextInst.imm));
builder.CreateStore(
finalRet,
regs[inst.dst_reg]);
SPDLOG_DEBUG(
"Emit lddw helper 6 (map_by_idx + map_val) at pc {}, imm1={}, imm2={}",
pc, inst.imm,
nextInst.imm);

} else {
return llvm::make_error<
llvm::StringError>(
"Using lddw helper 6, which requires map_val",
llvm::inconvertibleErrorCode());
}
} else {
return llvm::make_error<
llvm::StringError>(
"Using lddw helper 6, which requires map_by_idx",
llvm::inconvertibleErrorCode());
}
}
break;
Expand Down
Loading

0 comments on commit dd95d8e

Please sign in to comment.