/* Glue code to connect to GCC backend.
   Copyright (C) 2001, 2002 (??)

This file is part of GCC.

GCC 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, or (at your option)
any later version.

GCC 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 GCC; see the file COPYING.  If not, write to
the Free Software Foundation, 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA.  */

/*
The toy language was originally created by Fergus Henderson.

Fergus' homepage is http://www.cs.mu.oz.au/~fjh/


The front-end was updated to GCC 2.95 by Jonathan Bartlett.  Jonathan
maintains "The GNU Compiler Writer's Jump Point" at
http://members.wri.com/johnnyb/compilers/

Jonathan's e-mail is johnnyb@wolfram.com
Jonathan's homepage is http://members.wri.com/johnnyb/


This distribution is an improved version of Jonathan's GCC 2.95 tarball by
Brian Young (me).  See the CHANGELOG for further details.

My e-mail is bayoung@acm.org
My homepage is http://www.tildeslash.org/


Then I hacked it evily, every brokenness is my fault:
Michael Meeks <michael@ximian.com>
http://www.gnome.org/~michael/ 

And after that I (Michal Moskal <malekith@pld-linux.org>) have
hacked it up some more, ripped some code and added some more
in order to suit it for Ksi. 

Jun 26 2002: Now only push{level,decl}() and poplevel() remains from
original Toy compiler :)
*/

#include "ksi.h"
#include "ggc.h"
#include "langhooks.h"
#include "langhooks-def.h"
#include "rtl.h"
#include "expr.h"
#include "convert.h"

/* Used externaly */
extern void set_yydebug PARAMS ((int));
extern void yyerror PARAMS ((char *));

int flag_yydebug = 0;
int flag_traditional = 0;		/* Used by dwarfout.c.  */


/* These functions and variables deal with binding contours.  We only
   need these functions for the list of PARM_DECLs, but we leave the
   functions more general; these are a simplified version of the
   functions from GNAT.  */

/* For each binding contour we allocate a binding_level structure which records
   the entities defined or declared in that contour. Contours include:

	the global one
	one for each subprogram definition
	one for each compound statement (declare block)

   Binding contours are used to create GCC tree BLOCK nodes.  */

struct binding_level
{
	/* A chain of ..._DECL nodes for all variables, constants, functions,
	   parameters and type declarations.  These ..._DECL nodes are chained
	   through the TREE_CHAIN field. Note that these ..._DECL nodes are 
	   stored in the reverse of the order supplied to be compatible with 
	   the back-end.  */
	tree names;
	/* For each level (except the global one), a chain of BLOCK nodes 
	   for all the levels that were entered and exited one level down 
	   from this one.  */
	tree blocks;
	/* The back end may need, for its own internal processing, to create 
	 * a BLOCK node. This field is set aside for this purpose. If this 
	 * field is non-null when the level is popped, i.e. when poplevel 
	 * is invoked, we will use such block instead of creating a new 
	 * one from the 'names' field, that is the ..._DECL nodes accumulated 
	 * so far.  Typically the routine 'pushlevel' will be called before 
	 * setting this field, so that if the front-end had inserted ..._DECL 
	 * nodes in the current block they will not be lost.   */
	tree block_created_by_back_end;
	/* The binding level containing this one (the enclosing binding 
	 * level). */
	struct binding_level *level_chain;
};

/* The binding level currently in effect.  */
static struct binding_level *current_binding_level = NULL;

/* List of binding levels to reuse. */
static struct binding_level *free_binding_levels = NULL;

/* The outermost binding level. This binding level is created when the
   compiler is started and it will exist through the entire compilation.  */
static struct binding_level *global_binding_level;

/* Binding level structures are initialized by copying this one.  */
static struct binding_level clear_binding_level = {NULL, NULL, NULL, NULL};


