socsvn commit: r273264 - soc2014/dpl/netmap-ipfwjit/sys/netpfil/ipfw

dpl at FreeBSD.org dpl at FreeBSD.org
Thu Aug 28 16:19:05 UTC 2014


Author: dpl
Date: Thu Aug 28 16:19:04 2014
New Revision: 273264
URL: http://svnweb.FreeBSD.org/socsvn/?view=rev&rev=273264

Log:
  Updated the code to LLVM 3.6, added the compilation boilerplate, and storage of rules in a nice vector, so that we can jump from one place to another.
  

Modified:
  soc2014/dpl/netmap-ipfwjit/sys/netpfil/ipfw/jit.cc

Modified: soc2014/dpl/netmap-ipfwjit/sys/netpfil/ipfw/jit.cc
==============================================================================
--- soc2014/dpl/netmap-ipfwjit/sys/netpfil/ipfw/jit.cc	Thu Aug 28 15:05:42 2014	(r273263)
+++ soc2014/dpl/netmap-ipfwjit/sys/netpfil/ipfw/jit.cc	Thu Aug 28 16:19:04 2014	(r273264)
@@ -3,8 +3,7 @@
 #include <string>
 #include <vector>
 
-#include <llvm/ADT/OwningPtr.h>
-#include <llvm/ADT/ArrayRef.h>
+#include <llvm/Analysis/Passes.h>
 #include <llvm/Bitcode/ReaderWriter.h>
 #include <llvm/CodeGen/MachineCodeInfo.h>
 #include <llvm/ExecutionEngine/ExecutionEngine.h>
@@ -17,9 +16,12 @@
 #include <llvm/IR/Type.h>
 #include <llvm/IR/Value.h>
 #include <llvm/IR/Verifier.h>
+#include <llvm/PassManager.h>
 #include <llvm/Support/MemoryBuffer.h>
 #include <llvm/Support/ErrorOr.h>
 #include <llvm/Support/TargetSelect.h>
