codegen_test.cc revision 8a16d97fb8f031822b206e65f9109a071da40563
1/* 2 * Copyright (C) 2014 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17#include "builder.h" 18#include "code_generator_arm.h" 19#include "code_generator_x86.h" 20#include "code_generator_x86_64.h" 21#include "common_compiler_test.h" 22#include "dex_file.h" 23#include "dex_instruction.h" 24#include "instruction_set.h" 25#include "nodes.h" 26#include "optimizing_unit_test.h" 27 28#include "gtest/gtest.h" 29 30namespace art { 31 32class InternalCodeAllocator : public CodeAllocator { 33 public: 34 InternalCodeAllocator() { } 35 36 virtual uint8_t* Allocate(size_t size) { 37 size_ = size; 38 memory_.reset(new uint8_t[size]); 39 return memory_.get(); 40 } 41 42 size_t GetSize() const { return size_; } 43 uint8_t* GetMemory() const { return memory_.get(); } 44 45 private: 46 size_t size_; 47 std::unique_ptr<uint8_t[]> memory_; 48 49 DISALLOW_COPY_AND_ASSIGN(InternalCodeAllocator); 50}; 51 52#if defined(__i386__) || defined(__arm__) || defined(__x86_64__) 53static void Run(const InternalCodeAllocator& allocator, 54 const CodeGenerator& codegen, 55 bool has_result, 56 int32_t expected) { 57 typedef int32_t (*fptr)(); 58 CommonCompilerTest::MakeExecutable(allocator.GetMemory(), allocator.GetSize()); 59 fptr f = reinterpret_cast<fptr>(allocator.GetMemory()); 60 if (codegen.GetInstructionSet() == kThumb2) { 61 // For thumb we need the bottom bit set. 62 f = reinterpret_cast<fptr>(reinterpret_cast<uintptr_t>(f) + 1); 63 } 64 int32_t result = f(); 65 if (has_result) { 66 CHECK_EQ(result, expected); 67 } 68} 69#endif 70 71static void TestCode(const uint16_t* data, bool has_result = false, int32_t expected = 0) { 72 ArenaPool pool; 73 ArenaAllocator arena(&pool); 74 HGraphBuilder builder(&arena); 75 const DexFile::CodeItem* item = reinterpret_cast<const DexFile::CodeItem*>(data); 76 HGraph* graph = builder.BuildGraph(*item); 77 ASSERT_NE(graph, nullptr); 78 InternalCodeAllocator allocator; 79 80 x86::CodeGeneratorX86 codegenX86(graph); 81 // We avoid doing a stack overflow check that requires the runtime being setup, 82 // by making sure the compiler knows the methods we are running are leaf methods. 83 codegenX86.CompileBaseline(&allocator, true); 84 if (kRuntimeISA == kX86) { 85 Run(allocator, codegenX86, has_result, expected); 86 } 87 88 arm::CodeGeneratorARM codegenARM(graph); 89 codegenARM.CompileBaseline(&allocator, true); 90 if (kRuntimeISA == kArm || kRuntimeISA == kThumb2) { 91 Run(allocator, codegenARM, has_result, expected); 92 } 93 94 x86_64::CodeGeneratorX86_64 codegenX86_64(graph); 95 codegenX86_64.CompileBaseline(&allocator, true); 96 if (kRuntimeISA == kX86_64) { 97 Run(allocator, codegenX86_64, has_result, expected); 98 } 99} 100 101TEST(CodegenTest, ReturnVoid) { 102 const uint16_t data[] = ZERO_REGISTER_CODE_ITEM(Instruction::RETURN_VOID); 103 TestCode(data); 104} 105 106TEST(CodegenTest, CFG1) { 107 const uint16_t data[] = ZERO_REGISTER_CODE_ITEM( 108 Instruction::GOTO | 0x100, 109 Instruction::RETURN_VOID); 110 111 TestCode(data); 112} 113 114TEST(CodegenTest, CFG2) { 115 const uint16_t data[] = ZERO_REGISTER_CODE_ITEM( 116 Instruction::GOTO | 0x100, 117 Instruction::GOTO | 0x100, 118 Instruction::RETURN_VOID); 119 120 TestCode(data); 121} 122 123TEST(CodegenTest, CFG3) { 124 const uint16_t data1[] = ZERO_REGISTER_CODE_ITEM( 125 Instruction::GOTO | 0x200, 126 Instruction::RETURN_VOID, 127 Instruction::GOTO | 0xFF00); 128 129 TestCode(data1); 130 131 const uint16_t data2[] = ZERO_REGISTER_CODE_ITEM( 132 Instruction::GOTO_16, 3, 133 Instruction::RETURN_VOID, 134 Instruction::GOTO_16, 0xFFFF); 135 136 TestCode(data2); 137 138 const uint16_t data3[] = ZERO_REGISTER_CODE_ITEM( 139 Instruction::GOTO_32, 4, 0, 140 Instruction::RETURN_VOID, 141 Instruction::GOTO_32, 0xFFFF, 0xFFFF); 142 143 TestCode(data3); 144} 145 146TEST(CodegenTest, CFG4) { 147 const uint16_t data[] = ZERO_REGISTER_CODE_ITEM( 148 Instruction::RETURN_VOID, 149 Instruction::GOTO | 0x100, 150 Instruction::GOTO | 0xFE00); 151 152 TestCode(data); 153} 154 155TEST(CodegenTest, CFG5) { 156 const uint16_t data[] = ONE_REGISTER_CODE_ITEM( 157 Instruction::CONST_4 | 0 | 0, 158 Instruction::IF_EQ, 3, 159 Instruction::GOTO | 0x100, 160 Instruction::RETURN_VOID); 161 162 TestCode(data); 163} 164 165TEST(CodegenTest, IntConstant) { 166 const uint16_t data[] = ONE_REGISTER_CODE_ITEM( 167 Instruction::CONST_4 | 0 | 0, 168 Instruction::RETURN_VOID); 169 170 TestCode(data); 171} 172 173TEST(CodegenTest, Return1) { 174 const uint16_t data[] = ONE_REGISTER_CODE_ITEM( 175 Instruction::CONST_4 | 0 | 0, 176 Instruction::RETURN | 0); 177 178 TestCode(data, true, 0); 179} 180 181TEST(CodegenTest, Return2) { 182 const uint16_t data[] = TWO_REGISTERS_CODE_ITEM( 183 Instruction::CONST_4 | 0 | 0, 184 Instruction::CONST_4 | 0 | 1 << 8, 185 Instruction::RETURN | 1 << 8); 186 187 TestCode(data, true, 0); 188} 189 190TEST(CodegenTest, Return3) { 191 const uint16_t data[] = TWO_REGISTERS_CODE_ITEM( 192 Instruction::CONST_4 | 0 | 0, 193 Instruction::CONST_4 | 1 << 8 | 1 << 12, 194 Instruction::RETURN | 1 << 8); 195 196 TestCode(data, true, 1); 197} 198 199TEST(CodegenTest, ReturnIf1) { 200 const uint16_t data[] = TWO_REGISTERS_CODE_ITEM( 201 Instruction::CONST_4 | 0 | 0, 202 Instruction::CONST_4 | 1 << 8 | 1 << 12, 203 Instruction::IF_EQ, 3, 204 Instruction::RETURN | 0 << 8, 205 Instruction::RETURN | 1 << 8); 206 207 TestCode(data, true, 1); 208} 209 210TEST(CodegenTest, ReturnIf2) { 211 const uint16_t data[] = TWO_REGISTERS_CODE_ITEM( 212 Instruction::CONST_4 | 0 | 0, 213 Instruction::CONST_4 | 1 << 8 | 1 << 12, 214 Instruction::IF_EQ | 0 << 4 | 1 << 8, 3, 215 Instruction::RETURN | 0 << 8, 216 Instruction::RETURN | 1 << 8); 217 218 TestCode(data, true, 0); 219} 220 221TEST(CodegenTest, ReturnAdd1) { 222 const uint16_t data[] = TWO_REGISTERS_CODE_ITEM( 223 Instruction::CONST_4 | 3 << 12 | 0, 224 Instruction::CONST_4 | 4 << 12 | 1 << 8, 225 Instruction::ADD_INT, 1 << 8 | 0, 226 Instruction::RETURN); 227 228 TestCode(data, true, 7); 229} 230 231TEST(CodegenTest, ReturnAdd2) { 232 const uint16_t data[] = TWO_REGISTERS_CODE_ITEM( 233 Instruction::CONST_4 | 3 << 12 | 0, 234 Instruction::CONST_4 | 4 << 12 | 1 << 8, 235 Instruction::ADD_INT_2ADDR | 1 << 12, 236 Instruction::RETURN); 237 238 TestCode(data, true, 7); 239} 240 241TEST(CodegenTest, ReturnAdd3) { 242 const uint16_t data[] = ONE_REGISTER_CODE_ITEM( 243 Instruction::CONST_4 | 4 << 12 | 0 << 8, 244 Instruction::ADD_INT_LIT8, 3 << 8 | 0, 245 Instruction::RETURN); 246 247 TestCode(data, true, 7); 248} 249 250TEST(CodegenTest, ReturnAdd4) { 251 const uint16_t data[] = ONE_REGISTER_CODE_ITEM( 252 Instruction::CONST_4 | 4 << 12 | 0 << 8, 253 Instruction::ADD_INT_LIT16, 3, 254 Instruction::RETURN); 255 256 TestCode(data, true, 7); 257} 258 259} // namespace art 260