tree lookup_type(tree id, enum tree_code type)
{
	tree ptr;
	struct binding_level *ctx;
	
	for (ctx = current_binding_level; ctx; ctx = ctx->level_chain)
		for (ptr = ctx->names; ptr; ptr = TREE_CHAIN(ptr))
			if (DECL_KSI_NAME(ptr) == id && 
			    TREE_CODE(ptr) == TYPE_DECL &&
			    ((type == TYPE_DECL && !DECL_TAGGED_TYPE(ptr)) || 
			     (DECL_TAGGED_TYPE(ptr) && 
			      TREE_CODE(TREE_TYPE(ptr)) == type)))
			    	return ptr;
	
	return NULL;
}

tree lookup_id(const char *text, enum tree_code type)
{
	tree id;
	tree ptr;
	struct binding_level *ctx;

	id = get_identifier(text);
	
	for (ctx = current_binding_level; ctx; ctx = ctx->level_chain)
		for (ptr = ctx->names; ptr; ptr = TREE_CHAIN(ptr))
			if (DECL_KSI_NAME(ptr) == id && 
			    (TREE_CODE(ptr) == type || 
			     (type == VAR_DECL && TREE_CODE(ptr) == PARM_DECL)))
				return ptr;
	
	return NULL;
}

tree get_vars(void)
{
	return current_binding_level->names;
}

/* Return non-zero if we are currently in the global binding level.  */
int
global_bindings_p ()
{
	return current_binding_level == global_binding_level ? -1 : 0;
}

/* Return the list of declarations in the current level. Note that this list
   is in reverse order (it has to be so for back-end compatibility).  */

tree
getdecls ()
{
	return current_binding_level->names;
}

#if 0
/* Nonzero if the current level needs to have a BLOCK made.  */
int
kept_level_p (void)
{
	return (current_binding_level->names != 0);
}
#endif

/* Enter a new binding level. The input parameter is ignored, but has to be
   specified for back-end compatibility.  */

void
pushlevel (ignore)
     int ignore ATTRIBUTE_UNUSED;
{
	struct binding_level *newlevel;
	
	if (free_binding_levels) {
		newlevel = free_binding_levels;
		free_binding_levels = free_binding_levels->level_chain;
	} else {
		newlevel = (struct binding_level *) 
				xmalloc (sizeof (struct binding_level));
	}

	*newlevel = clear_binding_level;

	/* Add this level to the front of the chain (stack) of levels that are
	   active.  */
	newlevel->level_chain = current_binding_level;
	current_binding_level = newlevel;
}

/* Exit a binding level.
   Pop the level off, and restore the state of the identifier-decl mappings
   that were in effect when this level was entered.

   If KEEP is nonzero, this level had explicit declarations, so
   and create a "block" (a BLOCK node) for the level
   to record its declarations and subblocks for symbol table output.

   If FUNCTIONBODY is nonzero, this level is the body of a function,
   so create a block as if KEEP were set and also clear out all
   label names.

   If REVERSE is nonzero, reverse the order of decls before putting
   them into the BLOCK.  */