+#include <llvm/Transforms/IPO.h>
+#include <llvm/Transforms/IPO/PassManagerBuilder.h>
 #define _KERNEL
 
 extern "C" {
@@ -46,11 +48,10 @@
 	Module *mod;
 	Function *func;
 	LLVMContext con;
-	OwningPtr<MemoryBuffer> buffer;
 	IRBuilder<> irb;
 
 	// We'll store the BasicBlock objects for each rule here.
-	int rulenumber = 1;
+	int rulenumber = 0;
 	std::vector<BasicBlock *> rules;
 
 	// Vars Types
@@ -69,9 +70,6 @@
 	BasicBlock *outer_for_epilogue;
 	BasicBlock *inner_for_epilogue;
 
-	// This BB is the next emitted rule, always.
-	BasicBlock *next;
-
 	// JIT Compiled Vars
 	// These are the function arguments.
 	Value *args;
@@ -174,22 +172,29 @@
 
 	// Load the bc for JIT compilation.
 	Module *
-	loadbc(std::string name)
+	loadBitcode(std::string name)
 	{
-		error_code ec = MemoryBuffer::getFile(name, buffer);
-		if (ec) {
-			std::cerr << "Failed to open bitcode: " << ec.message() << "\n";
+		auto buffer = MemoryBuffer::getFile(name);
+		if (buffer.getError()){
+			std::cerr << "Failed to open bitcode: " << buffer.getError() << "\n";
 			return (NULL);
 		}
 
-		ErrorOr<Module*> ptr = parseBitcodeFile(buffer.get(), con);
-		if ((ec = ptr.getError()))
-		{
-			std::cerr << "Failed to parse bitcode: " << ec.message() << "\n";
+		auto modptr = parseBitcodeFile(buffer.get().get(), con);
+		if ((modptr.getError())){
+			std::cerr << "Failed to parse bitcode: " << buffer.getError() << "\n";
 			return (NULL);
 		}
-		mod = ptr.get();
-		return (mod);
+		return (modptr.get());
+	}
+
+	BasicBlock*
+	nextRule(int num)
+	{
+		if (num >= rules.size())
+			return (end);
+		else
+			return (rules[num]);
 	}
 
 	// Create the needed variables to perform pkt filtering.
@@ -408,6 +413,7 @@
 
 		// if (V_fw_verbose)
 		irb.CreateCondBr(irb.CreateICmpEQ(is_verbose, ConstantInt::get(int32Ty, 0)), ret, print);
+
 		// printf("ipfw: pullup failed\n");
 		irb.SetInsertPoint(print);
 		irb.CreateCall(printfFunc, str);
@@ -466,7 +472,8 @@
 		// else f_pos = 0;
 		// Since f_pos is initialized by default as 0, we only br.
 		irb.SetInsertPoint(nottagged);
-		irb.CreateBr(rules[rulenumber]);
+		// Jump to first rule.
+		irb.CreateBr(rules.front());
 	}
 
 	void
@@ -499,7 +506,7 @@
 
 		irb.SetInsertPoint(jt);
 		//		continue;
-		irb.CreateBr(next);
+		irb.CreateBr(nextRule(rulenumber+1));
 
 		// skip_or = 0;
 		irb.SetInsertPoint(jf);
@@ -555,7 +562,7 @@
 
 		irb.SetInsertPoint(secondf);
 		// continue;
-		irb.CreateBr(next);
+		irb.CreateBr(nextRule(rulenumber+1));
 
 		irb.SetInsertPoint(firstf);
 		// match = 0;
@@ -568,15 +575,13 @@
 	void
 	emit_inner_for_epilogue()
 	{
-		BasicBlock *matchnz = BasicBlock::Create(con, "jt", func);
-		BasicBlock *matchz = BasicBlock::Create(con, "jt", func);
+		BasicBlock *matchnz = BasicBlock::Create(con, "matchnz", func);
+		BasicBlock *matchz = BasicBlock::Create(con, "matchz", func);
 		BasicBlock *jt = BasicBlock::Create(con, "jt", func);
-		BasicBlock *jf = BasicBlock::Create(con, "jf", func);
 		BasicBlock *sec_cond = BasicBlock::Create(con, "sec_cond", func);
 		BasicBlock *matchzero = BasicBlock::Create(con, "matchzero", func);
 		BasicBlock *matchnotzero = BasicBlock::Create(con, "matchnotzero", func);
 		BasicBlock *is_or = BasicBlock::Create(con, "is_or", func);
-		BasicBlock *is_not_or = BasicBlock::Create(con, "is_not_or", func);
 
 		// This are the increments of the for loop.
 		// l -= cmdlen, cmd += cmdlen;
@@ -628,7 +633,7 @@
 		irb.SetInsertPoint(matchzero);
 		// if (!(cmd->len & F_OR)) /* not an OR block, */
 		//     break;
-		irb.CreateCondBr(irb.CreateICmpEQ(irb.CreateAnd(irb.CreateInBoundsGEP(cmd, {ConstantInt::get(int32Ty, 0), ConstantInt::get(int32Ty, 1)}), ConstantInt::get(int8Ty, F_OR)), ConstantInt::get(int32Ty, 0)), next /* break */, outer_for_epilogue);
+		irb.CreateCondBr(irb.CreateICmpEQ(irb.CreateAnd(irb.CreateInBoundsGEP(cmd, {ConstantInt::get(int32Ty, 0), ConstantInt::get(int32Ty, 1)}), ConstantInt::get(int8Ty, F_OR)), ConstantInt::get(int32Ty, 0)), nextRule(rulenumber+1) /* break */, outer_for_epilogue);
 	}
 
 	// This code gets executed at the end of inner loop.
@@ -643,7 +648,7 @@
 
 		// if (done)
 		//		break;
-		irb.CreateCondBr(irb.CreateICmpNE(done, ConstantInt::get(int32Ty, 0)), end, next);
+		irb.CreateCondBr(irb.CreateICmpNE(done, ConstantInt::get(int32Ty, 0)), end, nextRule(rulenumber+1));
 	}
 
 	void
@@ -734,11 +739,18 @@
 	ipfwJIT(int rulesnumber): irb(con)
 	{
 		// Create the module and load the code.
-		mod = loadbc("ip_fw_rules.bc");
+		mod = loadBitcode("ip_fw_rules.bc");
 
 		func = mod->getFunction("ipfw_chk_jit");
 		func->setLinkage(GlobalValue::ExternalLinkage);
 
+		// Initialize the vector.
+		rules = std::vector<BasicBlock *>(rulesnumber);
+		for (auto &i: rules){
+			i = BasicBlock::Create(con, "rule", func);
+		}
+
+
 		// Create static BasicBlocks.
 		// The entry basic block contains all the initialization 
 		// and allocation of resources, and a basic check done 
@@ -746,15 +758,8 @@
 		entry = BasicBlock::Create(con, "entry", func);
 		check_tag = BasicBlock::Create(con, "check_tag", func);
 		end = BasicBlock::Create(con, "end", func);
-
-		// Initialize the vector.
-		rules = std::vector<BasicBlock *>(rulesnumber + 1);
-		rules[rulenumber] = BasicBlock::Create(con, "rule", func);
-		start_rule();
-
 		// This is equivalent to the pullup_failed tag.
 		pullup_failed = BasicBlock::Create(con, "pullup_failed", func);
-
 		//Snippets of code to be executed when iterating through the rules.
 		outer_for_prologue = BasicBlock::Create(con, "outer_for_prologue", func);
 		inner_for_prologue = BasicBlock::Create(con, "inner_for_prologue", func);
@@ -775,12 +780,6 @@
 		emit_inner_for_epilogue();
 		emit_outer_for_epilogue();
 		emit_end();
-
-		verifyFunction(*func);
-
-
-		verifyModule(*mod);
-		mod->dump();
 	}
 	~ipfwJIT()
 	{
@@ -788,33 +787,60 @@
 			delete mod;
 	}
 
-	void
-	optimize()
+	funcptr
+	compile()
 	{
+		// Check correctness.
+		verifyFunction(*func);
+		verifyModule(*mod);
+
+		//Optimise
+		PassManagerBuilder PMBuilder;
+		PMBuilder.OptLevel = 0;
+		PMBuilder.Inliner = createFunctionInliningPass(275);
+
+		// Function passes
+		FunctionPassManager *PerFunctionPasses = new FunctionPassManager(mod);
+		PMBuilder.populateFunctionPassManager(*PerFunctionPasses);
+		PerFunctionPasses->run(*func);
+		PerFunctionPasses->doFinalization();
+		delete PerFunctionPasses;
+
+		//printf("\n\n\n\n");
+		//mod->getFunction("ipfw_chk_jit")->dump();
+
+		// Module passes
+		PassManager *PerModulePasses = new PassManager();
+		PMBuilder.populateModulePassManager(*PerModulePasses);
+		PerModulePasses->run(*mod);
+		delete PerModulePasses;
+
 		// We don't need it anymore.
 		Function *vf = mod->getFunction("voidfunction");
 		vf->eraseFromParent();
-	}
 
-	// Returns the pointer to the compiled function.
-	funcptr
-	getFuncPtr()
-	{
-		return ((funcptr)NULL);
-	}
+		//Compile
+		std::string errstr;
+		std::string comperr = "Compilation error\n";
+
+		EngineBuilder EB = EngineBuilder(std::unique_ptr<Module>(mod));
+		EB.setEngineKind(EngineKind::Kind::JIT);
+		EB.setErrorStr(&comperr);
+
+		ExecutionEngine *EE = EB.create();
+		if (!EE) {
+			fprintf(stderr, "Error: %s\n", errstr.c_str());
+			exit(1);
+		}
 
-	void
-	start_rule()
-	{
-		// This will be the first BasicBlock to store our emmited code.
-		rules[rulenumber] = BasicBlock::Create(con, "rule", func);
-		next = rules[rulenumber+1] = BasicBlock::Create(con, "rule", func);
+		printf("Function ptr: %p\n", (void *)EE->getFunctionAddress("ipfw_chk_jit"));
+		err(1,"null");
+		return (funcptr)EE->getFunctionAddress("ipfw_chk_jit");
 	}
 
 	void
 	end_rule()
 	{
-		// We're on the next rule now.
 		rulenumber++;
 	}
 
@@ -851,32 +877,59 @@
 	}
 
 	// Rules
