/*
* Copyright (c) 1995, 1996, 1998, 1999 The University of Utah and
* the Computer Systems Laboratory at the University of Utah (CSL).
*
* This file is part of Flick, the Flexible IDL Compiler Kit.
*
* Flick is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* Flick is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Flick; see the file COPYING. If not, write to
* the Free Software Foundation, 59 Temple Place #330, Boston, MA 02111, USA.
*/
#include <assert.h>
#include <mom/compiler.h>
#include <mom/c/libcast.h>
#include <mom/c/be/mem_mu_state.hh>
void mem_mu_state::new_glob()
{
assert(glob_size_expr == 0);
assert(glob_size == 0);
assert(chunk_size_expr == 0);
assert(chunk_size == 0);
/* Create the beginning-of-glob macro invocation. */
char *name = flick_asprintf("flick_%s_%s_new_glob",
get_be_name(), get_buf_name());
cast_expr cex = cast_new_expr_call(cast_new_expr_name(name),
(op & MUST_DECODE) ? 1 : 2);
glob_size_expr = &cex->cast_expr_u_u.call.params.
cast_expr_array_val[0];
/* When we are encoding we might need to allocate space,
so we need to pass an abort label in order to handle out
of memory errors. . */
if( (op & MUST_ENCODE) ) {
cex->cast_expr_u_u.call.params.cast_expr_array_val[1] =
cast_new_expr_name( abort_block->use_current_label() );
}
add_stmt(cast_new_stmt_expr(cex));
/* Note that `end_glob' produces CAST statements that share the
parameter list structure pointed to by `glob_size_expr'. Moreover,
`end_glob' may change the expression in the parameter list --- and
thereby change the number that appears within this `new_glob'
statement. Tricky, eh? */
*glob_size_expr = cast_new_expr_lit_int(0, 0);
}
void mem_mu_state::end_glob()
{
assert(glob_size_expr);
assert(glob_size >= 0);
/* Chunks can't extend beyond the end of a glob. */
break_chunk();
/* Don't change the glob size expression if the existing glob size
expression refers to a value not less than `glob_size'. Why? We
may have already generated an `end_glob' for the current glob in
some other generated code branch, and that branch may have a greater
glob size requirement. */
assert (((*glob_size_expr)->kind == CAST_EXPR_LIT_PRIM) &&
((*glob_size_expr)->cast_expr_u_u.lit_prim.u.kind ==
CAST_PRIM_INT));
int prev_glob_size = (*glob_size_expr)->cast_expr_u_u.lit_prim.u.
cast_lit_prim_u_u.i;
if (prev_glob_size >= glob_size) {
/* Do nothing. */
} else {
/* Replace the existing expression with a new expression.
Note that all of the `new_glob()' and `end_glob()'
statements that refer to the current glob all reference the
same array of parameters, and that array is pointed to by
`glob_size_expr'. Therefore, changing the expression within
that parameter array has the effect of changing the constant
that appears in *all* the statements that refer to the
current glob! Tricky, eh? */
*glob_size_expr = cast_new_expr_lit_int(glob_size, 0);
/* Add this glob to the running total for the maximum message
size. Of course, we have to subtract this glob's previous
size from the count! */
if ((max_msg_size - prev_glob_size + glob_size) > max_msg_size)
max_msg_size = max_msg_size - prev_glob_size +
glob_size;
else
max_msg_size = MAXUINT_MAX;
}
/* Create the end-of-chunk macro invocation. */
char *name = flick_asprintf("flick_%s_%s_end_glob",
get_be_name(), get_buf_name());
cast_expr cex = cast_new_expr_call(cast_new_expr_name(name), 0);
/* Now change the list of parameters in `cex'. In particular, our new
expression will share its list of parameters with the `new_glob'
expression we generated previously. This sharing of structure makes
it possible for us to munge the parameters (i.e., the literal
integer that is the glob size) that appear in all of these
expressions. */
cex->cast_expr_u_u.call.params.cast_expr_array_len = 1;
cex->cast_expr_u_u.call.params.cast_expr_array_val = glob_size_expr;
add_stmt(cast_new_stmt_expr(cex));
glob_size_expr = 0;
glob_size = 0;
}
void mem_mu_state::glob_grow(int amount)
{
//printf("this %08x amt %d mgs %d\n", this, amount, max_glob_size);
assert(amount >= 0);
assert(amount <= (signed int)max_glob_size);
make_glob();
if (glob_size + amount > (signed int)max_glob_size) {
end_glob();
new_glob();
assert(glob_size + amount <= (signed int)max_glob_size);
}
glob_size += amount;
assert(glob_size <= (signed int)max_glob_size);
}
void mem_mu_state::glob_prim(int needed_align_bits, int prim_size)
{
/* Calculate the maximum amount of padding we might have to insert
here. */
/* maximum padding examples:
needed: 3, have 2,0:
you have either 3,0 or 3,4. 3,4 is the 'worst case'
needed: 3, have 1,1:
you have either 3,1, 3,3, 3,5, or 3,7. 3,1 is 'worst case'
needed: 3, have 1,0:
you have either 3,0, 3,2, 3,4, or 3,6. 3,2 is 'worst case'
needed: 2, have 3,2:
you have 2,2
needed: 3, have 0,0:
you have either 3,0, 3,1, 3,2, ... 3,1 is 'worst case'
*/
assert(align_ofs < (1 << align_bits));
int needed_align_mask = (1 << needed_align_bits) - 1;
int alignment = (needed_align_bits > align_bits) ? needed_align_bits : align_bits;
int alignoffset = align_ofs;
if (align_ofs == 0 && needed_align_bits > align_bits)
alignoffset = (1 << align_bits);
int max_padding = ((1 << alignment) - alignoffset) & needed_align_mask;
/* Add it to the current glob, or start a new glob if necessary. */
if (max_padding > 0)
glob_grow(max_padding);
/* Then add the space for the actual primitive. */
glob_grow(prim_size);
}
syntax highlighted by Code2HTML, v. 0.9.1