tree
poplevel (keep, reverse, functionbody)
     int keep;
     int reverse;
     int functionbody;
{
	/* Points to a BLOCK tree node. This is the BLOCK node construted for
	 * the binding level that we are about to exit and which is returned 
	 * by this routine.  */
	tree block_node = NULL_TREE;
	tree decl_chain;
	tree subblock_chain = current_binding_level->blocks;
	tree subblock_node;
	tree block_created_by_back_end;

	/* Reverse the list of XXXX_DECL nodes if desired.  Note that the 
	 * ..._DECL nodes chained through the `names' field of 
	 * current_binding_level are in reverse order except for PARM_DECL 
	 * node, which are explicitely stored in the right order.  */
	decl_chain = (reverse) ? nreverse (current_binding_level->names)
		: current_binding_level->names;

	block_created_by_back_end = 
		current_binding_level->block_created_by_back_end;
	if (block_created_by_back_end != 0) {
		block_node = block_created_by_back_end;

		/* Check if we are about to discard some information that 
		 * was gathered by the front-end. Nameley check if the 
		 * back-end created a new block without calling pushlevel 
		 * first. To understand why things are lost just look at the 
		 * next case (i.e. no block created by back-end.  */
		if ((keep || functionbody) && (decl_chain || subblock_chain))
			abort ();
	}

	/* If there were any declarations in the current binding level, or 
	 * if this binding level is a function body, or if there are any 
	 * nested blocks then create a BLOCK node to record them for the 
	 * life of this function.  */
	else if (keep || functionbody)
		block_node = build_block (keep ? decl_chain : 0, 0, 
					  subblock_chain, 0, 0);

	/* Record the BLOCK node just built as the subblock its enclosing 
	 * scope.  */
	for (subblock_node = subblock_chain; subblock_node;
	     subblock_node = TREE_CHAIN (subblock_node))
		BLOCK_SUPERCONTEXT (subblock_node) = block_node;

	/* Clear out the meanings of the local variables of this level.  */

	for (subblock_node = decl_chain; subblock_node;
	     subblock_node = TREE_CHAIN (subblock_node))
		if (DECL_NAME (subblock_node) != 0)
			/* If the identifier was used or addressed via a 
			 * local extern decl,  don't forget that fact.   */
			if (DECL_EXTERNAL (subblock_node))
			{
				if (TREE_USED (subblock_node))
					TREE_USED (DECL_NAME (subblock_node)) 
						= 1;
				if (TREE_ADDRESSABLE (subblock_node))
					TREE_ADDRESSABLE (
						DECL_ASSEMBLER_NAME (
							subblock_node)) = 1;
			}

	{
		/* Pop the current level.  */
		struct binding_level *b = current_binding_level;
		
		current_binding_level = b->level_chain;
		b->level_chain = free_binding_levels;
		free_binding_levels = b;
	}

	if (functionbody) {
		/* This is the top level block of a function. The ..._DECL 
		 * chain stored in BLOCK_VARS are the function's parameters 
		 * (PARM_DECL nodes). Don't leave them in the BLOCK because 
		 * they are found in the FUNCTION_DECL instead.  */
		DECL_INITIAL (current_function_decl) = block_node;
		BLOCK_VARS (block_node) = 0;
	} else if (block_node) {
		if (block_created_by_back_end == NULL)
			current_binding_level->blocks
				= chainon (current_binding_level->blocks, block_node);
	}

	/* If we did not make a block for the level just exited, any blocks 
	 * made for inner levels (since they cannot be recorded as subblocks 
	 * in that level) must be carried forward so they will later become 
	 * subblocks of something else.  */
	else if (subblock_chain)
		current_binding_level->blocks
			= chainon (current_binding_level->blocks, 
				   subblock_chain);
	if (block_node)
		TREE_USED (block_node) = 1;

	return block_node;
}

/* Insert BLOCK at the end of the list of subblocks of the
   current binding level.  This is used when a BIND_EXPR is expanded,
   to handle the BLOCK node inside the BIND_EXPR.  */

void
insert_block (block)
     tree block;
{
	TREE_USED (block) = 1;
	current_binding_level->blocks
		= chainon (current_binding_level->blocks, block);
}

/* Set the BLOCK node for the innermost scope
   (the one we are currently in).  */

void
set_block (block)
     tree block;
{
	current_binding_level->block_created_by_back_end = block;
}

/* Records a ..._DECL node DECL as belonging to the current lexical scope.
   Returns the ..._DECL node. */

static void check_redef(tree decl)
{
	tree ptr;

	for (ptr = current_binding_level->names; ptr; ptr = TREE_CHAIN(ptr))
		if (DECL_NAME(ptr) == DECL_NAME(decl) &&
		    TREE_CODE(ptr) == TREE_CODE(decl) &&
		    (TREE_CODE(ptr) != TYPE_DECL ||
		     TREE_CODE(TREE_TYPE(ptr)) != TREE_CODE(TREE_TYPE(decl))))
		     	break;
	if (ptr)
		fatal_error("redefinition of `%s'", 
			    IDENTIFIER_POINTER(DECL_NAME(decl)));
}