-	int
+	void
 	emit_nop()
 	{
 		irb.CreateStore(ConstantInt::get(int32Ty, 1), match);
-		return (0);
 	}
 
-	int
+	void
 	emit_forward_mac(u_int8_t opcode)
 	{
 		printf("Compilation error:\n");
 		printf("ipfwjitter: opcode %d unimplemented\n", opcode);
 		printf("Compilation continues.\n");
-		return (0);
 	}
 
-	int
+	void
 	emit_jail()
 	{
-		return (0);
+		// /*
+		//  * We only check offset == 0 && proto != 0,
+		//  * as this ensures that we have a
+		//  * packet with the ports info.
+		//  */
+		// if (offset != 0)
+		// 	return;
+		// if (proto == IPPROTO_TCP ||
+		// 	proto == IPPROTO_UDP)
+		// 	*match = check_uidgid(
+		// 			(ipfw_insn_u32 *)cmd,
+		// 			args, &ucred_lookup,
+		// #ifdef __FreeBSD__
+		// 			//(struct bsd_ucred **)&ucred_cache);
+		// 			(struct ucred **)&ucred_cache);
+		// #else
+		// 			(void *)&ucred_cache);
+		// #endif
+
 	}
 
-	int
+	void
 	emit_recv()
 	{
-		return (0);
+		// XXX Check correctness.
+		//*match = iface_match(m->m_pkthdr.rcvif, (ipfw_insn_if *)cmd, chain, tablearg);
+		Value *rcvif = irb.CreateStructGEP(irb.CreateStructGEP(irb.CreateLoad(m), 5), 0);
+		Value *cmdc = irb.CreateBitCast(cmd, ipfw_insn_ifPtrTy);
+		irb.CreateStore(irb.CreateCall4(iface_match, rcvif, cmdc, chain, tablearg), match);
+	}
+
+	void
+	emit_xmit()
+	{
+		// XXX Check correctness.
+		//*match = iface_match(oif, (ipfw_insn_if *)cmd, chain, tablearg);
 	}
 
 };
