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 : // Unittests for memory access analysis.
16 :
17 : #include "syzygy/block_graph/analysis/memory_access_analysis.h"
18 :
19 : #include "gtest/gtest.h"
20 : #include "mnemonics.h" // NOLINT
21 :
22 : namespace block_graph {
23 : namespace analysis {
24 :
25 : namespace {
26 :
27 : typedef block_graph::analysis::MemoryAccessAnalysis::State State;
28 : typedef block_graph::BasicBlockSubGraph::BasicBlock BasicBlock;
29 : typedef block_graph::BasicBlockSubGraph::BasicBlock::Instructions Instructions;
30 : typedef BasicBlockSubGraph::BlockDescription BlockDescription;
31 :
32 : // _asm add eax, ecx
33 : const uint8 kClearEax[] = { 0x03, 0xC1 };
34 : // _asm add ecx, [eax]
35 : const uint8 kReadEax[] = { 0x03, 0x08 };
36 : // _asm add ecx, [eax + 42]
37 : const uint8 kReadEax42[] = { 0x03, 0x48, 0x2A };
38 : // _asm add eax, ecx
39 : const uint8 kRegsOnly[] = { 0x03, 0xC1 };
40 : // _asm add [eax + ebx*2 + 42], ecx
41 : const uint8 kWriteWithScale[] = { 0x01, 0x4C, 0x58, 0x2A };
42 : // _asm add DWORD PTR [X], ecx
43 : const uint8 kWriteDispl[] = { 0x01, 0x0D, 0x80, 0x1E, 0xF2, 0x00 };
44 : // _asm add [eax + 42], ecx
45 : const uint8 kWriteEax42[] = { 0x01, 0x48, 0x2A };
46 : // _asm lea ecx, [eax]
47 : const uint8 kLeaEax[] = { 0x8D, 0x08 };
48 : // _asm lea ecx, [eax + 42]
49 : const uint8 kLeaEax42[] = { 0x8D, 0x48, 0x2A };
50 :
51 : // _asm repnz movsb
52 : const uint8 kRepMovsb[] = { 0xF2, 0xA4 };
53 :
54 : // _asm add ecx, [eax + C]
55 : const uint8 kReadEax10[] = { 0x03, 0x48, 0x0A };
56 : const uint8 kReadEax11[] = { 0x03, 0x48, 0x0B };
57 : const uint8 kReadEax12[] = { 0x03, 0x48, 0x0C };
58 : const uint8 kReadEax13[] = { 0x03, 0x48, 0x0D };
59 : const uint8 kReadEax14[] = { 0x03, 0x48, 0x0E };
60 : const uint8 kReadEax15[] = { 0x03, 0x48, 0x0F };
61 :
62 : // _asm ret
63 : const uint8 kRet[] = { 0xC3 };
64 : // _asm call <FFFFFFFF>
65 : const uint8 kCall[] = { 0xE8, 0xFF, 0xD7, 0xFF, 0xFF };
66 : // _asm rdtsc
67 : const uint8 kRdtsc[] = { 0x0F, 0x31 };
68 :
69 : void AddSuccessorBetween(Successor::Condition condition,
70 : BasicCodeBlock* from,
71 E : BasicCodeBlock* to) {
72 : from->successors().push_back(
73 : Successor(condition,
74 : BasicBlockReference(BlockGraph::RELATIVE_REF,
75 : BlockGraph::Reference::kMaximumSize,
76 : to),
77 E : 0));
78 E : }
79 :
80 : } // namespace
81 :
82 : class TestMemoryAccessAnalysisState: public MemoryAccessAnalysis::State {
83 : public:
84 : bool IsEmpty(const core::Register32& reg) const;
85 : bool IsEmpty() const;
86 : bool Contains(const core::Register32& reg, int32 displ) const;
87 :
88 : template<size_t N>
89 : bool HasNonRedundantAccess(const uint8 (& data)[N]) const;
90 :
91 : template<size_t N>
92 : void Execute(const uint8 (& data)[N]);
93 :
94 : using MemoryAccessAnalysis::State::Clear;
95 : };
96 :
97 : class TestMemoryAccessAnalysis: public MemoryAccessAnalysis {
98 : public:
99 : using MemoryAccessAnalysis::Intersect;
100 : };
101 :
102 : class MemoryAccessAnalysisTest : public testing::Test {
103 : public:
104 E : MemoryAccessAnalysisTest() : bb_(NULL) {
105 E : bb_ = subgraph_.AddBasicCodeBlock("Dummy");
106 E : }
107 :
108 E : bool Intersect(const block_graph::BasicBlock* bb, const State& state) {
109 E : return memory_access_.Intersect(bb, state);
110 E : }
111 :
112 E : void GetStateAtEntryOf(const BasicBlock* bb, State* state) const {
113 E : return memory_access_.GetStateAtEntryOf(bb, state);
114 E : }
115 :
116 : template<size_t N>
117 : void PropagateForward(const uint8 (& data)[N]);
118 :
119 : protected:
120 : TestMemoryAccessAnalysis memory_access_;
121 : TestMemoryAccessAnalysisState state_;
122 : BasicBlockSubGraph subgraph_;
123 : BasicCodeBlock* bb_;
124 : };
125 :
126 E : bool TestMemoryAccessAnalysisState::IsEmpty(const core::Register32& reg) const {
127 E : return active_memory_accesses_[reg.id() - core::kRegister32Min].empty();
128 E : }
129 :
130 E : bool TestMemoryAccessAnalysisState::IsEmpty() const {
131 E : for (int r = 0; r < core::kRegister32Count; ++r) {
132 E : if (!IsEmpty(core::kRegisters32[r]))
133 E : return false;
134 E : }
135 E : return true;
136 E : }
137 :
138 : bool TestMemoryAccessAnalysisState::Contains(
139 E : const core::Register32& reg, int32 displ) const {
140 : const std::set<int32>& offsets = active_memory_accesses_[
141 E : reg.id() - core::kRegister32Min];
142 E : return offsets.find(displ) != offsets.end();
143 E : }
144 :
145 : template<size_t N>
146 : bool TestMemoryAccessAnalysisState::HasNonRedundantAccess(
147 E : const uint8 (& data)[N]) const {
148 : // Decode an instruction.
149 E : DCHECK_GT(core::AssemblerImpl::kMaxInstructionLength, N);
150 :
151 E : block_graph::Instruction temp;
152 E : bool decoded = block_graph::Instruction::FromBuffer(&data[0], N, &temp);
153 E : DCHECK(decoded);
154 :
155 : // Expect to decode the entire buffer.
156 E : DCHECK_EQ(N, temp.size());
157 :
158 : // Execute the decoded instruction, and modify the current state.
159 E : return MemoryAccessAnalysis::State::HasNonRedundantAccess(temp);
160 E : }
161 :
162 : template<size_t N>
163 E : void TestMemoryAccessAnalysisState::Execute(const uint8 (& data)[N]) {
164 : // Decode an instruction.
165 E : DCHECK_GT(core::AssemblerImpl::kMaxInstructionLength, N);
166 :
167 E : block_graph::Instruction temp;
168 E : bool decoded = block_graph::Instruction::FromBuffer(&data[0], N, &temp);
169 E : DCHECK(decoded);
170 :
171 : // Expect to decode the entire buffer.
172 E : DCHECK_EQ(N, temp.size());
173 :
174 : // Execute the decoded instruction, and modify the current state.
175 E : MemoryAccessAnalysis::State::Execute(temp);
176 E : }
177 :
178 : template<size_t N>
179 : void MemoryAccessAnalysisTest::PropagateForward(
180 E : const uint8 (& data)[N]) {
181 : // Decode an instruction.
182 E : DCHECK_GT(core::AssemblerImpl::kMaxInstructionLength, N);
183 :
184 E : block_graph::Instruction temp;
185 E : bool decoded = block_graph::Instruction::FromBuffer(&data[0], N, &temp);
186 E : ASSERT_TRUE(decoded);
187 :
188 : // Expect to decode the entire buffer.
189 E : ASSERT_EQ(N, temp.size());
190 :
191 : // Execute the decoded instruction, and modify the current state.
192 E : MemoryAccessAnalysis::PropagateForward(temp, &state_);
193 E : }
194 :
195 E : TEST(MemoryAccessAnalysisStateTest, Constructor) {
196 : // Initial state is empty.
197 E : TestMemoryAccessAnalysisState state;
198 E : EXPECT_TRUE(state.IsEmpty());
199 E : }
200 :
201 E : TEST(MemoryAccessAnalysisStateTest, CopyConstructor) {
202 E : TestMemoryAccessAnalysisState state1;
203 :
204 E : state1.Execute(kReadEax);
205 E : state1.Execute(kWriteEax42);
206 :
207 E : EXPECT_TRUE(state1.Contains(core::eax, 0));
208 E : EXPECT_TRUE(state1.Contains(core::eax, 42));
209 :
210 : // Expect memory accesses to be copied into state2.
211 E : TestMemoryAccessAnalysisState state2(state1);
212 E : EXPECT_TRUE(state2.Contains(core::eax, 0));
213 E : EXPECT_TRUE(state2.Contains(core::eax, 42));
214 E : }
215 :
216 E : TEST(MemoryAccessAnalysisStateTest, Clear) {
217 E : TestMemoryAccessAnalysisState state;
218 :
219 E : state.Execute(kWriteEax42);
220 E : EXPECT_TRUE(!state.IsEmpty());
221 E : state.Clear();
222 E : EXPECT_TRUE(state.IsEmpty());
223 E : }
224 :
225 E : TEST(MemoryAccessAnalysisStateTest, ExecuteOperandKind) {
226 E : TestMemoryAccessAnalysisState state;
227 :
228 E : state.Execute(kRegsOnly);
229 E : EXPECT_TRUE(state.IsEmpty());
230 :
231 E : state.Execute(kWriteWithScale);
232 E : EXPECT_TRUE(state.IsEmpty());
233 :
234 E : state.Execute(kWriteDispl);
235 E : EXPECT_TRUE(state.IsEmpty());
236 :
237 E : state.Execute(kReadEax);
238 E : EXPECT_TRUE(state.Contains(core::eax, 0));
239 :
240 E : state.Execute(kReadEax42);
241 E : EXPECT_TRUE(state.Contains(core::eax, 42));
242 E : }
243 :
244 E : TEST(MemoryAccessAnalysisStateTest, LeaOperand) {
245 E : TestMemoryAccessAnalysisState state;
246 :
247 : // LEA do not perform a memory access.
248 E : state.Execute(kLeaEax);
249 E : EXPECT_FALSE(state.Contains(core::eax, 0));
250 E : state.Execute(kLeaEax42);
251 E : EXPECT_FALSE(state.Contains(core::eax, 42));
252 E : }
253 :
254 E : TEST(MemoryAccessAnalysisStateTest, ExecuteWithPrefix) {
255 E : TestMemoryAccessAnalysisState state;
256 :
257 E : state.Execute(kRepMovsb);
258 E : EXPECT_TRUE(state.IsEmpty());
259 E : }
260 :
261 E : TEST(MemoryAccessAnalysisStateTest, HasNonRedundantAccess) {
262 E : TestMemoryAccessAnalysisState state;
263 :
264 : // Initial state is empty, and accesses are not redundant.
265 E : bool redundant_read1 = state.HasNonRedundantAccess(kReadEax42);
266 E : bool redundant_write1 = state.HasNonRedundantAccess(kWriteEax42);
267 E : EXPECT_TRUE(redundant_read1);
268 E : EXPECT_TRUE(redundant_write1);
269 :
270 : // Perform a read of [eax + 42].
271 E : state.Execute(kReadEax42);
272 E : EXPECT_TRUE(state.Contains(core::eax, 42));
273 :
274 : // After the read, accesses are redundant.
275 E : bool redundant_read2 = state.HasNonRedundantAccess(kReadEax42);
276 E : bool redundant_write2 = state.HasNonRedundantAccess(kWriteEax42);
277 E : EXPECT_FALSE(redundant_read2);
278 E : EXPECT_FALSE(redundant_write2);
279 E : }
280 :
281 E : TEST(MemoryAccessAnalysisStateTest, HasNonRedundantAccessOperandKind) {
282 E : TestMemoryAccessAnalysisState state;
283 :
284 : // Instructions without memory access, on empty state.
285 E : EXPECT_FALSE(state.HasNonRedundantAccess(kRegsOnly));
286 E : EXPECT_FALSE(state.HasNonRedundantAccess(kLeaEax));
287 E : EXPECT_FALSE(state.HasNonRedundantAccess(kLeaEax42));
288 :
289 : // Initial state is empty, and accesses are not redundant.
290 E : EXPECT_TRUE(state.HasNonRedundantAccess(kReadEax));
291 E : EXPECT_TRUE(state.HasNonRedundantAccess(kReadEax42));
292 E : EXPECT_TRUE(state.HasNonRedundantAccess(kWriteWithScale));
293 E : EXPECT_TRUE(state.HasNonRedundantAccess(kWriteDispl));
294 E : EXPECT_TRUE(state.HasNonRedundantAccess(kWriteEax42));
295 E : }
296 :
297 E : TEST(MemoryAccessAnalysisStateTest, HasNonRedundantAccessWithPrefix) {
298 E : TestMemoryAccessAnalysisState state;
299 E : state.Execute(kRepMovsb);
300 E : bool redundant = state.HasNonRedundantAccess(kRepMovsb);
301 E : EXPECT_TRUE(redundant);
302 E : }
303 :
304 E : TEST_F(MemoryAccessAnalysisTest, GetStateOf) {
305 : // It is valid to get the state of a NULL block.
306 E : GetStateAtEntryOf(NULL, &state_);
307 E : EXPECT_TRUE(state_.IsEmpty());
308 :
309 : // Get an non-existing basic block.
310 E : GetStateAtEntryOf(bb_, &state_);
311 E : EXPECT_TRUE(state_.IsEmpty());
312 E : }
313 :
314 E : TEST_F(MemoryAccessAnalysisTest, IntersectEmpty) {
315 E : memory_access_.GetStateAtEntryOf(bb_, &state_);
316 E : EXPECT_TRUE(state_.IsEmpty());
317 :
318 : // Perform an initial intersection with an empty set.
319 E : TestMemoryAccessAnalysisState state;
320 E : Intersect(bb_, state);
321 :
322 E : state.Execute(kReadEax10);
323 E : state.Execute(kReadEax11);
324 :
325 : // Perform an second intersection with a non empty set.
326 E : Intersect(bb_, state_);
327 E : GetStateAtEntryOf(bb_, &state_);
328 :
329 : // The results must be empty.
330 E : EXPECT_TRUE(state_.IsEmpty());
331 E : }
332 :
333 E : TEST_F(MemoryAccessAnalysisTest, IntersectStates) {
334 : // Intersection with displacements [10, 11, 12, 13, 14, 15].
335 E : TestMemoryAccessAnalysisState state1;
336 E : state1.Execute(kReadEax10);
337 E : state1.Execute(kReadEax11);
338 E : state1.Execute(kReadEax12);
339 E : state1.Execute(kReadEax13);
340 E : state1.Execute(kReadEax14);
341 E : state1.Execute(kReadEax15);
342 E : Intersect(bb_, state1);
343 :
344 : // Intersection with displacements [10, 11, 12, 14].
345 E : TestMemoryAccessAnalysisState state2;
346 E : state2.Execute(kReadEax10);
347 E : state2.Execute(kReadEax11);
348 E : state2.Execute(kReadEax12);
349 E : state2.Execute(kReadEax14);
350 E : Intersect(bb_, state2);
351 :
352 : // Check current state [10, 11, 12, 14].
353 E : GetStateAtEntryOf(bb_, &state_);
354 E : EXPECT_TRUE(state_.Contains(core::eax, 10));
355 E : EXPECT_TRUE(state_.Contains(core::eax, 11));
356 E : EXPECT_TRUE(state_.Contains(core::eax, 12));
357 E : EXPECT_FALSE(state_.Contains(core::eax, 13));
358 E : EXPECT_TRUE(state_.Contains(core::eax, 14));
359 E : EXPECT_FALSE(state_.Contains(core::eax, 15));
360 :
361 : // Intersection with displacements [10, 11, 15].
362 E : TestMemoryAccessAnalysisState state3;
363 E : state3.Execute(kReadEax10);
364 E : state3.Execute(kReadEax11);
365 E : state3.Execute(kReadEax15);
366 E : Intersect(bb_, state3);
367 :
368 : // Check current state [10, 11].
369 E : GetStateAtEntryOf(bb_, &state_);
370 E : EXPECT_TRUE(state_.Contains(core::eax, 10));
371 E : EXPECT_TRUE(state_.Contains(core::eax, 11));
372 E : EXPECT_FALSE(state_.Contains(core::eax, 12));
373 E : EXPECT_FALSE(state_.Contains(core::eax, 13));
374 E : EXPECT_FALSE(state_.Contains(core::eax, 14));
375 E : EXPECT_FALSE(state_.Contains(core::eax, 15));
376 :
377 : // Intersection with displacements [15].
378 E : TestMemoryAccessAnalysisState state4;
379 E : state4.Execute(kReadEax15);
380 E : Intersect(bb_, state4);
381 :
382 : // The state must be empty.
383 E : GetStateAtEntryOf(bb_, &state_);
384 E : EXPECT_TRUE(state_.IsEmpty());
385 E : }
386 :
387 E : TEST_F(MemoryAccessAnalysisTest, PropagateForwardSimple) {
388 E : ASSERT_NO_FATAL_FAILURE(PropagateForward(kReadEax10));
389 E : EXPECT_TRUE(state_.Contains(core::eax, 10));
390 :
391 E : ASSERT_NO_FATAL_FAILURE(PropagateForward(kReadEax));
392 E : EXPECT_TRUE(state_.Contains(core::eax, 0));
393 E : EXPECT_TRUE(state_.Contains(core::eax, 10));
394 :
395 E : ASSERT_NO_FATAL_FAILURE(PropagateForward(kClearEax));
396 E : EXPECT_TRUE(state_.IsEmpty());
397 :
398 E : ASSERT_NO_FATAL_FAILURE(PropagateForward(kLeaEax));
399 E : EXPECT_TRUE(state_.IsEmpty());
400 E : }
401 :
402 E : TEST_F(MemoryAccessAnalysisTest, PropagateForwardWithCallRet) {
403 E : ASSERT_NO_FATAL_FAILURE(PropagateForward(kReadEax10));
404 E : EXPECT_TRUE(state_.Contains(core::eax, 10));
405 E : ASSERT_NO_FATAL_FAILURE(PropagateForward(kCall));
406 E : EXPECT_TRUE(state_.IsEmpty());
407 :
408 E : ASSERT_NO_FATAL_FAILURE(PropagateForward(kReadEax10));
409 E : EXPECT_TRUE(state_.Contains(core::eax, 10));
410 E : ASSERT_NO_FATAL_FAILURE(PropagateForward(kRet));
411 E : EXPECT_TRUE(state_.IsEmpty());
412 E : }
413 :
414 E : TEST_F(MemoryAccessAnalysisTest, UnknownInstruction) {
415 : // Ensure unknown instructions are processed correctly.
416 E : ASSERT_NO_FATAL_FAILURE(PropagateForward(kReadEax10));
417 E : EXPECT_TRUE(state_.Contains(core::eax, 10));
418 E : ASSERT_NO_FATAL_FAILURE(PropagateForward(kRdtsc));
419 E : EXPECT_TRUE(state_.IsEmpty());
420 E : }
421 :
422 E : TEST_F(MemoryAccessAnalysisTest, Analyze) {
423 E : BasicBlockSubGraph subgraph;
424 :
425 : BlockDescription* block = subgraph.AddBlockDescription(
426 E : "b1", "b1.obj", BlockGraph::CODE_BLOCK, 7, 2, 42);
427 :
428 E : BasicCodeBlock* bb_if = subgraph.AddBasicCodeBlock("if");
429 E : BasicCodeBlock* bb_true = subgraph.AddBasicCodeBlock("true");
430 E : BasicCodeBlock* bb_false = subgraph.AddBasicCodeBlock("false");
431 E : BasicCodeBlock* bb_end = subgraph.AddBasicCodeBlock("end");
432 :
433 E : ASSERT_TRUE(bb_if != NULL);
434 E : ASSERT_TRUE(bb_true != NULL);
435 E : ASSERT_TRUE(bb_false != NULL);
436 E : ASSERT_TRUE(bb_end != NULL);
437 :
438 E : block->basic_block_order.push_back(bb_if);
439 E : block->basic_block_order.push_back(bb_true);
440 E : block->basic_block_order.push_back(bb_end);
441 E : block->basic_block_order.push_back(bb_false);
442 :
443 E : AddSuccessorBetween(Successor::kConditionEqual, bb_if, bb_true);
444 E : AddSuccessorBetween(Successor::kConditionNotEqual, bb_if, bb_false);
445 E : AddSuccessorBetween(Successor::kConditionTrue, bb_true, bb_end);
446 E : AddSuccessorBetween(Successor::kConditionTrue, bb_false, bb_end);
447 :
448 : BasicBlockAssembler asm_if(bb_if->instructions().end(),
449 E : &bb_if->instructions());
450 E : asm_if.mov(core::ecx, Operand(core::eax, Immediate(1, core::kSize32Bit)));
451 E : asm_if.mov(core::edx, Operand(core::ecx, Immediate(12, core::kSize32Bit)));
452 E : asm_if.mov(core::edx, Operand(core::eax, Immediate(42, core::kSize32Bit)));
453 :
454 : BasicBlockAssembler asm_true(bb_true->instructions().end(),
455 E : &bb_true->instructions());
456 E : asm_true.mov(core::ecx, Operand(core::eax, Immediate(1, core::kSize32Bit)));
457 E : asm_true.mov(core::edx, Operand(core::eax, Immediate(12, core::kSize32Bit)));
458 E : asm_true.mov(core::ecx, Operand(core::eax, Immediate(24, core::kSize32Bit)));
459 :
460 : BasicBlockAssembler asm_false(bb_false->instructions().end(),
461 E : &bb_false->instructions());
462 E : asm_false.mov(core::ecx, Operand(core::eax, Immediate(24, core::kSize32Bit)));
463 E : asm_false.mov(core::edx, Operand(core::eax, Immediate(48, core::kSize32Bit)));
464 :
465 : // Analyze the flow graph.
466 E : memory_access_.Analyze(&subgraph);
467 :
468 : // State of first basic block is empty.
469 E : GetStateAtEntryOf(bb_if, &state_);
470 E : EXPECT_TRUE(state_.IsEmpty());
471 :
472 : // Get entry state of bb_true.
473 E : GetStateAtEntryOf(bb_true, &state_);
474 E : EXPECT_TRUE(state_.Contains(core::eax, 1));
475 E : EXPECT_TRUE(state_.Contains(core::ecx, 12));
476 E : EXPECT_TRUE(state_.Contains(core::eax, 42));
477 :
478 : // Get entry state of bb_false.
479 E : GetStateAtEntryOf(bb_false, &state_);
480 E : EXPECT_TRUE(state_.Contains(core::eax, 1));
481 E : EXPECT_TRUE(state_.Contains(core::ecx, 12));
482 E : EXPECT_TRUE(state_.Contains(core::eax, 42));
483 :
484 : // Get entry state of bb_end. Intersection of bb_true and bb_false.
485 E : GetStateAtEntryOf(bb_end, &state_);
486 E : EXPECT_TRUE(state_.Contains(core::eax, 1));
487 E : EXPECT_FALSE(state_.Contains(core::eax, 12));
488 E : EXPECT_FALSE(state_.Contains(core::ecx, 12));
489 E : EXPECT_TRUE(state_.Contains(core::eax, 24));
490 E : EXPECT_TRUE(state_.Contains(core::eax, 42));
491 E : }
492 :
493 E : TEST_F(MemoryAccessAnalysisTest, AnalyzeWithData) {
494 E : BasicBlockSubGraph subgraph;
495 E : const uint8 raw_data[] = { 0, 1, 2, 3, 4 };
496 E : const size_t raw_data_len = ARRAYSIZE(raw_data);
497 :
498 : BlockDescription* block = subgraph.AddBlockDescription(
499 E : "b1", "b1.obj", BlockGraph::CODE_BLOCK, 7, 2, 42);
500 :
501 E : BasicCodeBlock* bb = subgraph.AddBasicCodeBlock("bb");
502 : BasicDataBlock* data =
503 E : subgraph.AddBasicDataBlock("data", raw_data_len, &raw_data[0]);
504 :
505 E : block->basic_block_order.push_back(bb);
506 E : block->basic_block_order.push_back(data);
507 :
508 E : BasicBlockAssembler asm_bb(bb->instructions().end(), &bb->instructions());
509 E : asm_bb.ret();
510 :
511 : // Analyze the flow graph.
512 E : memory_access_.Analyze(&subgraph);
513 :
514 : // Expect empty state.
515 E : GetStateAtEntryOf(bb, &state_);
516 E : EXPECT_TRUE(state_.IsEmpty());
517 :
518 E : GetStateAtEntryOf(data, &state_);
519 E : EXPECT_TRUE(state_.IsEmpty());
520 E : }
521 :
522 : } // namespace analysis
523 : } // namespace block_graph
|