tree
pushdecl (decl)
     tree decl;
{
	/* External objects aren't nested, other objects may be.  */
	if (DECL_EXTERNAL (decl))
		DECL_CONTEXT (decl) = 0;
	else
		DECL_CONTEXT (decl) = current_function_decl;

	check_redef(decl);
	
	/* Put the declaration on the list.  The list of declarations is 
	 * in reverse order. The list will be reversed later if necessary.  
	 * This needs to be this way for compatibility with the back-end.  */

	TREE_CHAIN (decl) = current_binding_level->names;
	current_binding_level->names = decl;

	/* For the declaration of a type, set its name if it is not 
	 * already set. */

	if (TREE_CODE (decl) == TYPE_DECL
	    && TYPE_NAME (TREE_TYPE (decl)) == 0)
		TYPE_NAME (TREE_TYPE (decl)) = DECL_NAME (decl);

	if (DECL_LANG_SPECIFIC(decl) == NULL) {
		DECL_LANG_SPECIFIC(decl) = 
			ggc_alloc(sizeof(struct lang_decl));
		DECL_KSI_NAME(decl) = DECL_NAME(decl);
	} else if (DECL_KSI_NAME(decl) == NULL)
		DECL_KSI_NAME(decl) = DECL_NAME(decl);

	return decl;
}

#ifndef CHAR_TYPE_SIZE
#define CHAR_TYPE_SIZE BITS_PER_UNIT
#endif

#ifndef INT_TYPE_SIZE
#define INT_TYPE_SIZE BITS_PER_WORD
#endif

void set_type_name(tree type, const char *name);

void set_type_name(tree type, const char *name)
{
	tree decl;

	if (type == NULL)
		return;

	decl = build_decl(TYPE_DECL, get_identifier(name), type);
	TYPE_NAME(type) = decl;

	pushdecl(decl);
}	
		
/* Create the predefined scalar types such as `integer_type_node' needed 
   in the gcc back-end and initialize the global binding level.  */

static void
ksi_init_decl_processing (void)
{
	lineno = 0;

	current_function_decl = NULL;
	current_binding_level = NULL;
	/* Make the binding_level structure for global names.  */
	pushlevel (0);
	global_binding_level = current_binding_level;
	
	ggc_add_tree_root(&global_binding_level->names, 1);

	build_common_tree_nodes (/*flag_signed_char*/ 0);
	set_sizetype (make_unsigned_type (POINTER_SIZE));
	build_common_tree_nodes_2(0);
	
	/* strict bool type */
	bool_type_node = make_unsigned_type(CHAR_TYPE_SIZE);
	TREE_SET_CODE(bool_type_node, BOOLEAN_TYPE);
	TYPE_MAX_VALUE(bool_type_node) = build_int_2(1, 0);
	TREE_TYPE(TYPE_MAX_VALUE(bool_type_node)) = bool_type_node;
	TYPE_PRECISION(bool_type_node) = 1;
	layout_type(bool_type_node);
	ggc_add_tree_root(&bool_type_node, 1);

	/* (poly) */
	poly_type_node = make_unsigned_type(POINTER_SIZE);
	TYPE_POLYMORPHIC(poly_type_node) = 1;
	layout_type(poly_type_node);
	ggc_add_tree_root(&poly_type_node, 1);

	set_type_name(poly_type_node, "poly");
	set_type_name(bool_type_node, "bool");
	set_type_name(void_type_node, "void");
	set_type_name(ptr_type_node, "ptr");
	set_type_name(float_type_node, "float");
	set_type_name(double_type_node, "double");
	set_type_name(long_double_type_node, "long double");

	/* I'm not sure if anything beside c_{integer,char} is needed
	 * here... These are for dbxout*().  */
	set_type_name(integer_type_node, "c_integer");
	set_type_name(char_type_node, "c_char");

	init_builtins();
}


