/*
* Copyright (C) 2014 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "base/arena_allocator.h"
#include "builder.h"
#include "dex_instruction.h"
#include "nodes.h"
#include "optimizing_unit_test.h"
#include "gtest/gtest.h"
namespace art {
static void TestCode(const uint16_t* data, const int* blocks, size_t blocks_length) {
ArenaPool pool;
ArenaAllocator allocator(&pool);
HGraph* graph = CreateGraph(&allocator);
HGraphBuilder builder(graph);
const DexFile::CodeItem* item = reinterpret_cast<const DexFile::CodeItem*>(data);
bool graph_built = builder.BuildGraph(*item);
ASSERT_TRUE(graph_built);
graph->BuildDominatorTree();
ASSERT_EQ(graph->GetBlocks().Size(), blocks_length);
for (size_t i = 0, e = blocks_length; i < e; ++i) {
if (blocks[i] == -1) {
if (graph->GetBlocks().Get(i) == nullptr) {
// Dead block.
} else {
// Only the entry block has no dominator.
ASSERT_EQ(nullptr, graph->GetBlocks().Get(i)->GetDominator());
ASSERT_TRUE(graph->GetBlocks().Get(i)->IsEntryBlock());
}
} else {
ASSERT_NE(nullptr, graph->GetBlocks().Get(i)->GetDominator());
ASSERT_EQ(blocks[i], graph->GetBlocks().Get(i)->GetDominator()->GetBlockId());
}
}
}
TEST(OptimizerTest, ReturnVoid) {
const uint16_t data[] = ZERO_REGISTER_CODE_ITEM(
Instruction::RETURN_VOID); // Block number 1
const int dominators[] = {
-1,
0,
1
};
TestCode(data, dominators, sizeof(dominators) / sizeof(int));
}
TEST(OptimizerTest, CFG1) {
const uint16_t data[] = ZERO_REGISTER_CODE_ITEM(
Instruction::GOTO | 0x100, // Block number 1
Instruction::RETURN_VOID); // Block number 2
const int dominators[] = {
-1,
0,
1,
2
};
TestCode(data, dominators, sizeof(dominators) / sizeof(int));
}
TEST(OptimizerTest, CFG2) {
const uint16_t data[] = ZERO_REGISTER_CODE_ITEM(
Instruction::GOTO | 0x100, // Block number 1
Instruction::GOTO | 0x100, // Block number 2
Instruction::RETURN_VOID); // Block number 3
const int dominators[] = {
-1,
0,
1,
2,
3
};
TestCode(data, dominators, sizeof(dominators) / sizeof(int));
}
TEST(OptimizerTest, CFG3) {
const uint16_t data1[] = ZERO_REGISTER_CODE_ITEM(
Instruction::GOTO | 0x200, // Block number 1
Instruction::RETURN_VOID, // Block number 2
Instruction::GOTO | 0xFF00); // Block number 3
const int dominators[] = {
-1,
0,
3,
1,
2
};
TestCode(data1, dominators, sizeof(dominators) / sizeof(int));
const uint16_t data2[] = ZERO_REGISTER_CODE_ITEM(
Instruction::GOTO_16, 3,
Instruction::RETURN_VOID,
Instruction::GOTO_16, 0xFFFF);
TestCode(data2, dominators, sizeof(dominators) / sizeof(int));
const uint16_t data3[] = ZERO_REGISTER_CODE_ITEM(
Instruction::GOTO_32, 4, 0,
Instruction::RETURN_VOID,
Instruction::GOTO_32, 0xFFFF, 0xFFFF);
TestCode(data3, dominators, sizeof(dominators) / sizeof(int));
}
TEST(OptimizerTest, CFG4) {
const uint16_t data1[] = ZERO_REGISTER_CODE_ITEM(
Instruction::NOP,
Instruction::GOTO | 0xFF00);
const int dominators[] = {
-1,
0,
-1
};
TestCode(data1, dominators, sizeof(dominators) / sizeof(int));
const uint16_t data2[] = ZERO_REGISTER_CODE_ITEM(
Instruction::GOTO_32, 0, 0);
TestCode(data2, dominators, sizeof(dominators) / sizeof(int));
}
TEST(OptimizerTest, CFG5) {
const uint16_t data[] = ZERO_REGISTER_CODE_ITEM(
Instruction::RETURN_VOID, // Block number 1
Instruction::GOTO | 0x100, // Dead block
Instruction::GOTO | 0xFE00); // Block number 2
const int dominators[] = {
-1,
0,
-1,
1
};
TestCode(data, dominators, sizeof(dominators) / sizeof(int));
}
TEST(OptimizerTest, CFG6) {
const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
Instruction::CONST_4 | 0 | 0,
Instruction::IF_EQ, 3,
Instruction::GOTO | 0x100,
Instruction::RETURN_VOID);
const int dominators[] = {
-1,
0,
1,
1,
3,
1, // Synthesized block to avoid critical edge.
};
TestCode(data, dominators, sizeof(dominators) / sizeof(int));
}
TEST(OptimizerTest, CFG7) {
const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
Instruction::CONST_4 | 0 | 0,
Instruction::IF_EQ, 3, // Block number 1
Instruction::GOTO | 0x100, // Block number 2
Instruction::GOTO | 0xFF00); // Block number 3
const int dominators[] = {
-1,
0,
1,
1,
-1, // exit block is not dominated by any block due to the spin loop.
1, // block to avoid critical edge.
1 // block to avoid critical edge.
};
TestCode(data, dominators, sizeof(dominators) / sizeof(int));
}
TEST(OptimizerTest, CFG8) {
const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
Instruction::CONST_4 | 0 | 0,
Instruction::IF_EQ, 3, // Block number 1
Instruction::GOTO | 0x200, // Block number 2
Instruction::GOTO | 0x100, // Block number 3
Instruction::GOTO | 0xFF00); // Block number 4
const int dominators[] = {
-1,
0,
1,
1,
1,
-1, // exit block is not dominated by any block due to the spin loop.
1 // block to avoid critical edge.
};
TestCode(data, dominators, sizeof(dominators) / sizeof(int));
}
TEST(OptimizerTest, CFG9) {
const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
Instruction::CONST_4 | 0 | 0,
Instruction::IF_EQ, 3, // Block number 1
Instruction::GOTO | 0x200, // Block number 2
Instruction::GOTO | 0x100, // Block number 3
Instruction::GOTO | 0xFE00); // Block number 4
const int dominators[] = {
-1,
0,
1,
1,
1,
-1, // exit block is not dominated by any block due to the spin loop.
1 // block to avoid critical edge.
};
TestCode(data, dominators, sizeof(dominators) / sizeof(int));
}
TEST(OptimizerTest, CFG10) {
const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
Instruction::CONST_4 | 0 | 0,
Instruction::IF_EQ, 6, // Block number 1
Instruction::IF_EQ, 3, // Block number 2
Instruction::GOTO | 0x100, // Block number 3
Instruction::GOTO | 0x100, // Block number 4
Instruction::RETURN_VOID); // Block number 5
const int dominators[] = {
-1,
0,
1,
2,
2,
1,
5, // Block number 5 dominates exit block
1, // block to avoid critical edge.
2 // block to avoid critical edge.
};
TestCode(data, dominators, sizeof(dominators) / sizeof(int));
}
} // namespace art