#include <llvm/ExecutionEngine/MCJIT.h>
#include <llvm/ExecutionEngine/SectionMemoryManager.h>
#include <llvm/IRReader/IRReader.h>
+#include <llvm/IR/IRBuilder.h>
#include <llvm/IR/IRPrintingPasses.h>
#include <llvm/IR/LegacyPassManager.h>
#include <llvm/IR/LLVMContext.h>
ctx_.reset();
}
-unique_ptr<ExecutionEngine> BPFModule::make_reader(LLVMContext &ctx) {
- auto m = make_unique<Module>("scanf_reader", ctx);
- Module *mod = &*m;
- auto structs = mod->getIdentifiedStructTypes();
- for (auto s : structs) {
- fprintf(stderr, "struct %s\n", s->getName().str().c_str());
+// recursive helper to capture the arguments
+void parse_type(IRBuilder<> &B, vector<Value *> *args, string *fmt, Type *type, Value *out) {
+ if (StructType *st = dyn_cast<StructType>(type)) {
+ *fmt += "{ ";
+ unsigned idx = 0;
+ for (auto field : st->elements()) {
+ parse_type(B, args, fmt, field, B.CreateStructGEP(type, out, idx++));
+ *fmt += " ";
+ }
+ *fmt += "}";
+ } else if (dyn_cast<IntegerType>(type)) {
+ *fmt += "%lli";
+ args->push_back(out);
}
+}
+
+int BPFModule::make_reader(Module *mod, Type *type) {
+ if (readers_.find(type) != readers_.end()) return 0;
+
+ // int read(const char *in, Type *out) {
+ // int n = sscanf(in, "{ %i ... }", &out->field1, ...);
+ // if (n != num_fields) return -1;
+ // return 0;
+ // }
+
+ IRBuilder<> B(*ctx_);
+
+ vector<Type *> fn_args({B.getInt8PtrTy(), PointerType::getUnqual(type)});
+ FunctionType *fn_type = FunctionType::get(B.getInt32Ty(), fn_args, /*isVarArg=*/false);
+ Function *fn = Function::Create(fn_type, GlobalValue::ExternalLinkage,
+ "reader" + std::to_string(readers_.size()), mod);
+ auto arg_it = fn->arg_begin();
+ Argument *arg_in = arg_it++;
+ arg_in->setName("in");
+ Argument *arg_out = arg_it++;
+ arg_out->setName("out");
+
+ BasicBlock *label_entry = BasicBlock::Create(*ctx_, "entry", fn);
+ BasicBlock *label_exit = BasicBlock::Create(*ctx_, "exit", fn);
+ B.SetInsertPoint(label_entry);
+
+ vector<Value *> args;
+ string fmt;
+ parse_type(B, &args, &fmt, type, arg_out);
+
+ GlobalVariable *fmt_gvar = B.CreateGlobalString(fmt, "fmt");
+
+ args.insert(args.begin(), B.CreateInBoundsGEP(fmt_gvar, vector<Value *>({B.getInt64(0), B.getInt64(0)})));
+ args.insert(args.begin(), arg_in);
+
+ vector<Type *> sscanf_fn_args({B.getInt8PtrTy(), B.getInt8PtrTy()});
+ FunctionType *sscanf_fn_type = FunctionType::get(B.getInt32Ty(), sscanf_fn_args, /*isVarArg=*/true);
+ Function *sscanf_fn = mod->getFunction("__isoc99_sscanf");
+ if (!sscanf_fn)
+ sscanf_fn = Function::Create(sscanf_fn_type, GlobalValue::ExternalLinkage, "__isoc99_sscanf", mod);
+
+ CallInst *call = B.CreateCall(sscanf_fn, args);
+ BasicBlock *label_then = BasicBlock::Create(*ctx_, "then", fn);
+
+ Value *is_neq = B.CreateICmpNE(call, B.getInt32(args.size() - 2));
+ B.CreateCondBr(is_neq, label_then, label_exit);
+
+ B.SetInsertPoint(label_then);
+ B.CreateRet(B.getInt32(-1));
+
+ B.SetInsertPoint(label_exit);
+ B.CreateRet(B.getInt32(0));
+
+ readers_[type] = fn;
+ return 0;
+}
+
+unique_ptr<ExecutionEngine> BPFModule::finalize_reader(unique_ptr<Module> m) {
+ Module *mod = &*m;
- dump_ir(*mod);
run_pass_manager(*mod);
string err;
- map<string, tuple<uint8_t *, uintptr_t>> sections;
EngineBuilder builder(move(m));
builder.setErrorStr(&err);
- builder.setMCJITMemoryManager(make_unique<MyMemoryManager>(§ions));
builder.setUseOrcMCJITReplacement(true);
auto engine = unique_ptr<ExecutionEngine>(builder.create());
if (!engine)
for (auto fn = mod_->getFunctionList().begin(); fn != mod_->getFunctionList().end(); ++fn)
fn->addFnAttr(Attribute::AlwaysInline);
+ // separate module to hold the reader functions
+ auto m = make_unique<Module>("sscanf", *ctx_);
+
for (auto table : *tables_) {
table_names_.push_back(table.first);
GlobalValue *gvar = mod_->getNamedValue(table.first);
if (!gvar) continue;
- llvm::errs() << "table " << gvar->getName() << "\n";
- }
- //for (auto s : mod_->getIdentifiedStructTypes()) {
- // llvm::errs() << "struct " << s->getName() << "\n";
- // for (auto e : s->elements()) {
- // llvm::errs() << " ";
- // e->print(llvm::errs());
- // llvm::errs() << "\n";
- // }
- //}
-
- if (1) {
- auto engine = make_reader(*ctx_);
- if (engine)
- engine->finalizeObject();
+ if (PointerType *pt = dyn_cast<PointerType>(gvar->getType())) {
+ if (StructType *st = dyn_cast<StructType>(pt->getElementType())) {
+ if (st->getNumElements() < 2) continue;
+ Type *key_type = st->elements()[0];
+ Type *leaf_type = st->elements()[1];
+ if (int rc = make_reader(&*m, key_type))
+ return rc;
+ if (int rc = make_reader(&*m, leaf_type))
+ return rc;
+ }
+ }
}
+ auto engine = finalize_reader(move(m));
+ if (engine)
+ engine->finalizeObject();
return 0;
}
void BPFModule::dump_ir(Module &mod) {
legacy::PassManager PM;
- PM.add(createPrintModulePass(outs()));
+ PM.add(createPrintModulePass(errs()));
PM.run(mod);
}
else
return mkstatus_(n, "Table type %s not implemented", n->type_id()->name_.c_str());
+ StructType *key_stype, *leaf_stype;
+ TRY2(lookup_struct_type(n->key_type_, &key_stype));
+ TRY2(lookup_struct_type(n->leaf_type_, &leaf_stype));
StructType *decl_struct = mod_->getTypeByName("_struct." + n->id_->name_);
if (!decl_struct)
decl_struct = StructType::create(ctx(), "_struct." + n->id_->name_);
if (decl_struct->isOpaque())
- decl_struct->setBody(std::vector<Type *>({Type::getInt32Ty(ctx()), Type::getInt32Ty(ctx()),
- Type::getInt32Ty(ctx()), Type::getInt32Ty(ctx())}),
- /*isPacked=*/false);
+ decl_struct->setBody(vector<Type *>({key_stype, leaf_stype}), /*isPacked=*/false);
GlobalVariable *decl_gvar = new GlobalVariable(*mod_, decl_struct, false,
GlobalValue::ExternalLinkage, 0, n->id_->name_);
decl_gvar->setSection("maps");
- vector<Constant *> struct_init = { B.getInt32(map_type), B.getInt32(key->bit_width_ / 8),
- B.getInt32(leaf->bit_width_ / 8), B.getInt32(n->size_)};
- Constant *const_struct = ConstantStruct::get(decl_struct, struct_init);
- decl_gvar->setInitializer(const_struct);
tables_[n] = decl_gvar;
int map_fd = bpf_create_map(map_type, key->bit_width_ / 8, leaf->bit_width_ / 8, n->size_);
BasicBlock *label_entry = BasicBlock::Create(ctx(), "entry", fn);
B.SetInsertPoint(label_entry);
- string scoped_entry_label = std::to_string((uintptr_t)fn) + "::entry";
+ string scoped_entry_label = to_string((uintptr_t)fn) + "::entry";
labels_[scoped_entry_label] = label_entry;
BasicBlock *label_return = resolve_label("DONE");
retval_ = new AllocaInst(fn->getReturnType(), "ret", label_entry);
return mkstatus(0);
}
-int CodegenLLVM::get_table_fd(const std::string &name) const {
+int CodegenLLVM::get_table_fd(const string &name) const {
TableDeclStmtNode *table = scopes_->top_table()->lookup(name);
if (!table)
return -1;
BasicBlock * CodegenLLVM::resolve_label(const string &label) {
Function *parent = B.GetInsertBlock()->getParent();
- string scoped_label = std::to_string((uintptr_t)parent) + "::" + label;
+ string scoped_label = to_string((uintptr_t)parent) + "::" + label;
auto it = labels_.find(scoped_label);
if (it != labels_.end()) return it->second;
BasicBlock *label_new = BasicBlock::Create(ctx(), label, parent);