static rtx my_expand_expr(union tree_node *, rtx, enum machine_mode, 
			  enum expand_modifier);
			  
static rtx my_expand_expr(exp, x, y, modifier)
	union tree_node *exp;
	rtx x ATTRIBUTE_UNUSED;
	enum machine_mode y ATTRIBUTE_UNUSED;
	enum expand_modifier modifier ATTRIBUTE_UNUSED;
{
	if (TREE_CODE(exp) == LABEL_EXPR)
		expand_label(TREE_OPERAND(exp, 0));
	else
		abort();
	return const0_rtx;
}


/* Perform all the initialization steps that are language-specific.  */
static const char *
ksi_init (const char *name)
{
	lang_expand_expr = my_expand_expr;
	kpp_init();
	if (flag_just_preprocess)
		flag_syntax_only = 1;

	ksi_init_decl_processing();
	
	return ksi_init_parse(name);
}

/* Called to initialize options, before any calls to decode_option.  */
static void
ksi_init_options (void)
{
}

static int ksi_decode_options(int,char **);

int flag_just_preprocess = 0;
extern char *kpp_output;

/* Function called with an option vector as argument, to decode a
   single option (typically starting with -f or -W or +).  It should
   return the number of command-line arguments it uses if it handles
   the option, or 0 and not complain if it does not recognise the
   option.  If this function returns a negative number, then its
   absolute value is the number of command-line arguments used, but,
   in addition, no language-independent option processing should be
   done for this option. */
static int
ksi_decode_options (argc, argv)
	int    argc ATTRIBUTE_UNUSED;
	char **argv;
{
	char *p = argv[0];

	if (strcmp(p, "-kpp") == 0) {
		flag_just_preprocess++;
		if (argv[1] == NULL)
			error("no name given to -kpp");
		else {
			kpp_output = argv[1];
			return 2;
		}
	} else if (p[0] == '-' && (p[1] == 'D' || p[1] == 'A')) {
		kpp_define_opt(p + 2);
	} else 
		return 0;
		
	return 1;
}

/* If DECL has a cleanup, build and return that cleanup here.
   This is a callback called by expand_expr.  */
tree
maybe_build_cleanup (decl)
     tree decl ATTRIBUTE_UNUSED;
{
	return NULL_TREE;
}

/* Print an error message for invalid use of an incomplete type.  */
void
incomplete_type_error (dont_care_1, dont_care_2)
     tree dont_care_1 ATTRIBUTE_UNUSED;
     tree dont_care_2 ATTRIBUTE_UNUSED;
{
	abort ();
}

tree
truthvalue_conversion (expr)
	tree expr;
{
	return expr;
}


int
mark_addressable (expr)
     tree expr ATTRIBUTE_UNUSED;
{
	return 0;
}

/* Since we don't use the DECL_LANG_SPECIFIC field, this is a no-op.  */

void
copy_lang_decl (node)
     tree node ATTRIBUTE_UNUSED;
{
}

/* Mark language-specific parts of T for garbage-collection.  */
void
lang_mark_tree (t)
	tree t;
{
	if (TREE_CODE(t) == IDENTIFIER_NODE) {
		struct lang_identifier *i = (struct lang_identifier *) t;
		ggc_mark_tree(i->enum_value);
	} else if (TYPE_P(t) && TYPE_LANG_SPECIFIC(t)) {
		ggc_mark(TYPE_LANG_SPECIFIC(t));
	} else if (DECL_P(t) && DECL_LANG_SPECIFIC(t)) {
		ggc_mark(DECL_LANG_SPECIFIC(t));
		ggc_mark_tree(DECL_KSI_NAME(t));
	}
}