@@ -890,6 +943,9 @@
 	InitializeNativeTarget();
 	LLVMLinkInJIT();
 
+	if (chain->n_rules == 0)
+		return (NULL);
+
 	ipfwJIT compiler(chain->n_rules);
 
 	// Iterate through the rules.
@@ -905,7 +961,6 @@
 		f = chain->map[f_pos];
 
 		// Rule start.
-		compiler.start_rule();
 		compiler.emit_outer_for_prologue_call();
 
 		// For each different command.
@@ -933,11 +988,11 @@
 				compiler.emit_recv();
 				break;
 
-/* XXX
 			case O_XMIT:
 				compiler.emit_xmit();
 				break;
 
+/* XXX
 			case O_VIA:
 				compiler.emit_via();
 				break;
@@ -1295,7 +1350,7 @@
 			default:
 				panic("-- unknown opcode %d\n", cmd->opcode);
 			} /* end of switch() on opcodes */
-			compiler.emit_inner_for_prologue_call();
+			compiler.emit_inner_for_epilogue_call();
 		}	/* end of inner loop, scan opcodes */
 		// Rule ends.
 		compiler.emit_outer_for_epilogue_call();
@@ -1305,6 +1360,5 @@
 	compiler.emit_end_call();
 
 	// Once we're done iterating through the rules, return the pointer.
-	compiler.optimize();
-	return (compiler.getFuncPtr());
+	return (compiler.compile());
 }


More information about the svn-soc-all mailing list