mirror of
https://github.com/phabrics/Run-Sun3-SunOS-4.1.1.git
synced 2026-04-29 11:02:59 -04:00
313 lines
12 KiB
C
313 lines
12 KiB
C
/* $Id: recode-conds.c,v 1.2 2008/07/01 01:39:01 fredette Exp $ */
|
|
|
|
/* libtme/recode-conds.c - generic support for recode conditions: */
|
|
|
|
/*
|
|
* Copyright (c) 2008 Matt Fredette
|
|
* All rights reserved.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions
|
|
* are met:
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
* notice, this list of conditions and the following disclaimer.
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
* documentation and/or other materials provided with the distribution.
|
|
* 3. All advertising materials mentioning features or use of this software
|
|
* must display the following acknowledgement:
|
|
* This product includes software developed by Matt Fredette.
|
|
* 4. The name of the author may not be used to endorse or promote products
|
|
* derived from this software without specific prior written permission.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
|
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
* DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
|
|
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
|
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
|
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
|
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
* POSSIBILITY OF SUCH DAMAGE.
|
|
*/
|
|
|
|
#include <tme/common.h>
|
|
_TME_RCSID("$Id: recode-conds.c,v 1.2 2008/07/01 01:39:01 fredette Exp $");
|
|
|
|
#if TME_HAVE_RECODE
|
|
|
|
/* includes: */
|
|
#include "recode-impl.h"
|
|
|
|
/* this returns a conditions thunk for a conditions group: */
|
|
const struct tme_recode_conds_thunk *
|
|
tme_recode_conds_thunk(struct tme_recode_ic *ic,
|
|
const struct tme_recode_conds_group *conds_group_template)
|
|
{
|
|
const struct tme_recode_conds_group *conds_group_other;
|
|
struct tme_recode_conds_group *conds_group;
|
|
|
|
/* loop over the existing conditions groups: */
|
|
for (conds_group_other = ic->tme_recode_ic_conds_groups;
|
|
conds_group_other != NULL;
|
|
conds_group_other = conds_group_other->tme_recode_conds_group_next) {
|
|
|
|
/* skip this existing conditions group if its flags register
|
|
size or index or flags don't match: */
|
|
if (conds_group_other->tme_recode_conds_group_flags_reg_size
|
|
!= conds_group_template->tme_recode_conds_group_flags_reg_size) {
|
|
continue;
|
|
}
|
|
if (conds_group_other->tme_recode_conds_group_flags_reg
|
|
!= conds_group_template->tme_recode_conds_group_flags_reg) {
|
|
continue;
|
|
}
|
|
if (conds_group_other->tme_recode_conds_group_flags
|
|
!= conds_group_template->tme_recode_conds_group_flags) {
|
|
continue;
|
|
}
|
|
|
|
/* skip this existing conditions group if its conditions count or
|
|
guest function don't match: */
|
|
if (conds_group_other->tme_recode_conds_group_cond_count
|
|
!= conds_group_template->tme_recode_conds_group_cond_count) {
|
|
continue;
|
|
}
|
|
if (conds_group_other->tme_recode_conds_group_guest_func
|
|
!= conds_group_template->tme_recode_conds_group_guest_func) {
|
|
continue;
|
|
}
|
|
|
|
/* return the conditions thunk from the existing conditions
|
|
group: */
|
|
return (conds_group_other->tme_recode_conds_group_thunk);
|
|
}
|
|
|
|
/* allocate and fill the new conditions group: */
|
|
conds_group = tme_new0(struct tme_recode_conds_group, 1);
|
|
*conds_group = *conds_group_template;
|
|
|
|
/* build the new conditions thunk: */
|
|
conds_group->tme_recode_conds_group_thunk = tme_recode_host_conds_thunk_new(ic, conds_group);
|
|
|
|
/* add this new conditions group to the ic: */
|
|
conds_group->tme_recode_conds_group_next = ic->tme_recode_ic_conds_groups;
|
|
ic->tme_recode_ic_conds_groups = conds_group;
|
|
|
|
/* update the initial thunk offset of the first variable thunk: */
|
|
ic->tme_recode_ic_thunk_off_variable
|
|
= tme_recode_build_to_thunk_off(ic, ic->tme_recode_ic_thunk_build_next);
|
|
|
|
/* return the conditions thunk: */
|
|
return (conds_group->tme_recode_conds_group_thunk);
|
|
}
|
|
|
|
/* this generic function returns the maximum index for a conditions
|
|
group's flags: */
|
|
tme_uint32_t
|
|
tme_recode_conds_group_flags_index_max(const struct tme_recode_conds_group *conds_group)
|
|
{
|
|
tme_recode_uguest_t conds_group_flags_mask;
|
|
unsigned int count_bits;
|
|
|
|
/* count the number of bits in the condition group flags mask: */
|
|
conds_group_flags_mask = conds_group->tme_recode_conds_group_flags;
|
|
assert (conds_group_flags_mask != 0);
|
|
for (count_bits = 0;
|
|
conds_group_flags_mask != 0;
|
|
count_bits++) {
|
|
conds_group_flags_mask &= (conds_group_flags_mask - 1);
|
|
}
|
|
|
|
/* return the maximum condition group flags index: */
|
|
assert (count_bits <= (sizeof(tme_uint32_t) * 8));
|
|
return ((((tme_uint32_t) 2) << (count_bits - 1)) - 1);
|
|
}
|
|
|
|
/* this generic function returns the indexed combination of a
|
|
conditions group's flags: */
|
|
tme_recode_uguest_t
|
|
tme_recode_conds_group_flags_from_index(const struct tme_recode_conds_group *conds_group,
|
|
tme_uint32_t conds_group_flags_index)
|
|
{
|
|
tme_recode_uguest_t conds_group_flags_mask;
|
|
tme_recode_uguest_t conds_group_flags;
|
|
tme_recode_uguest_t conds_group_flag_next;
|
|
|
|
/* make this combination of the flags: */
|
|
conds_group_flags_mask = conds_group->tme_recode_conds_group_flags;
|
|
conds_group_flags = 0;
|
|
conds_group_flag_next = 1;
|
|
do {
|
|
if (conds_group_flags_mask & conds_group_flag_next) {
|
|
if (conds_group_flags_index & 1) {
|
|
conds_group_flags |= conds_group_flag_next;
|
|
}
|
|
conds_group_flags_index >>= 1;
|
|
}
|
|
conds_group_flag_next <<= 1;
|
|
} while (conds_group_flags_index != 0);
|
|
return (conds_group_flags);
|
|
}
|
|
|
|
/* this generic function returns a simple mask of a conditions group's
|
|
flags and one or more bitwise operations that can be used with the
|
|
mask to test the given condition. it returns zero if the condition
|
|
can't be tested with a simple mask: */
|
|
tme_uint32_t
|
|
tme_recode_conds_simple_mask(const struct tme_recode_conds_group *conds_group,
|
|
tme_uint32_t cond,
|
|
tme_recode_uguest_t *_conds_group_flags_mask)
|
|
{
|
|
tme_recode_uguest_t conds_group_flags_same_for_mask[2];
|
|
int conds_group_flags_same_for_defined[2];
|
|
tme_uint32_t conds_group_flags_index;
|
|
tme_recode_uguest_t conds_group_flags;
|
|
int cond_true;
|
|
tme_recode_uguest_t conds_group_flags_same_for[2];
|
|
tme_recode_uguest_t conds_group_flags_mask;
|
|
tme_uint32_t bitwise_mask;
|
|
|
|
/* we haven't seen any combination of flags that make the condition
|
|
either true or false yet: */
|
|
conds_group_flags_same_for_mask[1] = conds_group->tme_recode_conds_group_flags;
|
|
conds_group_flags_same_for_mask[0] = conds_group->tme_recode_conds_group_flags;
|
|
conds_group_flags_same_for_defined[1] = FALSE;
|
|
conds_group_flags_same_for_defined[0] = FALSE;
|
|
|
|
/* loop over all combinations of the flags: */
|
|
conds_group_flags_index = tme_recode_conds_group_flags_index_max(conds_group);
|
|
do {
|
|
conds_group_flags = tme_recode_conds_group_flags_from_index(conds_group, conds_group_flags_index);
|
|
|
|
/* test if this combination of flags makes the condition true: */
|
|
cond_true = ((*conds_group->tme_recode_conds_group_guest_func)(conds_group_flags, cond) != 0);
|
|
|
|
/* if this is the first combination of flags that we have seen
|
|
that makes the condition have this state: */
|
|
if (!conds_group_flags_same_for_defined[cond_true]) {
|
|
|
|
/* start tracking flags that always have the same values when
|
|
the condition has this state: */
|
|
conds_group_flags_same_for[cond_true] = conds_group_flags;
|
|
conds_group_flags_same_for_defined[cond_true] = TRUE;
|
|
}
|
|
|
|
/* otherwise, this is not the first combination of flags that
|
|
we have seen that makes the condition have this state: */
|
|
else {
|
|
|
|
/* drop any flags that before had the same value when the
|
|
condition had this state, that now have a different value
|
|
when the condition has this same state: */
|
|
conds_group_flags_same_for_mask[cond_true]
|
|
&= ~(conds_group_flags_same_for[cond_true]
|
|
^ conds_group_flags);
|
|
}
|
|
|
|
} while (conds_group_flags_index-- != 0);
|
|
|
|
/* if we never saw a combination of flags that makes the condition
|
|
true: */
|
|
if (!conds_group_flags_same_for_defined[1]) {
|
|
|
|
/* this condition is always false, which we can express with an
|
|
all-bits-zero mask and either OR or AND: */
|
|
*_conds_group_flags_mask = 0;
|
|
return (TME_RECODE_BITWISE_OR | TME_RECODE_BITWISE_AND);
|
|
}
|
|
|
|
/* if we never saw a combination of flags that makes the condition
|
|
false: */
|
|
if (!conds_group_flags_same_for_defined[0]) {
|
|
|
|
/* this condition is always true, which we can express with an
|
|
all-bits-zero mask and either NOR or NAND: */
|
|
*_conds_group_flags_mask = 0;
|
|
return (TME_RECODE_BITWISE_NOR | TME_RECODE_BITWISE_NAND);
|
|
}
|
|
|
|
/* bits that are the same in all combinations of flags that make the
|
|
condition both true and false, can't be in the mask of flags that
|
|
determine the condition: */
|
|
conds_group_flags_mask
|
|
= ((conds_group_flags_same_for[1]
|
|
^ ~conds_group_flags_same_for[0])
|
|
& conds_group_flags_same_for_mask[1]
|
|
& conds_group_flags_same_for_mask[0]);
|
|
conds_group_flags_same_for_mask[1] &= ~conds_group_flags_mask;
|
|
conds_group_flags_same_for_mask[0] &= ~conds_group_flags_mask;
|
|
|
|
/* if there is any mask of flags that determine one state of the
|
|
condition, the mask of flags that determine the other state must
|
|
either be zero, or be exactly the same mask: */
|
|
conds_group_flags_mask = conds_group_flags_same_for_mask[1];
|
|
if (conds_group_flags_mask == 0) {
|
|
conds_group_flags_mask = conds_group_flags_same_for_mask[0];
|
|
}
|
|
else {
|
|
assert (conds_group_flags_same_for_mask[0] == 0
|
|
|| conds_group_flags_same_for_mask[0] == conds_group_flags_mask);
|
|
}
|
|
|
|
/* loop over all combinations of the flags again, eliminating
|
|
bitwise operations that don't give the correct condition state
|
|
under the mask for all combinations: */
|
|
bitwise_mask
|
|
= (TME_RECODE_BITWISE_OR
|
|
| TME_RECODE_BITWISE_NOR
|
|
| TME_RECODE_BITWISE_AND
|
|
| TME_RECODE_BITWISE_NAND);
|
|
conds_group_flags_index = tme_recode_conds_group_flags_index_max(conds_group);
|
|
do {
|
|
conds_group_flags = tme_recode_conds_group_flags_from_index(conds_group, conds_group_flags_index);
|
|
|
|
/* test if this combination of flags makes the condition true: */
|
|
cond_true = ((*conds_group->tme_recode_conds_group_guest_func)(conds_group_flags, cond) != 0);
|
|
|
|
/* mask off all other flags: */
|
|
conds_group_flags &= conds_group_flags_mask;
|
|
|
|
/* eliminate bitwise operations that don't give the correct
|
|
condition state for the flags: */
|
|
if (cond_true != (conds_group_flags != 0)) {
|
|
bitwise_mask &= ~TME_RECODE_BITWISE_OR;
|
|
}
|
|
if (cond_true != (conds_group_flags == 0)) {
|
|
bitwise_mask &= ~TME_RECODE_BITWISE_NOR;
|
|
}
|
|
if (cond_true != (conds_group_flags == conds_group_flags_mask)) {
|
|
bitwise_mask &= ~TME_RECODE_BITWISE_AND;
|
|
}
|
|
if (cond_true != (conds_group_flags != conds_group_flags_mask)) {
|
|
bitwise_mask &= ~TME_RECODE_BITWISE_NAND;
|
|
}
|
|
|
|
} while (conds_group_flags_index-- != 0);
|
|
|
|
/* return any mask of flags and bitwise operations: */
|
|
*_conds_group_flags_mask = conds_group_flags_mask;
|
|
return (bitwise_mask);
|
|
}
|
|
|
|
#ifdef TME_RECODE_DEBUG
|
|
#include <stdio.h>
|
|
|
|
/* this function dumps a conditions thunk: */
|
|
void
|
|
tme_recode_conds_thunk_dump(const struct tme_recode_ic *ic,
|
|
const struct tme_recode_conds_thunk *conds_thunk,
|
|
const char * const *cond_names)
|
|
{
|
|
printf(" flags offset: 0x%x\n flags tested: ",
|
|
(unsigned int) conds_thunk->tme_recode_conds_thunk_flags_offset);
|
|
tme_recode_uguest_dump(conds_thunk->tme_recode_conds_thunk_flags);
|
|
printf("\n");
|
|
tme_recode_host_conds_thunk_dump(ic, conds_thunk, cond_names);
|
|
}
|
|
#endif /* TME_RECODE_DEBUG */
|
|
|
|
#endif /* TME_HAVE_RECODE */
|