sm4_analyze.cpp revision e5ae4588d150a179974a812887f3b6445d8e2f34
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
124bool sm4_allocate_resource_sampler_pairs(sm4_program& program)
125{
126	if(program.resource_sampler_slots_assigned)
127		return true;
128
129	std::set<std::pair<int, int> > pairs;
130	std::set<int> resinfos;
131
132	for(unsigned insn_num = 0; insn_num < program.insns.size(); ++insn_num)
133	{
134		int resource = -1;
135		int sampler = -2;
136		for(unsigned i = 0; i < program.insns[insn_num]->num_ops; ++i)
137		{
138			sm4_op* op = program.insns[insn_num]->ops[i].get();
139			if(op)
140			{
141				if(op->file == SM4_FILE_RESOURCE)
142				{
143					if(!op->has_simple_index() || resource >= 0)
144						return false;
145					resource = (int)op->indices[0].disp;
146				}
147				if(op->file == SM4_FILE_SAMPLER)
148				{
149					if(!op->has_simple_index() || sampler >= 0)
150						return false;
151					sampler = (int)op->indices[0].disp;
152				}
153			}
154		}
155
156		unsigned opcode = program.insns[insn_num]->opcode;
157		if(opcode == SM4_OPCODE_LD || opcode == SM4_OPCODE_LD_MS)
158			sampler = -1;
159		if(sampler >= -1 && resource >= 0)
160			pairs.insert(std::make_pair(resource, sampler));
161		if(opcode == SM4_OPCODE_RESINFO)
162			resinfos.insert(resource);
163	}
164
165	for(std::set<std::pair<int, int> >::iterator i = pairs.begin(); i != pairs.end(); ++i)
166	{
167		program.resource_sampler_to_slot[*i] = program.slot_to_resource.size();
168		if(!program.resource_to_slot.count(i->first))
169		{
170			program.resource_to_slot[i->first] =  program.slot_to_resource.size();
171			resinfos.erase(i->first);
172		}
173		program.slot_to_resource.push_back(i->first);
174		program.slot_to_sampler.push_back(i->second);
175	}
176
177	for(std::set<int>::iterator i = resinfos.begin(); i != resinfos.end(); ++i)
178	{
179		program.resource_sampler_to_slot[std::make_pair(*i, -1)] = program.slot_to_resource.size();
180		program.resource_to_slot[*i] =  program.slot_to_resource.size();
181		program.slot_to_resource.push_back(*i);
182		program.slot_to_sampler.push_back(-1);
183	}
184	program.resource_sampler_slots_assigned = true;
185	return true;
186}
187