Impala
Impalaistheopensource,nativeanalyticdatabaseforApacheHadoop.
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros
instruction-counter-test.cc
Go to the documentation of this file.
1 // Copyright 2012 Cloudera Inc.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #include <boost/thread/thread.hpp>
16 #include <gtest/gtest.h>
17 #include <string>
18 
19 #include "llvm/IR/Module.h"
20 #include "llvm/IR/Function.h"
21 #include "llvm/PassManager.h"
22 #include "llvm/IR/CallingConv.h"
23 #include "llvm/Analysis/Verifier.h"
24 #include "llvm/Assembly/PrintModulePass.h"
25 #include "llvm/IR/IRBuilder.h"
26 
27 #include "codegen/llvm-codegen.h"
29 
30 #include "common/names.h"
31 using namespace llvm;
32 
33 namespace impala {
34 
35 class InstructionCounterTest : public testing:: Test {
36 };
37 
38 // IR output from CodegenMullAdd
39 // define i32 @mul_add(i32 %x, i32 %y, i32 %z) {
40 // entry:
41 // %tmp = mul i32 %x, %y
42 // %tmp2 = add i32 %tmp, %z
43 // ret i32 %tmp2
44 // }
45 // Create a module with one function, which multiplies two arguments, add a third and
46 // then returns the result.
47 Module* CodegenMulAdd(LLVMContext* context) {
48  Module* mod = new Module("test", *context);
49  Constant* c = mod->getOrInsertFunction("mul_add", IntegerType::get(*context, 32),
50  IntegerType::get(*context, 32), IntegerType::get(*context, 32),
51  IntegerType::get(*context, 32), NULL);
52  Function* mul_add = cast<Function>(c);
53  mul_add->setCallingConv(CallingConv::C);
54  Function::arg_iterator args = mul_add->arg_begin();
55  Value* x = args++;
56  x->setName("x");
57  Value* y = args++;
58  y->setName("y");
59  Value* z = args++;
60  z->setName("z");
61  BasicBlock* block = BasicBlock::Create(*context, "entry", mul_add);
62  IRBuilder<> builder(block);
63  Value* tmp = builder.CreateBinOp(Instruction::Mul, x, y, "tmp");
64  Value* tmp2 = builder.CreateBinOp(Instruction::Add, tmp, z, "tmp2");
65  builder.CreateRet(tmp2);
66  return mod;
67 }
68 
70  Module* MulAddModule = CodegenMulAdd(&getGlobalContext());
71  InstructionCounter* instruction_counter = new InstructionCounter();
72  instruction_counter->visit(*MulAddModule);
73  instruction_counter->PrintCounters();
74  EXPECT_EQ(instruction_counter->GetCount(InstructionCounter::TOTAL_FUNCTIONS), 1);
75  EXPECT_EQ(instruction_counter->GetCount(InstructionCounter::TOTAL_INSTS), 3);
76  EXPECT_EQ(instruction_counter->GetCount(InstructionCounter::TERMINATOR_INSTS), 1);
77  EXPECT_EQ(instruction_counter->GetCount(InstructionCounter::MEMORY_INSTS), 0);
78 
79  // Test Reset
80  instruction_counter->ResetCount();
81  EXPECT_EQ(instruction_counter->GetCount(InstructionCounter::TOTAL_FUNCTIONS), 0);
82  EXPECT_EQ(instruction_counter->GetCount(InstructionCounter::TOTAL_INSTS), 0);
83  EXPECT_EQ(instruction_counter->GetCount(InstructionCounter::MEMORY_INSTS), 0);
84 }
85 
86 // IR output from CodegenGcd
87 // define i32 @gcd(i32 %x, i32 %y) {
88 // entry:
89 // %tmp = icmp eq i32 %x, %y
90 // br i1 %tmp, label %return, label %cond_false
91 //
92 // return: ; preds = %entry
93 // ret i32 %x
94 //
95 // cond_false: ; preds = %entry
96 // %tmp2 = icmp ult i32 %x, %y
97 // br i1 %tmp2, label %cond_true, label %cond_false1
98 //
99 // cond_true: ; preds = %cond_false
100 // %tmp3 = sub i32 %y, %x
101 // %tmp4 = call i32 @gcd(i32 %x, i32 %tmp3)
102 // ret i32 %tmp4
103 //
104 // cond_false1: ; preds = %cond_false
105 // %tmp5 = sub i32 %x, %y
106 // %tmp6 = call i32 @gcd(i32 %tmp5, i32 %y)
107 // ret i32 %tmp6
108 // LLVM IR module which contains one function to return the GCD of two numbers
109 // }
110 Module* CodegenGcd(LLVMContext* context) {
111  Module* mod = new Module("gcd", *context);
112  Constant* c = mod->getOrInsertFunction("gcd", IntegerType::get(*context, 32),
113  IntegerType::get(*context, 32), IntegerType::get(*context, 32), NULL);
114  Function* gcd = cast<Function>(c);
115  Function::arg_iterator args = gcd->arg_begin();
116  Value* x = args++;
117  x->setName("x");
118  Value* y = args++;
119  y->setName("y");
120  BasicBlock* entry = BasicBlock::Create(*context, "entry", gcd);
121  BasicBlock* ret = BasicBlock::Create(*context, "return", gcd);
122  BasicBlock* cond_false = BasicBlock::Create(*context, "cond_false", gcd);
123  BasicBlock* cond_true = BasicBlock::Create(*context, "cond_true", gcd);
124  BasicBlock* cond_false_2 = BasicBlock::Create(*context, "cond_false", gcd);
125  IRBuilder<> builder(entry);
126  Value* xEqualsY = builder.CreateICmpEQ(x, y, "tmp");
127  builder.CreateCondBr(xEqualsY, ret, cond_false); builder.SetInsertPoint(ret);
128  builder.CreateRet(x);
129  builder.SetInsertPoint(cond_false);
130  Value* xLessThanY = builder.CreateICmpULT(x, y, "tmp");
131  builder.CreateCondBr(xLessThanY, cond_true, cond_false_2);
132  builder.SetInsertPoint(cond_true);
133  Value* yMinusX = builder.CreateSub(y, x, "tmp");
134  Value* args1[2] = {x , yMinusX};
135  Value* recur_1 = builder.CreateCall(gcd, args1, "tmp");
136  builder.CreateRet(recur_1);
137  builder.SetInsertPoint(cond_false_2);
138  Value* xMinusY = builder.CreateSub(x, y, "tmp");
139  Value* args2[2] = {xMinusY, y};
140  Value* recur_2 = builder.CreateCall(gcd, args2, "tmp");
141  builder.CreateRet(recur_2);
142  return mod;
143 }
144 
145 TEST_F(InstructionCounterTest, TestMemInstrCount) {
146  Module* GcdModule = CodegenGcd(&getGlobalContext());
147  InstructionCounter* instruction_counter = new InstructionCounter();
148  instruction_counter->visit(*GcdModule);
149  std::cout << instruction_counter->PrintCounters();
150  EXPECT_EQ(instruction_counter->GetCount(InstructionCounter::TOTAL_FUNCTIONS), 1);
151  EXPECT_EQ(instruction_counter->GetCount(InstructionCounter::TOTAL_BLOCKS), 5);
152  EXPECT_EQ(instruction_counter->GetCount(InstructionCounter::TOTAL_INSTS), 11);
153  // Test Category Totals
154  EXPECT_EQ(instruction_counter->GetCount(InstructionCounter::TERMINATOR_INSTS), 5);
155  EXPECT_EQ(instruction_counter->GetCount(InstructionCounter::MEMORY_INSTS), 0);
156  EXPECT_EQ(instruction_counter->GetCount(InstructionCounter::OTHER_INSTS), 4);
157 
158  // Test Reset
159  instruction_counter->ResetCount();
160  EXPECT_EQ(instruction_counter->GetCount(InstructionCounter::TOTAL_FUNCTIONS), 0);
161  EXPECT_EQ(instruction_counter->GetCount(InstructionCounter::TOTAL_BLOCKS), 0);
162  EXPECT_EQ(instruction_counter->GetCount(InstructionCounter::TOTAL_INSTS), 0);
163  EXPECT_EQ(instruction_counter->GetCount(InstructionCounter::TERMINATOR_INSTS), 0);
164  EXPECT_EQ(instruction_counter->GetCount(InstructionCounter::MEMORY_INSTS), 0);
165  EXPECT_EQ(instruction_counter->GetCount(InstructionCounter::OTHER_INSTS), 0);
166 }
167 
168 } // namespace impala
169 
170 int main(int argc, char **argv) {
171  ::testing::InitGoogleTest(&argc, argv);
172  return RUN_ALL_TESTS();
173 }
174 
BigIntVal Count(FunctionContext *context)
Definition: test-udfs.cc:183
TEST_F(InstructionCounterTest, TestMemInstrCount)
int GetCount(const char *name)
Return count of counter described by name.
void ResetCount()
Set all counts to 0.
Module * CodegenMulAdd(LLVMContext *context)
std::string PrintCounters() const
Prints all counters.
uint64_t Test(T *ht, const ProbeTuple *input, uint64_t num_tuples)
void visit(const llvm::Module &M)
Visits each Function in Module M.
Module * CodegenGcd(LLVMContext *context)
int main(int argc, char **argv)