/* Return the typed-based alias set for T, which may be an expression
   or a type.  Return -1 if we don't do anything special.  */

static HOST_WIDE_INT
ksi_get_alias_set(tree t ATTRIBUTE_UNUSED)
{
	/* alias.c:get_alias_set() will use TYPE_ALIAS_SET if we set
	 * it regardless of what we return here. I'm not sure what
	 * should be done with expressions, so we'll just always return
	 * 0 for now. */

	return 0;
}

/* Return a definition for a builtin function named NAME and whose data type
   is TYPE.  TYPE should be a function type with argument types.
   FUNCTION_CODE tells later passes how to compile calls to this function.
   See tree.h for its possible values.

   If LIBRARY_NAME is nonzero, use that for DECL_ASSEMBLER_NAME,
   the name to be called if we can't opencode the function.  */
tree
builtin_function (name, type, function_code, class, library_name)
     const char *name;
     tree type;
     int function_code;
     enum built_in_class class;
     const char *library_name;
{
	tree decl = build_decl (FUNCTION_DECL, get_identifier (name), type);
	DECL_EXTERNAL (decl) = 1;
	TREE_PUBLIC (decl) = 1;
	if (library_name)
		SET_DECL_ASSEMBLER_NAME (decl, get_identifier (library_name));
	make_decl_rtl (decl, NULL);
	pushdecl (decl);
	DECL_BUILT_IN_CLASS (decl) = class;
	DECL_FUNCTION_CODE (decl) = function_code;
	return decl;
}

/* Sets some debug flags for the parser.  */
void
set_yydebug (value)
     int value;
{
	flag_yydebug = value;
}

#undef LANG_HOOKS_NAME
#define LANG_HOOKS_NAME			"Ksi"
#undef LANG_HOOKS_INIT
#define LANG_HOOKS_INIT			ksi_init
#undef LANG_HOOKS_INIT_OPTIONS
#define LANG_HOOKS_INIT_OPTIONS		ksi_init_options
#undef LANG_HOOKS_DECODE_OPTION
#define LANG_HOOKS_DECODE_OPTION	ksi_decode_options
#undef LANG_HOOKS_GET_ALIAS_SET
#define LANG_HOOKS_GET_ALIAS_SET	ksi_get_alias_set

const struct lang_hooks lang_hooks = LANG_HOOKS_INITIALIZER;
/*
 * Type callbacks for gcc. convert() stolen from c-convert.c,
 * other are from toy compiler.
 */

/* Create an expression whose value is that of EXPR,
   converted to type TYPE.  The TREE_TYPE of the value
   is always TYPE.  This function implements all reasonable
   conversions; callers should filter out those that are
   not permitted by the language being compiled.  */

tree
convert (type, expr)
     tree type, expr;
{
  register tree e = expr;
  register enum tree_code code = TREE_CODE (type);

  if (type == TREE_TYPE (expr)
      || TREE_CODE (expr) == ERROR_MARK
      || code == ERROR_MARK || TREE_CODE (TREE_TYPE (expr)) == ERROR_MARK)
    return expr;

  if (TYPE_MAIN_VARIANT (type) == TYPE_MAIN_VARIANT (TREE_TYPE (expr)))
    return fold (build1 (NOP_EXPR, type, expr));
  if (TREE_CODE (TREE_TYPE (expr)) == ERROR_MARK)
    return error_mark_node;
  if (TREE_CODE (TREE_TYPE (expr)) == VOID_TYPE)
    {
      error ("void value not ignored as it ought to be");
      return error_mark_node;
    }
  if (code == VOID_TYPE)
    return build1 (CONVERT_EXPR, type, e);
#if 0
  /* This is incorrect.  A truncation can't be stripped this way.
     Extensions will be stripped by the use of get_unwidened.  */
  if (TREE_CODE (expr) == NOP_EXPR)
    return convert (type, TREE_OPERAND (expr, 0));
#endif
  if (code == INTEGER_TYPE || code == ENUMERAL_TYPE)
    return fold (convert_to_integer (type, e));
  if (code == BOOLEAN_TYPE)
    {
      tree t = truthvalue_conversion (expr);
      /* If truthvalue_conversion returns a NOP_EXPR, we must fold it here
	 to avoid infinite recursion between fold () and convert ().  */
      if (TREE_CODE (t) == NOP_EXPR)
	return fold (build1 (NOP_EXPR, type, TREE_OPERAND (t, 0)));
      else
	return fold (build1 (NOP_EXPR, type, t));
    }
  if (code == POINTER_TYPE || code == REFERENCE_TYPE)
    return fold (convert_to_pointer (type, e));
  if (code == REAL_TYPE)
    return fold (convert_to_real (type, e));
  if (code == COMPLEX_TYPE)
    return fold (convert_to_complex (type, e));
  if (code == VECTOR_TYPE)
    return fold (convert_to_vector (type, e));

  error ("conversion to non-scalar type requested");
  return error_mark_node;
}

