1 : // Copyright 2013 Google Inc. All Rights Reserved.
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 "syzygy/optimize/transforms/peephole_transform.h"
16 :
17 : #include "gmock/gmock.h"
18 : #include "gtest/gtest.h"
19 : #include "syzygy/block_graph/basic_block_decomposer.h"
20 : #include "syzygy/block_graph/basic_block_subgraph.h"
21 : #include "syzygy/block_graph/block_builder.h"
22 : #include "syzygy/block_graph/block_graph.h"
23 : #include "syzygy/optimize/application_profile.h"
24 : #include "syzygy/pe/pe_transform_policy.h"
25 :
26 : namespace optimize {
27 : namespace transforms {
28 :
29 : namespace {
30 :
31 : using block_graph::BasicBlock;
32 : using block_graph::BasicBlockDecomposer;
33 : using block_graph::BasicBlockSubGraph;
34 : using block_graph::BasicCodeBlock;
35 : using block_graph::BlockBuilder;
36 : using block_graph::BlockGraph;
37 : using pe::ImageLayout;
38 : using testing::ElementsAreArray;
39 : typedef BasicBlock::Instructions Instructions;
40 :
41 : // _asm push ebp
42 : // _asm mov ebp, esp
43 : // _asm pop ebp
44 : // _asm xor eax, eax
45 : // _asm ret
46 : const uint8 kPrologEpilog[] = { 0x55, 0x8B, 0xEC, 0x5D, 0x33, 0xC0, 0xC3 };
47 :
48 : const uint8 kTwicePrologEpilog[] =
49 : { 0x55, 0x8B, 0xEC, 0x5D, 0x55, 0x8B, 0xEC, 0x5D, 0x33, 0xC0, 0xC3 };
50 :
51 : // _asm xor eax, eax
52 : // _asm ret
53 : const uint8 kRet0[] = { 0x33, 0xC0, 0xC3 };
54 :
55 : enum TransformKind {
56 : ktransformBlock,
57 : ktransformSubgraph
58 : };
59 :
60 : class PeepholeTransformTest : public testing::Test {
61 : public:
62 : PeepholeTransformTest()
63 : : image_(&block_graph_),
64 : profile_(&image_),
65 E : block_(NULL) {
66 E : }
67 :
68 : void TransformBlock(TransformKind kind, const uint8* data, size_t length);
69 :
70 : protected:
71 : pe::PETransformPolicy policy_;
72 : BlockGraph block_graph_;
73 : ImageLayout image_;
74 : BlockGraph::Block* block_;
75 : PeepholeTransform tx_;
76 : ApplicationProfile profile_;
77 : SubGraphProfile subgraph_profile_;
78 : };
79 :
80 : void PeepholeTransformTest::TransformBlock(TransformKind kind,
81 : const uint8* data,
82 E : size_t length) {
83 E : DCHECK_NE(reinterpret_cast<const uint8*>(NULL), data);
84 :
85 : // Create a dummy block.
86 E : block_ = block_graph_.AddBlock(BlockGraph::CODE_BLOCK, length, "test");
87 E : DCHECK_NE(reinterpret_cast<BlockGraph::Block*>(NULL), block_);
88 E : block_->SetData(data, length);
89 E : block_->SetLabel(0, "code", BlockGraph::CODE_LABEL);
90 :
91 : // Decompose to subgraph.
92 E : BasicBlockSubGraph subgraph;
93 E : BasicBlockDecomposer decomposer(block_, &subgraph);
94 E : ASSERT_TRUE(decomposer.Decompose());
95 :
96 E : switch (kind) {
97 : case ktransformBlock: {
98 : // Apply peephole transform.
99 E : PeepholeTransform tx;
100 : ASSERT_TRUE(
101 : tx_.TransformBasicBlockSubGraph(&policy_, &block_graph_, &subgraph,
102 E : &profile_, &subgraph_profile_));
103 E : break;
104 : }
105 : case ktransformSubgraph: {
106 : // Apply peephole simplification on subgraph.
107 E : ASSERT_TRUE(PeepholeTransform::SimplifySubgraph(&subgraph));
108 : break;
109 : }
110 : }
111 :
112 : // Rebuild block.
113 E : BlockBuilder builder(&block_graph_);
114 E : ASSERT_TRUE(builder.Merge(&subgraph));
115 E : CHECK_EQ(1u, builder.new_blocks().size());
116 E : block_ = *builder.new_blocks().begin();
117 E : };
118 :
119 : } // namespace
120 :
121 E : TEST_F(PeepholeTransformTest, SimplifyEmptyPrologEpilogBlock) {
122 : ASSERT_NO_FATAL_FAILURE(
123 E : TransformBlock(ktransformBlock, kPrologEpilog, sizeof(kPrologEpilog)));
124 E : EXPECT_THAT(kRet0, ElementsAreArray(block_->data(), block_->size()));
125 E : }
126 :
127 E : TEST_F(PeepholeTransformTest, SimplifyEmptyPrologEpilogSubgraph) {
128 : ASSERT_NO_FATAL_FAILURE(
129 E : TransformBlock(ktransformSubgraph, kPrologEpilog, sizeof(kPrologEpilog)));
130 E : EXPECT_THAT(kRet0, ElementsAreArray(block_->data(), block_->size()));
131 E : }
132 :
133 E : TEST_F(PeepholeTransformTest, SimplifyEmptyPrologEpilogTwice) {
134 : ASSERT_NO_FATAL_FAILURE(
135 : TransformBlock(ktransformBlock,
136 : kTwicePrologEpilog,
137 E : sizeof(kTwicePrologEpilog)));
138 E : EXPECT_THAT(kRet0, ElementsAreArray(block_->data(), block_->size()));
139 E : }
140 :
141 : } // namespace transforms
142 : } // namespace optimize
|