16 #include <gtest/gtest.h>
17 #include <boost/thread/thread.hpp>
37 for (
int i = 0; i < 10; ++i) {
42 status = object1.
Init();
43 ASSERT_TRUE(status.
ok());
45 status = object2.
Init();
46 ASSERT_TRUE(status.ok());
48 status = object3.
Init();
49 ASSERT_TRUE(status.ok());
55 scoped_ptr<LlvmCodeGen>* codegen) {
56 return LlvmCodeGen::LoadFromFile(pool, filename,
"test", codegen);
61 if (codegen != NULL) {
63 if (!status.
ok())
return NULL;
87 thread_group thread_group;
89 thread_group.add_thread(
new thread(&LifetimeTest));
91 thread_group.join_all();
97 string module_file =
"NonExistentFile.ir";
98 scoped_ptr<LlvmCodeGen> codegen;
99 Status status = LlvmCodeGenTest::LoadFromFile(&pool, module_file.c_str(), &codegen);
100 EXPECT_TRUE(!status.
ok());
114 LLVMContext& context = codegen->
context();
119 BasicBlock* entry_block = BasicBlock::Create(context,
"entry", jitted_loop_call);
120 builder.SetInsertPoint(entry_block);
124 Value* const_delta = ConstantInt::get(context, APInt(64, delta));
127 Value* loaded_counter = builder.CreateLoad(counter_ptr);
128 Value* incremented_value = builder.CreateAdd(loaded_counter, const_delta);
129 builder.CreateStore(incremented_value, counter_ptr);
130 builder.CreateRetVoid();
132 return jitted_loop_call;
149 const char* loop_call_name =
"DefaultImplementation";
150 const char* loop_name =
"TestLoop";
151 typedef void (*TestLoopFn)(int);
154 PathBuilder::GetFullPath(
"llvm-ir/test-loop.ir", &module_file);
157 scoped_ptr<LlvmCodeGen> codegen;
158 Status status = LlvmCodeGenTest::LoadFromFile(&pool, module_file.c_str(), &codegen);
159 EXPECT_TRUE(codegen.get() != NULL);
160 EXPECT_TRUE(status.
ok());
162 vector<Function*> functions;
163 codegen->GetFunctions(&functions);
164 EXPECT_EQ(functions.size(), 2);
166 Function* loop_call = functions[0];
167 Function* loop = functions[1];
169 EXPECT_TRUE(loop_call->getName().find(loop_call_name) != string::npos);
170 EXPECT_TRUE(loop_call->arg_empty());
171 EXPECT_TRUE(loop->getName().find(loop_name) != string::npos);
172 EXPECT_EQ(loop->arg_size(), 1);
174 void* original_loop = LlvmCodeGenTest::JitFunction(codegen.get(), loop);
175 EXPECT_TRUE(original_loop != NULL);
177 TestLoopFn original_loop_fn =
reinterpret_cast<TestLoopFn
>(original_loop);
189 int64_t jitted_counter = 0;
190 Function* jitted_loop_call =
CodegenInnerLoop(codegen.get(), &jitted_counter, 1);
195 Function* jitted_loop = codegen->ReplaceCallSites(
196 loop,
false, jitted_loop_call, loop_call_name, &num_replaced);
197 EXPECT_EQ(num_replaced, 1);
198 EXPECT_TRUE(codegen->VerifyFunction(jitted_loop));
201 void* new_loop = LlvmCodeGenTest::JitFunction(codegen.get(), jitted_loop);
202 EXPECT_TRUE(new_loop != NULL);
204 TestLoopFn new_loop_fn =
reinterpret_cast<TestLoopFn
>(new_loop);
205 EXPECT_EQ(jitted_counter, 0);
207 EXPECT_EQ(jitted_counter, 5);
209 EXPECT_EQ(jitted_counter, 10);
212 Function* jitted_loop_call2 =
CodegenInnerLoop(codegen.get(), &jitted_counter, -2);
213 Function* jitted_loop2 = codegen->ReplaceCallSites(loop,
true, jitted_loop_call2,
214 loop_call_name, &num_replaced);
215 EXPECT_EQ(num_replaced, 1);
216 EXPECT_TRUE(codegen->VerifyFunction(jitted_loop2));
220 LlvmCodeGenTest::JitFunction(codegen.get(), jitted_loop2);
221 EXPECT_TRUE(new_loop2 != NULL);
223 TestLoopFn new_loop_fn2 =
reinterpret_cast<TestLoopFn
>(new_loop2);
225 EXPECT_EQ(jitted_counter, 0);
249 EXPECT_TRUE(string_val_ptr_type != NULL);
256 Function* interop_fn = prototype.GeneratePrototype(&builder, &str);
259 Value* str_ptr = builder.CreateStructGEP(str, 0,
"str_ptr");
260 Value* ptr = builder.CreateLoad(str_ptr,
"ptr");
262 Value* first_char_ptr = builder.CreateGEP(ptr, first_char_offset,
"first_char_ptr");
266 Value* len_ptr = builder.CreateStructGEP(str, 1,
"len_ptr");
267 Value* len = builder.CreateLoad(len_ptr,
"len");
269 builder.CreateRet(len);
280 scoped_ptr<LlvmCodeGen> codegen;
281 Status status = LlvmCodeGen::LoadImpalaIR(&pool,
"test", &codegen);
282 EXPECT_TRUE(status.
ok());
283 EXPECT_TRUE(codegen.get() != NULL);
289 memset(&str_val, 0,
sizeof(str_val));
290 str_val.
ptr =
const_cast<char*
>(str.c_str());
291 str_val.
len = str.length();
294 EXPECT_TRUE(string_test_fn != NULL);
295 EXPECT_TRUE(codegen->VerifyFunction(string_test_fn));
298 void* jitted_fn = LlvmCodeGenTest::JitFunction(codegen.get(), string_test_fn);
299 EXPECT_TRUE(jitted_fn != NULL);
303 TestStringInteropFn fn =
reinterpret_cast<TestStringInteropFn
>(jitted_fn);
304 int result = fn(&str_val);
307 EXPECT_EQ(str.length(), result);
308 EXPECT_EQ(
'A', str_val.
ptr[0]);
309 EXPECT_EQ(1, str_val.
len);
310 EXPECT_EQ(static_cast<void*>(str_val.
ptr), static_cast<const void*>(str.c_str()));
313 int32_t* bytes =
reinterpret_cast<int32_t*
>(&str_val);
314 EXPECT_EQ(1, bytes[2]);
315 EXPECT_EQ(0, bytes[3]);
322 scoped_ptr<LlvmCodeGen> codegen;
323 Status status = LlvmCodeGen::LoadImpalaIR(&pool,
"test", &codegen);
324 ASSERT_TRUE(status.
ok());
325 ASSERT_TRUE(codegen.get() != NULL);
338 Function* fn = prototype.GeneratePrototype(&builder, &args[0]);
339 codegen->CodegenMemcpy(&builder, args[0], args[1],
sizeof(src));
340 builder.CreateRetVoid();
342 fn = codegen->FinalizeFunction(fn);
343 ASSERT_TRUE(fn != NULL);
345 void* jitted_fn = LlvmCodeGenTest::JitFunction(codegen.get(), fn);
346 ASSERT_TRUE(jitted_fn != NULL);
348 typedef void (*TestMemcpyFn)(
char*,
char*, int64_t);
349 TestMemcpyFn test_fn =
reinterpret_cast<TestMemcpyFn
>(jitted_fn);
351 test_fn(dst, src, 4);
353 EXPECT_EQ(memcmp(src, dst, 4), 0);
361 const char* data1 =
"test string";
362 const char* data2 =
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
364 scoped_ptr<LlvmCodeGen> codegen;
365 Status status = LlvmCodeGen::LoadImpalaIR(&pool,
"test", &codegen);
366 ASSERT_TRUE(status.
ok());
367 ASSERT_TRUE(codegen.get() != NULL);
369 bool restore_sse_support =
false;
371 Value* llvm_data1 = codegen->CastPtrToLlvmPtr(codegen->ptr_type(),
372 const_cast<char*
>(data1));
373 Value* llvm_data2 = codegen->CastPtrToLlvmPtr(codegen->ptr_type(),
374 const_cast<char*
>(data2));
375 Value* llvm_len1 = codegen->GetIntConstant(
TYPE_INT, strlen(data1));
376 Value* llvm_len2 = codegen->GetIntConstant(
TYPE_INT, strlen(data2));
379 for (
int i = 0; i < 2; ++i) {
380 uint32_t expected_hash = 0;
381 expected_hash =
HashUtil::Hash(data1, strlen(data1), expected_hash);
382 expected_hash =
HashUtil::Hash(data2, strlen(data2), expected_hash);
383 expected_hash =
HashUtil::Hash(data1, strlen(data1), expected_hash);
392 Function* fn_fixed = prototype.GeneratePrototype(&builder, NULL);
393 Function* data1_hash_fn = codegen->GetHashFunction(strlen(data1));
394 Function* data2_hash_fn = codegen->GetHashFunction(strlen(data2));
395 Function* generic_hash_fn = codegen->GetHashFunction();
397 ASSERT_TRUE(data1_hash_fn != NULL);
398 ASSERT_TRUE(data2_hash_fn != NULL);
399 ASSERT_TRUE(generic_hash_fn != NULL);
401 Value* seed = codegen->GetIntConstant(
TYPE_INT, 0);
402 seed = builder.CreateCall3(data1_hash_fn, llvm_data1, llvm_len1, seed);
403 seed = builder.CreateCall3(data2_hash_fn, llvm_data2, llvm_len2, seed);
404 seed = builder.CreateCall3(generic_hash_fn, llvm_data1, llvm_len1, seed);
405 builder.CreateRet(seed);
407 fn_fixed = codegen->FinalizeFunction(fn_fixed);
408 ASSERT_TRUE(fn_fixed != NULL);
410 void* jitted_fn = LlvmCodeGenTest::JitFunction(codegen.get(), fn_fixed);
411 ASSERT_TRUE(jitted_fn != NULL);
413 typedef uint32_t (*TestHashFn)();
414 TestHashFn test_fn =
reinterpret_cast<TestHashFn
>(jitted_fn);
416 uint32_t result = test_fn();
419 EXPECT_EQ(result, expected_hash) << CpuInfo::IsSupported(CpuInfo::SSE4_2);
421 if (i == 0 && CpuInfo::IsSupported(CpuInfo::SSE4_2)) {
422 CpuInfo::EnableFeature(CpuInfo::SSE4_2,
false);
423 restore_sse_support =
true;
424 LlvmCodeGenTest::ClearHashFns(codegen.get());
432 CpuInfo::EnableFeature(CpuInfo::SSE4_2, restore_sse_support);
437 int main(
int argc,
char **argv) {
439 ::testing::InitGoogleTest(&argc, argv);
441 return RUN_ALL_TESTS();
llvm::PointerType * GetPtrType(llvm::Type *type)
Return a pointer type to 'type'.
Utility struct that wraps a variable name and llvm type.
static void LifetimeTest()
Status Init()
Initializes the jitter and execution engine.
void InitCommonRuntime(int argc, char **argv, bool init_jvm, TestInfo::Mode m=TestInfo::NON_TEST)
static void ClearHashFns(LlvmCodeGen *codegen)
static Status LoadFromFile(ObjectPool *pool, const string &filename, scoped_ptr< LlvmCodeGen > *codegen)
static void * JitFunction(LlvmCodeGen *codegen, Function *function)
Function * CodegenStringTest(LlvmCodeGen *codegen)
LLVM code generator. This is the top level object to generate jitted code.
int main(int argc, char **argv)
llvm::Function * GeneratePrototype(LlvmBuilder *builder=NULL, llvm::Value **params=NULL)
llvm::Value * CastPtrToLlvmPtr(llvm::Type *type, const void *ptr)
void AddArgument(const NamedVariable &var)
Add argument.
void ClearHashFns()
Clears generated hash fns. This is only used for testing.
static uint64_t Hash(const IntVal &v)
static LlvmCodeGen * CreateCodegen(ObjectPool *pool)
uint64_t Test(T *ht, const ProbeTuple *input, uint64_t num_tuples)
static void InitializeLlvm(bool load_backend=false)
llvm::Type * GetType(const ColumnType &type)
Returns llvm type for the column type.
llvm::Value * GetIntConstant(PrimitiveType type, int64_t val)
Returns the constant 'val' of 'type'.
TEST_F(LlvmCodeGenTest, HashTest)
void CodegenDebugTrace(LlvmBuilder *builder, const char *message)
llvm::LLVMContext & context()
void * JitFunction(llvm::Function *function)
Function * CodegenInnerLoop(LlvmCodeGen *codegen, int64_t *jitted_counter, int delta)