/* These are used to build types for various sizes.  The code below
   comes from C frontend. */

/* Return an integer type with the number of bits of precision given by  
   PRECISION.  UNSIGNEDP is nonzero if the type is unsigned; otherwise
   it is a signed type.  */

tree
type_for_size (bits, unsignedp)
     unsigned bits;
     int unsignedp;
{
  if (bits == TYPE_PRECISION (integer_type_node))
    return unsignedp ? unsigned_type_node : integer_type_node;

  if (bits == TYPE_PRECISION (signed_char_type_node))
    return unsignedp ? unsigned_char_type_node : signed_char_type_node;

  if (bits == TYPE_PRECISION (short_integer_type_node))
    return unsignedp ? short_unsigned_type_node : short_integer_type_node;

  if (bits == TYPE_PRECISION (long_integer_type_node))
    return unsignedp ? long_unsigned_type_node : long_integer_type_node;

  if (bits == TYPE_PRECISION (long_long_integer_type_node))
    return (unsignedp ? long_long_unsigned_type_node
	    : long_long_integer_type_node);

  if (bits <= TYPE_PRECISION (intQI_type_node))
    return unsignedp ? unsigned_intQI_type_node : intQI_type_node;

  if (bits <= TYPE_PRECISION (intHI_type_node))
    return unsignedp ? unsigned_intHI_type_node : intHI_type_node;

  if (bits <= TYPE_PRECISION (intSI_type_node))
    return unsignedp ? unsigned_intSI_type_node : intSI_type_node;

  if (bits <= TYPE_PRECISION (intDI_type_node))
    return unsignedp ? unsigned_intDI_type_node : intDI_type_node;

  return 0;
}

void init_types(void)
{
}

void fini_types(void)
{
}

/* Return a data type that has machine mode MODE.  UNSIGNEDP selects
   an unsigned type; otherwise a signed type is returned.  */

tree
type_for_mode (mode, unsignedp)
     enum machine_mode mode;
     int unsignedp;
{
	return type_for_size (GET_MODE_BITSIZE (mode), unsignedp);
}

/* Return the unsigned version of a TYPE_NODE, a scalar type.  */

tree
unsigned_type (type_node)
     tree type_node;
{
	return type_for_size (TYPE_PRECISION (type_node), 1);
}

/* Return the signed version of a TYPE_NODE, a scalar type.  */

tree
signed_type (type_node)
     tree type_node;
{
	return type_for_size (TYPE_PRECISION (type_node), 0);
}

/* Return a type the same as TYPE except unsigned or signed according to
   UNSIGNEDP.  */

tree
signed_or_unsigned_type (unsignedp, type)
     int unsignedp;
     tree type;
{
	if (! INTEGRAL_TYPE_P (type) || TREE_UNSIGNED (type) == unsignedp)
		return type;
	else
		return type_for_size (TYPE_PRECISION (type), unsignedp);
}
