|
|
1.1 root 1: /* $Id: recode-conds.c,v 1.2 2008/07/01 01:39:01 fredette Exp $ */
2:
3: /* libtme/recode-conds.c - generic support for recode conditions: */
4:
5: /*
6: * Copyright (c) 2008 Matt Fredette
7: * All rights reserved.
8: *
9: * Redistribution and use in source and binary forms, with or without
10: * modification, are permitted provided that the following conditions
11: * are met:
12: * 1. Redistributions of source code must retain the above copyright
13: * notice, this list of conditions and the following disclaimer.
14: * 2. Redistributions in binary form must reproduce the above copyright
15: * notice, this list of conditions and the following disclaimer in the
16: * documentation and/or other materials provided with the distribution.
17: * 3. All advertising materials mentioning features or use of this software
18: * must display the following acknowledgement:
19: * This product includes software developed by Matt Fredette.
20: * 4. The name of the author may not be used to endorse or promote products
21: * derived from this software without specific prior written permission.
22: *
23: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
24: * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
25: * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
26: * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
27: * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
28: * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
29: * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
31: * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
32: * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
33: * POSSIBILITY OF SUCH DAMAGE.
34: */
35:
36: #include <tme/common.h>
37: _TME_RCSID("$Id: recode-conds.c,v 1.2 2008/07/01 01:39:01 fredette Exp $");
38:
39: #if TME_HAVE_RECODE
40:
41: /* includes: */
42: #include "recode-impl.h"
43:
44: /* this returns a conditions thunk for a conditions group: */
45: const struct tme_recode_conds_thunk *
46: tme_recode_conds_thunk(struct tme_recode_ic *ic,
47: const struct tme_recode_conds_group *conds_group_template)
48: {
49: const struct tme_recode_conds_group *conds_group_other;
50: struct tme_recode_conds_group *conds_group;
51:
52: /* loop over the existing conditions groups: */
53: for (conds_group_other = ic->tme_recode_ic_conds_groups;
54: conds_group_other != NULL;
55: conds_group_other = conds_group_other->tme_recode_conds_group_next) {
56:
57: /* skip this existing conditions group if its flags register
58: size or index or flags don't match: */
59: if (conds_group_other->tme_recode_conds_group_flags_reg_size
60: != conds_group_template->tme_recode_conds_group_flags_reg_size) {
61: continue;
62: }
63: if (conds_group_other->tme_recode_conds_group_flags_reg
64: != conds_group_template->tme_recode_conds_group_flags_reg) {
65: continue;
66: }
67: if (conds_group_other->tme_recode_conds_group_flags
68: != conds_group_template->tme_recode_conds_group_flags) {
69: continue;
70: }
71:
72: /* skip this existing conditions group if its conditions count or
73: guest function don't match: */
74: if (conds_group_other->tme_recode_conds_group_cond_count
75: != conds_group_template->tme_recode_conds_group_cond_count) {
76: continue;
77: }
78: if (conds_group_other->tme_recode_conds_group_guest_func
79: != conds_group_template->tme_recode_conds_group_guest_func) {
80: continue;
81: }
82:
83: /* return the conditions thunk from the existing conditions
84: group: */
85: return (conds_group_other->tme_recode_conds_group_thunk);
86: }
87:
88: /* allocate and fill the new conditions group: */
89: conds_group = tme_new0(struct tme_recode_conds_group, 1);
90: *conds_group = *conds_group_template;
91:
92: /* build the new conditions thunk: */
93: conds_group->tme_recode_conds_group_thunk = tme_recode_host_conds_thunk_new(ic, conds_group);
94:
95: /* add this new conditions group to the ic: */
96: conds_group->tme_recode_conds_group_next = ic->tme_recode_ic_conds_groups;
97: ic->tme_recode_ic_conds_groups = conds_group;
98:
99: /* update the initial thunk offset of the first variable thunk: */
100: ic->tme_recode_ic_thunk_off_variable
101: = tme_recode_build_to_thunk_off(ic, ic->tme_recode_ic_thunk_build_next);
102:
103: /* return the conditions thunk: */
104: return (conds_group->tme_recode_conds_group_thunk);
105: }
106:
107: /* this generic function returns the maximum index for a conditions
108: group's flags: */
109: tme_uint32_t
110: tme_recode_conds_group_flags_index_max(const struct tme_recode_conds_group *conds_group)
111: {
112: tme_recode_uguest_t conds_group_flags_mask;
113: unsigned int count_bits;
114:
115: /* count the number of bits in the condition group flags mask: */
116: conds_group_flags_mask = conds_group->tme_recode_conds_group_flags;
117: assert (conds_group_flags_mask != 0);
118: for (count_bits = 0;
119: conds_group_flags_mask != 0;
120: count_bits++) {
121: conds_group_flags_mask &= (conds_group_flags_mask - 1);
122: }
123:
124: /* return the maximum condition group flags index: */
125: assert (count_bits <= (sizeof(tme_uint32_t) * 8));
126: return ((((tme_uint32_t) 2) << (count_bits - 1)) - 1);
127: }
128:
129: /* this generic function returns the indexed combination of a
130: conditions group's flags: */
131: tme_recode_uguest_t
132: tme_recode_conds_group_flags_from_index(const struct tme_recode_conds_group *conds_group,
133: tme_uint32_t conds_group_flags_index)
134: {
135: tme_recode_uguest_t conds_group_flags_mask;
136: tme_recode_uguest_t conds_group_flags;
137: tme_recode_uguest_t conds_group_flag_next;
138:
139: /* make this combination of the flags: */
140: conds_group_flags_mask = conds_group->tme_recode_conds_group_flags;
141: conds_group_flags = 0;
142: conds_group_flag_next = 1;
143: do {
144: if (conds_group_flags_mask & conds_group_flag_next) {
145: if (conds_group_flags_index & 1) {
146: conds_group_flags |= conds_group_flag_next;
147: }
148: conds_group_flags_index >>= 1;
149: }
150: conds_group_flag_next <<= 1;
151: } while (conds_group_flags_index != 0);
152: return (conds_group_flags);
153: }
154:
155: /* this generic function returns a simple mask of a conditions group's
156: flags and one or more bitwise operations that can be used with the
157: mask to test the given condition. it returns zero if the condition
158: can't be tested with a simple mask: */
159: tme_uint32_t
160: tme_recode_conds_simple_mask(const struct tme_recode_conds_group *conds_group,
161: tme_uint32_t cond,
162: tme_recode_uguest_t *_conds_group_flags_mask)
163: {
164: tme_recode_uguest_t conds_group_flags_same_for_mask[2];
165: int conds_group_flags_same_for_defined[2];
166: tme_uint32_t conds_group_flags_index;
167: tme_recode_uguest_t conds_group_flags;
168: int cond_true;
169: tme_recode_uguest_t conds_group_flags_same_for[2];
170: tme_recode_uguest_t conds_group_flags_mask;
171: tme_uint32_t bitwise_mask;
172:
173: /* we haven't seen any combination of flags that make the condition
174: either true or false yet: */
175: conds_group_flags_same_for_mask[1] = conds_group->tme_recode_conds_group_flags;
176: conds_group_flags_same_for_mask[0] = conds_group->tme_recode_conds_group_flags;
177: conds_group_flags_same_for_defined[1] = FALSE;
178: conds_group_flags_same_for_defined[0] = FALSE;
179:
180: /* loop over all combinations of the flags: */
181: conds_group_flags_index = tme_recode_conds_group_flags_index_max(conds_group);
182: do {
183: conds_group_flags = tme_recode_conds_group_flags_from_index(conds_group, conds_group_flags_index);
184:
185: /* test if this combination of flags makes the condition true: */
186: cond_true = ((*conds_group->tme_recode_conds_group_guest_func)(conds_group_flags, cond) != 0);
187:
188: /* if this is the first combination of flags that we have seen
189: that makes the condition have this state: */
190: if (!conds_group_flags_same_for_defined[cond_true]) {
191:
192: /* start tracking flags that always have the same values when
193: the condition has this state: */
194: conds_group_flags_same_for[cond_true] = conds_group_flags;
195: conds_group_flags_same_for_defined[cond_true] = TRUE;
196: }
197:
198: /* otherwise, this is not the first combination of flags that
199: we have seen that makes the condition have this state: */
200: else {
201:
202: /* drop any flags that before had the same value when the
203: condition had this state, that now have a different value
204: when the condition has this same state: */
205: conds_group_flags_same_for_mask[cond_true]
206: &= ~(conds_group_flags_same_for[cond_true]
207: ^ conds_group_flags);
208: }
209:
210: } while (conds_group_flags_index-- != 0);
211:
212: /* if we never saw a combination of flags that makes the condition
213: true: */
214: if (!conds_group_flags_same_for_defined[1]) {
215:
216: /* this condition is always false, which we can express with an
217: all-bits-zero mask and either OR or AND: */
218: *_conds_group_flags_mask = 0;
219: return (TME_RECODE_BITWISE_OR | TME_RECODE_BITWISE_AND);
220: }
221:
222: /* if we never saw a combination of flags that makes the condition
223: false: */
224: if (!conds_group_flags_same_for_defined[0]) {
225:
226: /* this condition is always true, which we can express with an
227: all-bits-zero mask and either NOR or NAND: */
228: *_conds_group_flags_mask = 0;
229: return (TME_RECODE_BITWISE_NOR | TME_RECODE_BITWISE_NAND);
230: }
231:
232: /* bits that are the same in all combinations of flags that make the
233: condition both true and false, can't be in the mask of flags that
234: determine the condition: */
235: conds_group_flags_mask
236: = ((conds_group_flags_same_for[1]
237: ^ ~conds_group_flags_same_for[0])
238: & conds_group_flags_same_for_mask[1]
239: & conds_group_flags_same_for_mask[0]);
240: conds_group_flags_same_for_mask[1] &= ~conds_group_flags_mask;
241: conds_group_flags_same_for_mask[0] &= ~conds_group_flags_mask;
242:
243: /* if there is any mask of flags that determine one state of the
244: condition, the mask of flags that determine the other state must
245: either be zero, or be exactly the same mask: */
246: conds_group_flags_mask = conds_group_flags_same_for_mask[1];
247: if (conds_group_flags_mask == 0) {
248: conds_group_flags_mask = conds_group_flags_same_for_mask[0];
249: }
250: else {
251: assert (conds_group_flags_same_for_mask[0] == 0
252: || conds_group_flags_same_for_mask[0] == conds_group_flags_mask);
253: }
254:
255: /* loop over all combinations of the flags again, eliminating
256: bitwise operations that don't give the correct condition state
257: under the mask for all combinations: */
258: bitwise_mask
259: = (TME_RECODE_BITWISE_OR
260: | TME_RECODE_BITWISE_NOR
261: | TME_RECODE_BITWISE_AND
262: | TME_RECODE_BITWISE_NAND);
263: conds_group_flags_index = tme_recode_conds_group_flags_index_max(conds_group);
264: do {
265: conds_group_flags = tme_recode_conds_group_flags_from_index(conds_group, conds_group_flags_index);
266:
267: /* test if this combination of flags makes the condition true: */
268: cond_true = ((*conds_group->tme_recode_conds_group_guest_func)(conds_group_flags, cond) != 0);
269:
270: /* mask off all other flags: */
271: conds_group_flags &= conds_group_flags_mask;
272:
273: /* eliminate bitwise operations that don't give the correct
274: condition state for the flags: */
275: if (cond_true != (conds_group_flags != 0)) {
276: bitwise_mask &= ~TME_RECODE_BITWISE_OR;
277: }
278: if (cond_true != (conds_group_flags == 0)) {
279: bitwise_mask &= ~TME_RECODE_BITWISE_NOR;
280: }
281: if (cond_true != (conds_group_flags == conds_group_flags_mask)) {
282: bitwise_mask &= ~TME_RECODE_BITWISE_AND;
283: }
284: if (cond_true != (conds_group_flags != conds_group_flags_mask)) {
285: bitwise_mask &= ~TME_RECODE_BITWISE_NAND;
286: }
287:
288: } while (conds_group_flags_index-- != 0);
289:
290: /* return any mask of flags and bitwise operations: */
291: *_conds_group_flags_mask = conds_group_flags_mask;
292: return (bitwise_mask);
293: }
294:
295: #ifdef TME_RECODE_DEBUG
296: #include <stdio.h>
297:
298: /* this function dumps a conditions thunk: */
299: void
300: tme_recode_conds_thunk_dump(const struct tme_recode_ic *ic,
301: const struct tme_recode_conds_thunk *conds_thunk,
302: const char * const *cond_names)
303: {
304: printf(" flags offset: 0x%x\n flags tested: ",
305: (unsigned int) conds_thunk->tme_recode_conds_thunk_flags_offset);
306: tme_recode_uguest_dump(conds_thunk->tme_recode_conds_thunk_flags);
307: printf("\n");
308: tme_recode_host_conds_thunk_dump(ic, conds_thunk, cond_names);
309: }
310: #endif /* TME_RECODE_DEBUG */
311:
312: #endif /* TME_HAVE_RECODE */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.