1/**************************************************************************
2 *
3 * Copyright 2010 Luca Barbieri
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining
6 * a copy of this software and associated documentation files (the
7 * "Software"), to deal in the Software without restriction, including
8 * without limitation the rights to use, copy, modify, merge, publish,
9 * distribute, sublicense, and/or sell copies of the Software, and to
10 * permit persons to whom the Software is furnished to do so, subject to
11 * the following conditions:
12 *
13 * The above copyright notice and this permission notice (including the
14 * next paragraph) shall be included in all copies or substantial
15 * portions of the Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
20 * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE
21 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
22 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
23 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24 *
25 **************************************************************************/
26
27#include <vector>
28#include <set>
29#include "sm4.h"
30
31#define check(x) do {if(!(x)) return false;} while(0)
32
33bool sm4_link_cf_insns(sm4_program& program)
34{
35	if(program.cf_insn_linked.size())
36		return true;
37
38	std::vector<int> cf_insn_linked;
39	cf_insn_linked.resize(program.insns.size());
40	memset(&cf_insn_linked[0], 0xff, cf_insn_linked.size() * sizeof(int));
41	std::vector<unsigned> cf_stack;
42	for(unsigned insn_num = 0; insn_num < program.insns.size(); ++insn_num)
43	{
44		unsigned v;
45		switch(program.insns[insn_num]->opcode)
46		{
47		case SM4_OPCODE_LOOP:
48			cf_stack.push_back(insn_num);
49			break;
50		case SM4_OPCODE_ENDLOOP:
51			check(!cf_stack.empty());
52			v = cf_stack.back();
53			check(program.insns[v]->opcode == SM4_OPCODE_LOOP);
54			cf_insn_linked[v] = insn_num;
55			cf_insn_linked[insn_num] = v;
56			cf_stack.pop_back();
57			break;
58		case SM4_OPCODE_IF:
59		case SM4_OPCODE_SWITCH:
60			cf_insn_linked[insn_num] = insn_num; // later changed
61			cf_stack.push_back(insn_num);
62			break;
63		case SM4_OPCODE_ELSE:
64		case SM4_OPCODE_CASE:
65			check(!cf_stack.empty());
66			v = cf_stack.back();
67			if(program.insns[insn_num]->opcode == SM4_OPCODE_ELSE)
68				check(program.insns[v]->opcode == SM4_OPCODE_IF);
69			else
70				check(program.insns[v]->opcode == SM4_OPCODE_SWITCH || program.insns[v]->opcode == SM4_OPCODE_CASE);
71			cf_insn_linked[insn_num] = cf_insn_linked[v]; // later changed
72			cf_insn_linked[v] = insn_num;
73			cf_stack.back() = insn_num;
74			break;
75		case SM4_OPCODE_ENDSWITCH:
76		case SM4_OPCODE_ENDIF:
77			check(!cf_stack.empty());
78			v = cf_stack.back();
79			if(program.insns[insn_num]->opcode == SM4_OPCODE_ENDIF)
80				check(program.insns[v]->opcode == SM4_OPCODE_IF || program.insns[v]->opcode == SM4_OPCODE_ELSE);
81			else
82				check(program.insns[v]->opcode == SM4_OPCODE_SWITCH || program.insns[v]->opcode == SM4_OPCODE_CASE);
83			cf_insn_linked[insn_num] = cf_insn_linked[v];
84			cf_insn_linked[v] = insn_num;
85			cf_stack.pop_back();
86			break;
87		}
88	}
89	check(cf_stack.empty());
90	program.cf_insn_linked.swap(cf_insn_linked);
91	return true;
92}
93
94bool sm4_find_labels(sm4_program& program)
95{
96	if(program.labels_found)
97		return true;
98
99	std::vector<int> labels;
100	for(unsigned insn_num = 0; insn_num < program.insns.size(); ++insn_num)
101	{
102		switch(program.insns[insn_num]->opcode)
103		{
104		case SM4_OPCODE_LABEL:
105			if(program.insns[insn_num]->num_ops > 0)
106			{
107				sm4_op& op = *program.insns[insn_num]->ops[0];
108				if(op.file == SM4_FILE_LABEL && op.has_simple_index())
109				{
110					unsigned idx = (unsigned)op.indices[0].disp;
111					if(idx >= labels.size())
112						labels.resize(idx + 1);
113					labels[idx] = insn_num;
114				}
115			}
116			break;
117		}
118	}
119	program.label_to_insn_num.swap(labels);
120	program.labels_found = true;
121	return true;
122}
123