/*
	File:	cginstructions.c
	Author:	John van Groningen
	At:		University of Nijmegen
*/

#include <stdio.h>
#include <string.h>
#if defined (LINUX) && defined (G_AI64)
# include <stdint.h>
#endif
#include <stdlib.h>

#include "cgport.h"
#include "cg.h"
#include "cgconst.h"
#include "cgrconst.h"
#include "cgtypes.h"
#include "cgcode.h"
#include "cgcodep.h"
#include "cgstack.h"
#include "cglin.h"
#include "cginstructions.h"
#ifdef G_POWER
#	include "cgpas.h"
#	include "cgpwas.h"
#else
# ifdef I486
#	include "cgias.h"
#	include "cgiwas.h"
# else
#  ifdef SOLARIS
#	include "cgswas.h"
#  else
#	include "cgas.h"
#	include "cgwas.h"
#  endif
# endif
#endif
#if defined (THREAD32) || defined (THREAD64)
# include "cgiconst.h"
#endif
#ifndef MACH_O64
# define GEN_OBJ
#endif

#define LTEXT 0
#define LDATA 1

extern ULONG *offered_vector;
extern int offered_a_stack_size;
extern int offered_b_stack_size;

extern LABEL *enter_label (char *label_name,int label_flags);
extern LABEL *new_local_label (int label_flags);

extern LABEL *	system_sp_label,
				*string_to_string_node_label,*int_array_to_node_label,*real_array_to_node_label,
				*new_int_reducer_label,*channelP_label,*stop_reducer_label,*send_request_label,*send_graph_label;

#if (defined (I486) && !defined (THREAD64)) || defined (G_POWER)
LABEL *saved_heap_p_label,*saved_a_stack_p_label;
#endif
#ifdef MACH_O
LABEL *dyld_stub_binding_helper_p_label;
#endif
#if defined (THREAD32) || defined (THREAD64)
LABEL *tlsp_tls_index_label;
#endif

extern struct basic_block *last_block;

extern ULONG e_vector[],i_vector[],i_i_vector[],i_i_i_vector[],r_vector[];
extern int reachable;

extern int line_number; /* from cginput.c */

#define HIGH_LOW_FIRST_REAL_IN_RECORD
#define RESERVE_NEW_REDUCER

LABEL		*realloc_0_label,*realloc_1_label,*realloc_2_label,*realloc_3_label,
			*schedule_0_label,*schedule_1_label,*schedule_2_label,*schedule_3_label,
			*schedule_eval_label,*stack_overflow_label;

#ifdef SEPARATE_A_AND_B_STACK_OVERFLOW_CHECKS
LABEL	*end_a_stack_label,*end_b_stack_label;
#endif

INSTRUCTION_GRAPH g_new_node (int instruction_code,int arity,int arg_size)
{
	INSTRUCTION_GRAPH instruction;
	
	instruction=(struct instruction_node*)allocate_memory_from_heap (sizeof (struct instruction_node)+arg_size);

	instruction->instruction_code=instruction_code;
	instruction->inode_arity=arity;
	instruction->node_count=0;
	instruction->node_mark=0;
	instruction->instruction_d_min_a_cost=0;
	instruction->order_mode=0;

	return instruction;
}

INSTRUCTION_GRAPH g_instruction_1 (int instruction_code,INSTRUCTION_GRAPH graph_1)
{
	INSTRUCTION_GRAPH instruction;
	
	instruction=g_new_node (instruction_code,1,sizeof (union instruction_parameter));
	
	instruction->instruction_parameters[0].p=graph_1;
	
	return instruction;
}

INSTRUCTION_GRAPH g_instruction_2 (int instruction_code,INSTRUCTION_GRAPH graph_1,INSTRUCTION_GRAPH graph_2)
{
	INSTRUCTION_GRAPH instruction;
	
	instruction=g_new_node (instruction_code,2,2*sizeof (union instruction_parameter));
	
	instruction->instruction_parameters[0].p=graph_1;
	instruction->instruction_parameters[1].p=graph_2;
	
	return instruction;
}

INSTRUCTION_GRAPH g_instruction_2_0 (int instruction_code,INSTRUCTION_GRAPH graph_1,INSTRUCTION_GRAPH graph_2)
{
	INSTRUCTION_GRAPH instruction;
	
	instruction=g_new_node (instruction_code,3,3*sizeof (union instruction_parameter));
	
	instruction->instruction_parameters[0].p=graph_1;
	instruction->instruction_parameters[1].p=graph_2;
	instruction->instruction_parameters[2].p=NULL;
	
	return instruction;
}

INSTRUCTION_GRAPH g_test_o (INSTRUCTION_GRAPH graph_1)
{
	INSTRUCTION_GRAPH instruction;
	
	instruction=g_new_node (GTEST_O,1,sizeof (union instruction_parameter));
	
	instruction->instruction_parameters[0].p=graph_1;
	
	graph_1->instruction_parameters[2].p=instruction;
	
	return instruction;
}

INSTRUCTION_GRAPH g_allocate (INSTRUCTION_GRAPH graph_1,INSTRUCTION_GRAPH graph_2,int n)
{
	INSTRUCTION_GRAPH instruction;
	
	instruction=g_new_node (GALLOCATE,2+n,(2+n)*sizeof (union instruction_parameter));
	
	instruction->instruction_parameters[0].p=graph_1;
	instruction->instruction_parameters[1].p=graph_2;
	
	graph_2->instruction_d_min_a_cost+=1;
	
	return instruction;
}

static INSTRUCTION_GRAPH g_before0 (INSTRUCTION_GRAPH graph_1,int n)
{
	INSTRUCTION_GRAPH instruction;
	int argument_number;
	
	instruction=g_new_node (GBEFORE0,n+1,(n+1)*sizeof (union instruction_parameter));
	
	instruction->instruction_parameters[0].p=graph_1;
	
	for (argument_number=0; argument_number<n; ++argument_number)
		instruction->instruction_parameters[1+argument_number].p=NULL;
	
	return instruction;
}

INSTRUCTION_GRAPH g_copy (INSTRUCTION_GRAPH graph_1,INSTRUCTION_GRAPH graph_2)
{
	INSTRUCTION_GRAPH instruction;
	
	instruction=g_new_node (GCOPY,2,2*sizeof (union instruction_parameter));
	
	instruction->instruction_parameters[0].p=graph_1;
	instruction->instruction_parameters[1].p=graph_2;

	return instruction;
}

INSTRUCTION_GRAPH g_create_1 (INSTRUCTION_GRAPH graph_1)
{
	INSTRUCTION_GRAPH instruction;
	
	instruction=g_new_node (GCREATE,1,sizeof (union instruction_parameter));
	
	instruction->instruction_parameters[0].p=graph_1;

	return instruction;
}

INSTRUCTION_GRAPH g_create_2 (INSTRUCTION_GRAPH graph_1,INSTRUCTION_GRAPH graph_2)
{
	INSTRUCTION_GRAPH instruction;
	
	instruction=g_new_node (GCREATE,2,2*sizeof (union instruction_parameter));
	
	instruction->instruction_parameters[0].p=graph_1;
	instruction->instruction_parameters[1].p=graph_2;

	return instruction;
}

INSTRUCTION_GRAPH g_create_3 (INSTRUCTION_GRAPH graph_1,INSTRUCTION_GRAPH graph_2,INSTRUCTION_GRAPH graph_3)
{
	INSTRUCTION_GRAPH instruction;
	
	instruction=g_new_node (GCREATE,3,3*sizeof (union instruction_parameter));
	
	instruction->instruction_parameters[0].p=graph_1;
	instruction->instruction_parameters[1].p=graph_2;
	instruction->instruction_parameters[2].p=graph_3;

	return instruction;
}

INSTRUCTION_GRAPH g_create_m (int arity)
{
	INSTRUCTION_GRAPH instruction;
	
	instruction=g_new_node (GCREATE,arity,arity*sizeof (union instruction_parameter));
	
	return instruction;
}

INSTRUCTION_GRAPH g_create_r (INSTRUCTION_GRAPH graph_1,INSTRUCTION_GRAPH graph_2)
{
	INSTRUCTION_GRAPH instruction;
	
	instruction=g_new_node (GCREATE_R,2,2*sizeof (union instruction_parameter));
	
	instruction->instruction_parameters[0].p=graph_1;
	instruction->instruction_parameters[1].p=graph_2;

	return instruction;
}

INSTRUCTION_GRAPH g_exit_if (LABEL *label,INSTRUCTION_GRAPH graph_1,INSTRUCTION_GRAPH graph_2)
{
	INSTRUCTION_GRAPH exit_if_graph;
	
	exit_if_graph=g_new_node (GEXIT_IF,3,3*sizeof (union instruction_parameter));
	
	exit_if_graph->instruction_parameters[0].l=label;
	exit_if_graph->instruction_parameters[1].p=graph_1;
	exit_if_graph->instruction_parameters[2].p=graph_2;

	return exit_if_graph; 
}

INSTRUCTION_GRAPH g_fill_2 (INSTRUCTION_GRAPH graph_1,INSTRUCTION_GRAPH graph_2)
{
	INSTRUCTION_GRAPH instruction;
	
	instruction=g_new_node (GFILL,2,2*sizeof (union instruction_parameter));
	
	instruction->instruction_parameters[0].p=graph_1;
	instruction->instruction_parameters[1].p=graph_2;

	graph_1->instruction_d_min_a_cost+=1;

	if (graph_1->instruction_code==GBEFORE0)
		graph_1->instruction_code=GBEFORE;
	else if (graph_1->instruction_code==GCREATE && graph_1->inode_arity>0)
		graph_1->instruction_parameters[0].p=NULL;
	
	return instruction;
}

INSTRUCTION_GRAPH g_fill_3 (INSTRUCTION_GRAPH graph_1,INSTRUCTION_GRAPH graph_2,INSTRUCTION_GRAPH graph_3)
{
	INSTRUCTION_GRAPH instruction;
	
	instruction=g_new_node (GFILL,3,3*sizeof (union instruction_parameter));
	
	instruction->instruction_parameters[0].p=graph_1;
	instruction->instruction_parameters[1].p=graph_2;
	instruction->instruction_parameters[2].p=graph_3;

	graph_1->instruction_d_min_a_cost+=1;
	
	if (graph_1->instruction_code==GBEFORE0)
		graph_1->instruction_code=GBEFORE;
	else if (graph_1->instruction_code==GCREATE){
		int arity;

		arity=graph_1->inode_arity;
		if (arity>2)
			arity=2;
		
		while (arity>0)
			graph_1->instruction_parameters[--arity].p=NULL;
	}

	return instruction; 
}

INSTRUCTION_GRAPH g_fill_4 (INSTRUCTION_GRAPH graph_1,INSTRUCTION_GRAPH graph_2,INSTRUCTION_GRAPH graph_3,
							INSTRUCTION_GRAPH graph_4)
{
	INSTRUCTION_GRAPH instruction;
	
	instruction=g_new_node (GFILL,4,4*sizeof (union instruction_parameter));
	
	instruction->instruction_parameters[0].p=graph_1;
	instruction->instruction_parameters[1].p=graph_2;
	instruction->instruction_parameters[2].p=graph_3;
	instruction->instruction_parameters[3].p=graph_4;

	graph_1->instruction_d_min_a_cost+=1;
	
	if (graph_1->instruction_code==GBEFORE0)
		graph_1->instruction_code=GBEFORE;
	else if (graph_1->instruction_code==GCREATE){
		int arity;

		arity=graph_1->inode_arity;
		if (arity>3)
			arity=3;
		
		while (arity>0)
			graph_1->instruction_parameters[--arity].p=NULL;
	}

	return instruction; 
}

INSTRUCTION_GRAPH g_fill_m (INSTRUCTION_GRAPH graph_1,int arity)
{
	INSTRUCTION_GRAPH instruction;
	
	instruction=g_new_node (GFILL,arity+1,(arity+1)*sizeof (union instruction_parameter));
	
	instruction->instruction_parameters[0].p=graph_1;
	
	graph_1->instruction_d_min_a_cost+=1;

	if (graph_1->instruction_code==GBEFORE0)
		graph_1->instruction_code=GBEFORE;
	else if (graph_1->instruction_code==GCREATE){
		int arity;
		
		arity=graph_1->inode_arity;
		if (arity>2)
			arity=2;
		
		while (arity>0)
			graph_1->instruction_parameters[--arity].p=NULL;
	}

	return instruction;
}

INSTRUCTION_GRAPH g_fill_r (INSTRUCTION_GRAPH graph_1,INSTRUCTION_GRAPH graph_2,INSTRUCTION_GRAPH graph_3)
{
	INSTRUCTION_GRAPH instruction;
	
	instruction=g_new_node (GFILL_R,3,3*sizeof (union instruction_parameter));
	
	instruction->instruction_parameters[0].p=graph_1;
	instruction->instruction_parameters[1].p=graph_2;
	instruction->instruction_parameters[2].p=graph_3;

	graph_1->instruction_d_min_a_cost+=1;
	
	if (graph_1->instruction_code==GBEFORE0)
		graph_1->instruction_code=GBEFORE;
	else if (graph_1->instruction_code==GCREATE){
		int arity=graph_1->inode_arity;
		if (arity>3)
			arity=3;
		
		while (arity>0)
			graph_1->instruction_parameters[--arity].p=NULL;
	}

	return instruction; 
}

#ifdef G_A64
INSTRUCTION_GRAPH g_fp_arg (INSTRUCTION_GRAPH graph_1)
{
	if (graph_1->instruction_code==GFROMF)
		return graph_1->instruction_parameters[0].p;

	if (graph_1->instruction_code==GLOAD){
		INSTRUCTION_GRAPH fload_graph;

		fload_graph=g_fload (graph_1->instruction_parameters[0].i,graph_1->instruction_parameters[1].i);

		graph_1->instruction_code=GFROMF;
		graph_1->instruction_parameters[0].p=fload_graph;

		return fload_graph;
	}

	if (graph_1->instruction_code==GLOAD_ID){
		INSTRUCTION_GRAPH fload_graph;
				
		fload_graph=
			g_fload_id (graph_1->instruction_parameters[0].i,graph_1->instruction_parameters[1].p);

		graph_1->instruction_code=GFROMF;
		graph_1->instruction_parameters[0].p=fload_graph;

		return fload_graph;
	}

	if (graph_1->instruction_code==GMOVEMI){
		INSTRUCTION_GRAPH fmovemi_graph,movem_graph;
		int number;
				
		movem_graph=graph_1->instruction_parameters[0].p;
		number=graph_1->inode_arity;

		fmovemi_graph=g_new_node (GFMOVEMI,number,2*sizeof (union instruction_parameter));
		
		fmovemi_graph->instruction_parameters[0].p=movem_graph;
		fmovemi_graph->instruction_parameters[1].i=0;
		
		movem_graph->instruction_parameters[2+number].p=fmovemi_graph;
		movem_graph->instruction_parameters[2+number+1].p=NULL;

		graph_1->instruction_code=GFROMF;
		graph_1->instruction_parameters[0].p=fmovemi_graph;
		
		return fmovemi_graph;		
	}

	if (graph_1->instruction_code==GLOAD_X){
		INSTRUCTION_GRAPH fload_graph,*previous_loadx;

		previous_loadx=&load_indexed_list;

		while (*previous_loadx!=NULL && *previous_loadx!=graph_1)
			previous_loadx=&(*previous_loadx)->instruction_parameters[3].p;
		
		fload_graph=g_new_node (GFLOAD_X,0,4*sizeof (union instruction_parameter));
		
		fload_graph->instruction_parameters[0].p=graph_1->instruction_parameters[0].p;
		fload_graph->instruction_parameters[1].i=graph_1->instruction_parameters[1].i;
		fload_graph->instruction_parameters[2].p=graph_1->instruction_parameters[2].p;
		fload_graph->instruction_parameters[3].p=graph_1->instruction_parameters[3].p;

		if (*previous_loadx!=NULL)
			*previous_loadx=fload_graph;

		fload_graph->instruction_d_min_a_cost+=1;
		
		graph_1->instruction_code=GFROMF;
		graph_1->instruction_parameters[0].p=fload_graph;

		return fload_graph;
	}

	return g_tof (graph_1);	
}
#else
INSTRUCTION_GRAPH g_fjoin (INSTRUCTION_GRAPH graph_1,INSTRUCTION_GRAPH graph_2)
{
	if (graph_1->instruction_code==GFHIGH && graph_2->instruction_code==GFLOW
		&& graph_1->instruction_parameters[0].p==graph_2->instruction_parameters[0].p)
			return graph_1->instruction_parameters[0].p;

	if (graph_1->instruction_code==GLOAD && graph_2->instruction_code==GLOAD
		&& graph_1->instruction_parameters[1].i==graph_2->instruction_parameters[1].i
		&& graph_1->instruction_parameters[0].i+4==graph_2->instruction_parameters[0].i)
	{
		INSTRUCTION_GRAPH fload_graph;
				
		fload_graph=g_fload (graph_1->instruction_parameters[0].i,graph_1->instruction_parameters[1].i);
		
		graph_1->instruction_code=GFHIGH;
		graph_2->instruction_code=GFLOW;
		graph_1->instruction_parameters[0].p=fload_graph;
		graph_2->instruction_parameters[0].p=fload_graph;

		graph_1->instruction_parameters[1].p=graph_2;
		graph_2->instruction_parameters[1].p=graph_1;

		return fload_graph;
	}

	if (graph_1->instruction_code==GLOAD_ID && graph_2->instruction_code==GLOAD_ID
# ifdef HIGH_LOW_FIRST_REAL_IN_RECORD
		)
		if (!(graph_1->instruction_parameters[1].i==graph_2->instruction_parameters[1].i
			&& graph_1->instruction_parameters[0].i+4==graph_2->instruction_parameters[0].i))
		{
			INSTRUCTION_GRAPH join_graph,load_id_graph_1,load_id_graph_2;
			
			load_id_graph_1=g_load_id (graph_1->instruction_parameters[0].i,graph_1->instruction_parameters[1].p);
			load_id_graph_2=g_load_id (graph_2->instruction_parameters[0].i,graph_2->instruction_parameters[1].p);
			
			join_graph=g_instruction_2 (GFJOIN,load_id_graph_1,load_id_graph_2);

			graph_1->instruction_code=GFHIGH;
			graph_1->instruction_parameters[0].p=join_graph;
			graph_1->instruction_parameters[1].p=graph_2;
	
			graph_2->instruction_code=GFLOW;
			graph_2->instruction_parameters[0].p=join_graph;
			graph_2->instruction_parameters[1].p=graph_1;

			return join_graph;
		} else
# else
		&& graph_1->instruction_parameters[1].i==graph_2->instruction_parameters[1].i
		&& graph_1->instruction_parameters[0].i+4==graph_2->instruction_parameters[0].i)
# endif
	{
		INSTRUCTION_GRAPH fload_graph;
				
		fload_graph=
			g_fload_id (graph_1->instruction_parameters[0].i,graph_1->instruction_parameters[1].p);

		graph_1->instruction_code=GFHIGH;
		graph_1->instruction_parameters[0].p=fload_graph;
		graph_1->instruction_parameters[1].p=graph_2;

		graph_2->instruction_code=GFLOW;
		graph_2->instruction_parameters[0].p=fload_graph;
		graph_2->instruction_parameters[1].p=graph_1;

		return fload_graph;
	}

	if (graph_1->instruction_code==GMOVEMI && graph_2->instruction_code==GMOVEMI
		&&	graph_1->instruction_parameters[0].p==graph_2->instruction_parameters[0].p
		&&	graph_1->inode_arity+1==graph_2->inode_arity)
	{
		INSTRUCTION_GRAPH fmovemi_graph,movem_graph;
		int number;
				
		movem_graph=graph_1->instruction_parameters[0].p;
		number=graph_1->inode_arity;

		fmovemi_graph=g_new_node (GFMOVEMI,number,2*sizeof (union instruction_parameter));
		
		fmovemi_graph->instruction_parameters[0].p=movem_graph;
		fmovemi_graph->instruction_parameters[1].i=0;
		
		movem_graph->instruction_parameters[2+number].p=fmovemi_graph;
		movem_graph->instruction_parameters[2+number+1].p=NULL;

		graph_1->instruction_code=GFHIGH;
		graph_1->instruction_parameters[0].p=fmovemi_graph;
		graph_1->instruction_parameters[1].p=graph_2;
		
		graph_2->instruction_code=GFLOW;
		graph_2->instruction_parameters[0].p=fmovemi_graph;
		graph_2->instruction_parameters[1].p=graph_1;
		
		return fmovemi_graph;		
	}

	if (graph_1->instruction_code==GLOAD_X && graph_2->instruction_code==GLOAD_X
		&& graph_1->instruction_parameters[1].i+(4<<2)==graph_2->instruction_parameters[1].i
		&& graph_1->instruction_parameters[0].p==graph_2->instruction_parameters[0].p
		&& graph_1->instruction_parameters[2].p==graph_2->instruction_parameters[2].p
		&& graph_1->instruction_parameters[3].p==graph_2)
	{
		INSTRUCTION_GRAPH fload_graph,*previous_loadx;

		previous_loadx=&load_indexed_list;

		while (*previous_loadx!=NULL && *previous_loadx!=graph_1)
			previous_loadx=&(*previous_loadx)->instruction_parameters[3].p;
		
		fload_graph=g_new_node (GFLOAD_X,0,4*sizeof (union instruction_parameter));
		
		fload_graph->instruction_parameters[0].p=graph_1->instruction_parameters[0].p;
		fload_graph->instruction_parameters[1].i=graph_1->instruction_parameters[1].i;
		fload_graph->instruction_parameters[2].p=graph_1->instruction_parameters[2].p;

		fload_graph->instruction_parameters[3].p=graph_2->instruction_parameters[3].p;

		if (*previous_loadx!=NULL)
			*previous_loadx=fload_graph;

		fload_graph->instruction_d_min_a_cost+=1;
		
		graph_1->instruction_code=GFHIGH;
		graph_1->instruction_parameters[0].p=fload_graph;
		graph_1->instruction_parameters[1].p=graph_2;
		graph_1->instruction_parameters[3].p=fload_graph;

		graph_2->instruction_code=GFLOW;
		graph_2->instruction_parameters[0].p=fload_graph;
		graph_2->instruction_parameters[1].p=graph_1;
		graph_2->instruction_parameters[3].p=fload_graph;

		return fload_graph;
	}

	return g_instruction_2 (GFJOIN,graph_1,graph_2);
}
#endif

INSTRUCTION_GRAPH g_fload (int offset,int stack)
{
	INSTRUCTION_GRAPH instruction;
	
	instruction=g_new_node (GFLOAD,0,2*sizeof (union instruction_parameter));
	
	instruction->instruction_parameters[0].i=offset;
	instruction->instruction_parameters[1].i=stack;
	
	return instruction;
}

INSTRUCTION_GRAPH g_fload_i (DOUBLE v)
{
	INSTRUCTION_GRAPH instruction;
	
	instruction=g_new_node (GFLOAD_I,0,sizeof (DOUBLE));
	
	*(DOUBLE*)&instruction->instruction_parameters[0]=v;
	
	return instruction;
}

INSTRUCTION_GRAPH g_fload_id (int offset,INSTRUCTION_GRAPH graph_1)
{
	INSTRUCTION_GRAPH instruction;
	
	instruction=g_new_node (GFLOAD_ID,0,2*sizeof (union instruction_parameter));
	
	instruction->instruction_parameters[0].i=offset;
	instruction->instruction_parameters[1].p=graph_1;
	
	graph_1->instruction_d_min_a_cost+=1;
	
	return instruction;
}

INSTRUCTION_GRAPH g_fload_x (INSTRUCTION_GRAPH graph_1,int offset,int shift,INSTRUCTION_GRAPH graph_2)
{
	INSTRUCTION_GRAPH instruction;
	
	instruction=g_new_node (GFLOAD_X,0,4*sizeof (union instruction_parameter));
	
	instruction->instruction_parameters[0].p=graph_1;
	instruction->instruction_parameters[1].i=(offset<<2) | shift;
	instruction->instruction_parameters[2].p=graph_2;
	instruction->instruction_parameters[3].p=load_indexed_list;

#if defined (sparc) || defined (G_POWER)
	if (offset!=0 && graph_2!=NULL)
		graph_2->instruction_d_min_a_cost+=1;
	else
#endif
	graph_1->instruction_d_min_a_cost+=1;
	
	load_indexed_list=instruction;

	return instruction;
}

#ifdef I486
INSTRUCTION_GRAPH g_fload_s_x (INSTRUCTION_GRAPH graph_1,int offset,int shift,INSTRUCTION_GRAPH graph_2)
{
	INSTRUCTION_GRAPH instruction;
	
	instruction=g_new_node (GFLOAD_S_X,0,4*sizeof (union instruction_parameter));
	
	instruction->instruction_parameters[0].p=graph_1;
	instruction->instruction_parameters[1].i=(offset<<2) | shift;
	instruction->instruction_parameters[2].p=graph_2;
	instruction->instruction_parameters[3].p=load_indexed_list;

	graph_1->instruction_d_min_a_cost+=1;
	
	load_indexed_list=instruction;

	return instruction;
}
#endif

INSTRUCTION_GRAPH g_fstore (int offset,int reg_1,INSTRUCTION_GRAPH graph_1,
#ifdef G_A64
	INSTRUCTION_GRAPH graph_2)
#else
	INSTRUCTION_GRAPH graph_2,INSTRUCTION_GRAPH graph_3)
#endif
{
	INSTRUCTION_GRAPH instruction;
	
#ifdef G_A64
	instruction=g_new_node (GFSTORE,0,4*sizeof (union instruction_parameter));
#else
	instruction=g_new_node (GFSTORE,0,5*sizeof (union instruction_parameter));
#endif
	instruction->instruction_parameters[0].i=offset;
	instruction->instruction_parameters[1].i=reg_1;
	instruction->instruction_parameters[2].p=graph_1;
	
#ifdef G_A64
	if (graph_2 && graph_2->instruction_code==GTOF)
		instruction->instruction_parameters[3].p=graph_2->instruction_parameters[0].p;
	else
		instruction->instruction_parameters[3].p=graph_2;
#else
	if (graph_2 && (graph_2->instruction_code==GFLOW || graph_2->instruction_code==GFHIGH))
		instruction->instruction_parameters[3].p=graph_2->instruction_parameters[0].p;
	else
		instruction->instruction_parameters[3].p=graph_2;
		
	if (graph_3 && (graph_3->instruction_code==GFLOW || graph_3->instruction_code==GFHIGH))
		instruction->instruction_parameters[4].p=graph_3->instruction_parameters[0].p;
	else
		instruction->instruction_parameters[4].p=graph_3;
#endif		
	return instruction;
}

INSTRUCTION_GRAPH g_fstore_r (int reg_1,INSTRUCTION_GRAPH graph_1)
{
	INSTRUCTION_GRAPH instruction;
	
	instruction=g_new_node (GFSTORE_R,0,2*sizeof (union instruction_parameter));
	
	instruction->instruction_parameters[0].i=reg_1;
	instruction->instruction_parameters[1].p=graph_1;

	return instruction;
}

INSTRUCTION_GRAPH g_lea (LABEL *label)
{
	INSTRUCTION_GRAPH instruction;
	
	instruction=g_new_node (GLEA,0,sizeof (union instruction_parameter));
	
	instruction->instruction_parameters[0].l=label;
	
	return instruction;
}

INSTRUCTION_GRAPH g_lea_i (LABEL *label,int offset)
{
	INSTRUCTION_GRAPH instruction;
	
	instruction=g_new_node (GLEA,1,2*sizeof (union instruction_parameter));
	
	instruction->instruction_parameters[0].l=label;
	instruction->instruction_parameters[1].i=offset;
				
	return instruction;
}

INSTRUCTION_GRAPH g_load (int offset,int stack)
{
	register INSTRUCTION_GRAPH instruction;
	
	instruction=g_new_node (GLOAD,0,2*sizeof (union instruction_parameter));
	
	instruction->instruction_parameters[0].i=offset;
	instruction->instruction_parameters[1].i=stack;
	
	return instruction;
}

INSTRUCTION_GRAPH g_load_i (CleanInt value)
{
	INSTRUCTION_GRAPH instruction;
	
	instruction=g_new_node (GLOAD_I,0,sizeof (union instruction_parameter));
	
	instruction->instruction_parameters[0].imm=value;
	
	return instruction;
}

INSTRUCTION_GRAPH g_load_id (int offset,INSTRUCTION_GRAPH graph_1)
{
	INSTRUCTION_GRAPH instruction;
	
	instruction=g_new_node (GLOAD_ID,0,2*sizeof (union instruction_parameter));
	
	instruction->instruction_parameters[0].i=offset;
	instruction->instruction_parameters[1].p=graph_1;
	
	graph_1->instruction_d_min_a_cost+=1;
	
	return instruction;
}

INSTRUCTION_GRAPH g_load_b_x (INSTRUCTION_GRAPH graph_1,int offset,int sign_extend,INSTRUCTION_GRAPH graph_2)
{
	register INSTRUCTION_GRAPH instruction;
	
	instruction=g_new_node (GLOAD_B_X,0,4*sizeof (union instruction_parameter));
	
	instruction->instruction_parameters[0].p=graph_1;
	instruction->instruction_parameters[1].i=(offset<<2) | sign_extend;
	instruction->instruction_parameters[2].p=graph_2;
	instruction->instruction_parameters[3].p=load_indexed_list;
	
	graph_1->instruction_d_min_a_cost+=1;
	
	load_indexed_list=instruction;

	return instruction;
}

INSTRUCTION_GRAPH g_load_x (INSTRUCTION_GRAPH graph_1,int offset,int shift,INSTRUCTION_GRAPH graph_2)
{
	INSTRUCTION_GRAPH instruction;
	
	instruction=g_new_node (GLOAD_X,0,4*sizeof (union instruction_parameter));
	
	instruction->instruction_parameters[0].p=graph_1;
	instruction->instruction_parameters[1].i=(offset<<2) | shift;
	instruction->instruction_parameters[2].p=graph_2;
	instruction->instruction_parameters[3].p=load_indexed_list;

#if defined (sparc) || defined (G_POWER)
	if (offset!=0 && graph_2!=NULL)
		graph_2->instruction_d_min_a_cost+=1;
	else
#endif
	graph_1->instruction_d_min_a_cost+=1;
	
	load_indexed_list=instruction;

	return instruction;
}

INSTRUCTION_GRAPH g_load_b_id (int offset,INSTRUCTION_GRAPH graph_1)
{
	register INSTRUCTION_GRAPH instruction;
	
	instruction=g_new_node (GLOAD_B_ID,0,2*sizeof (union instruction_parameter));
	
	instruction->instruction_parameters[0].i=offset;
	instruction->instruction_parameters[1].p=graph_1;
	
	graph_1->instruction_d_min_a_cost+=1;
	
	return instruction;
}

INSTRUCTION_GRAPH g_load_des_i (LABEL *descriptor_label,int arity)
{
	register INSTRUCTION_GRAPH instruction;
	
	instruction=g_new_node (GLOAD_DES_I,0,2*sizeof (union instruction_parameter));
	
	instruction->instruction_parameters[0].l=descriptor_label;
#ifdef I486
# ifdef MACH_O64
	instruction->instruction_parameters[1].i=(arity<<4)+2;
# else
	instruction->instruction_parameters[1].i=(arity<<3)+2;
# endif
#else
	instruction->instruction_parameters[1].i=arity;
#endif
	
	return instruction;
}

INSTRUCTION_GRAPH g_load_des_id (int offset,INSTRUCTION_GRAPH graph_1)
{
	register INSTRUCTION_GRAPH instruction;
	
	instruction=g_new_node (GLOAD_DES_ID,0,2*sizeof (union instruction_parameter));
	
	instruction->instruction_parameters[0].i=offset;
	instruction->instruction_parameters[1].p=graph_1;
	
	graph_1->instruction_d_min_a_cost+=1;
	
	return instruction;
}

#ifdef G_AI64
INSTRUCTION_GRAPH g_load_s_x (INSTRUCTION_GRAPH graph_1,int offset,int shift,INSTRUCTION_GRAPH graph_2)
{
	INSTRUCTION_GRAPH instruction;
	
	instruction=g_new_node (GLOAD_S_X,0,4*sizeof (union instruction_parameter));
	
	instruction->instruction_parameters[0].p=graph_1;
	instruction->instruction_parameters[1].imm=(((CleanInt)offset)<<4) | (shift<<2);
	instruction->instruction_parameters[2].p=graph_2;
	instruction->instruction_parameters[3].p=load_indexed_list;

	graph_1->instruction_d_min_a_cost+=1;
	
	load_indexed_list=instruction;

	return instruction;
}

INSTRUCTION_GRAPH g_load_sqb_id (int offset,INSTRUCTION_GRAPH graph_1)
{
	INSTRUCTION_GRAPH instruction;

	instruction=g_new_node (GLOAD_SQB_ID,0,2*sizeof (union instruction_parameter));

	instruction->instruction_parameters[0].i=offset;
	instruction->instruction_parameters[1].p=graph_1;

	graph_1->instruction_d_min_a_cost+=1;

	return instruction;
}
#endif

INSTRUCTION_GRAPH g_movem (int offset,INSTRUCTION_GRAPH graph_1,int n)
{
	INSTRUCTION_GRAPH instruction;
	int argument_number;
	
	instruction=g_new_node (GMOVEM,n,(2+n)*sizeof (union instruction_parameter));
	
	instruction->instruction_parameters[0].i=offset;
	instruction->instruction_parameters[1].p=graph_1;
	
	for (argument_number=0; argument_number<n; ++argument_number)
		instruction->instruction_parameters[2+argument_number].p=NULL;
	
	return instruction;
}

INSTRUCTION_GRAPH g_movemi (int number,INSTRUCTION_GRAPH movem_graph)
{
	register INSTRUCTION_GRAPH instruction;
	
	instruction=g_new_node (GMOVEMI,number,2*sizeof (union instruction_parameter));
	
	instruction->instruction_parameters[0].p=movem_graph;
	instruction->instruction_parameters[1].i=0;
	
	movem_graph->instruction_parameters[2+number].p=instruction;
	
	return instruction;
}

INSTRUCTION_GRAPH g_fregister (int float_reg)
{
	INSTRUCTION_GRAPH instruction;
	
	instruction=g_new_node (GFREGISTER,0,sizeof (union instruction_parameter));

	if ((unsigned)float_reg<(unsigned)N_FLOAT_PARAMETER_REGISTERS)
		global_block.block_graph_f_register_parameter_node[float_reg]=instruction;
			
	instruction->instruction_parameters[0].i=float_reg;
			
	return instruction;
}

INSTRUCTION_GRAPH g_fstore_x (INSTRUCTION_GRAPH graph_1,INSTRUCTION_GRAPH graph_2,int offset,int shift,INSTRUCTION_GRAPH graph_3)
{
	INSTRUCTION_GRAPH instruction;
	
	instruction=g_new_node (GFSTORE_X,0,5*sizeof (union instruction_parameter));
	
	instruction->instruction_parameters[0].p=graph_1;
	instruction->instruction_parameters[1].p=graph_2;
	instruction->instruction_parameters[2].i=(offset<<2) | shift;
	instruction->instruction_parameters[3].p=graph_3;
	instruction->instruction_parameters[4].p=load_indexed_list;

#if defined (sparc) || defined (G_POWER)
	if (offset!=0 && graph_3!=NULL)
		graph_3->instruction_d_min_a_cost+=1;
	else
#endif
	graph_2->instruction_d_min_a_cost+=1;
	
	return instruction;
}

#ifdef I486
INSTRUCTION_GRAPH g_fstore_s_x (INSTRUCTION_GRAPH graph_1,INSTRUCTION_GRAPH graph_2,int offset,int shift,INSTRUCTION_GRAPH graph_3)
{
	INSTRUCTION_GRAPH instruction;
	
	instruction=g_new_node (GFSTORE_S_X,0,5*sizeof (union instruction_parameter));
	
	instruction->instruction_parameters[0].p=graph_1;
	instruction->instruction_parameters[1].p=graph_2;
	instruction->instruction_parameters[2].i=(offset<<2) | shift;
	instruction->instruction_parameters[3].p=graph_3;
	instruction->instruction_parameters[4].p=load_indexed_list;

	graph_2->instruction_d_min_a_cost+=1;
	
	return instruction;
}
#endif

INSTRUCTION_GRAPH g_g_register (int reg)
{
	INSTRUCTION_GRAPH instruction;
	
	instruction=g_new_node (GGREGISTER,0,sizeof (union instruction_parameter));
	
	instruction->instruction_parameters[0].i=reg;
	
	return instruction;
}

INSTRUCTION_GRAPH g_register (int reg)
{
	INSTRUCTION_GRAPH instruction;
	
	instruction=g_new_node (GREGISTER,0,sizeof (union instruction_parameter));
	
	instruction->instruction_parameters[0].i=reg;
	
	if ((unsigned)a_reg_num (reg)<(unsigned)N_ADDRESS_PARAMETER_REGISTERS)
		global_block.block_graph_a_register_parameter_node[a_reg_num (reg)]=instruction;
		
	if ((unsigned)d_reg_num (reg)<(unsigned)N_DATA_PARAMETER_REGISTERS)
		global_block.block_graph_d_register_parameter_node[d_reg_num (reg)]=instruction;
		
	return instruction;
}

INSTRUCTION_GRAPH g_store (int offset,int reg_1,INSTRUCTION_GRAPH graph_1,
							INSTRUCTION_GRAPH graph_2)
{
	register INSTRUCTION_GRAPH instruction;
	
	instruction=g_new_node (GSTORE,0,4*sizeof (union instruction_parameter));
	
	instruction->instruction_parameters[0].i=offset;
	instruction->instruction_parameters[1].i=reg_1;
	instruction->instruction_parameters[2].p=graph_1;
	
#ifdef G_A64
	if (graph_2 && graph_2->instruction_code==GTOF)
#else
	if (graph_2 && (graph_2->instruction_code==GFLOW || graph_2->instruction_code==GFHIGH))
#endif
		instruction->instruction_parameters[3].p=graph_2->instruction_parameters[0].p;
	else
		instruction->instruction_parameters[3].p=graph_2;
	
	return instruction;
}

INSTRUCTION_GRAPH g_store_b_x (INSTRUCTION_GRAPH graph_1,INSTRUCTION_GRAPH graph_2,int offset,INSTRUCTION_GRAPH graph_3)
{
	INSTRUCTION_GRAPH instruction;
	
	instruction=g_new_node (GSTORE_B_X,0,5*sizeof (union instruction_parameter));
	
	instruction->instruction_parameters[0].p=graph_1;
	instruction->instruction_parameters[1].p=graph_2;
	instruction->instruction_parameters[2].i=(offset<<2);
	instruction->instruction_parameters[3].p=graph_3;
	instruction->instruction_parameters[4].p=load_indexed_list;
	
	graph_2->instruction_d_min_a_cost+=1;
	
	return instruction;
}

#ifdef G_AI64
INSTRUCTION_GRAPH g_store_s_x (INSTRUCTION_GRAPH graph_1,INSTRUCTION_GRAPH graph_2,int offset,int shift,INSTRUCTION_GRAPH graph_3)
{
	INSTRUCTION_GRAPH instruction;
	
	instruction=g_new_node (GSTORE_S_X,0,5*sizeof (union instruction_parameter));
	
	instruction->instruction_parameters[0].p=graph_1;
	instruction->instruction_parameters[1].p=graph_2;
	instruction->instruction_parameters[2].imm=(((CleanInt)offset)<<4) | (shift<<2);
	instruction->instruction_parameters[3].p=graph_3;
	instruction->instruction_parameters[4].p=load_indexed_list;

	graph_2->instruction_d_min_a_cost+=1;
	
	return instruction;
}
#endif

INSTRUCTION_GRAPH g_store_x (INSTRUCTION_GRAPH graph_1,INSTRUCTION_GRAPH graph_2,int offset,int shift,INSTRUCTION_GRAPH graph_3)
{
	INSTRUCTION_GRAPH instruction;
	
	instruction=g_new_node (GSTORE_X,0,5*sizeof (union instruction_parameter));
	
	instruction->instruction_parameters[0].p=graph_1;
	instruction->instruction_parameters[1].p=graph_2;
	instruction->instruction_parameters[2].i=(offset<<2) | shift;
	instruction->instruction_parameters[3].p=graph_3;
	instruction->instruction_parameters[4].p=load_indexed_list;

#if defined (sparc) || defined (G_POWER)
	if (offset!=0 && graph_3!=NULL)
		graph_3->instruction_d_min_a_cost+=1;
	else
#endif
	graph_2->instruction_d_min_a_cost+=1;
	
	return instruction;
}

INSTRUCTION_GRAPH g_store_r (int reg_1,INSTRUCTION_GRAPH graph_1)
{
	register INSTRUCTION_GRAPH instruction;
	
	instruction=g_new_node (GSTORE_R,0,2*sizeof (union instruction_parameter));
	
	instruction->instruction_parameters[0].i=reg_1;
	instruction->instruction_parameters[1].p=graph_1;
	
	if (graph_1->instruction_code==GMOVEMI)
		graph_1->instruction_parameters[1].i=(reg_1<<1)+1;
	
	return instruction;
}

LABEL *w_code_string (char *string,int length)
{
	LABEL *string_label;

	string_label=new_local_label (LOCAL_LABEL
#ifdef G_POWER
									| DATA_LABEL
#endif
	);

#ifdef FUNCTION_LEVEL_LINKING
	as_new_data_module();
	if (assembly_flag)
		w_as_new_data_module();
#endif

#ifdef GEN_OBJ
	define_data_label (string_label);
	store_c_string_in_data_section (string,length);
#endif	
	if (assembly_flag)
		w_as_labeled_c_string_in_data_section (string,length,string_label->label_number);
	
	return string_label;
}

LABEL *w_code_descriptor_length_and_string (char *string,int length)
{
	LABEL *string_label;

	if (_STRING__label==NULL)
		_STRING__label=enter_label ("__STRING__",IMPORT_LABEL | DATA_LABEL);

	string_label=new_local_label (LOCAL_LABEL
#ifdef G_POWER
									| DATA_LABEL
#endif
	);

#ifdef FUNCTION_LEVEL_LINKING
	as_new_data_module();
	if (assembly_flag)
		w_as_new_data_module();
#endif

#ifdef GEN_OBJ
	define_data_label (string_label);
	if (_STRING__label->label_id<0)
		_STRING__label->label_id=next_label_id++;
	store_descriptor_in_data_section (_STRING__label);
	store_abc_string_in_data_section (string,length);
#endif
	if (assembly_flag){
# ifdef MACH_O64
		w_as_align_and_define_data_label (string_label->label_number);
# else
		w_as_define_data_label (string_label->label_number);
# endif
		w_as_descriptor_in_data_section (_STRING__label->label_name);
		w_as_abc_string_in_data_section (string,length);
	}
	
	return string_label;
}

LABEL *w_code_length_and_string (char *string,int length)
{
	LABEL *string_label;

	string_label=new_local_label (LOCAL_LABEL
#ifdef G_POWER
									| DATA_LABEL
#endif
	);

#ifdef FUNCTION_LEVEL_LINKING
	as_new_data_module();
	if (assembly_flag)
		w_as_new_data_module();
#endif

#ifdef GEN_OBJ
	define_data_label (string_label);
	store_abc_string_in_data_section (string,length);
#endif
	if (assembly_flag){
		w_as_define_data_label (string_label->label_number);
		w_as_abc_string_in_data_section (string,length);
	}

	return string_label;
}

void w_descriptor_string (char *string,int length,int string_code_label_id,LABEL *string_label)
{
#ifdef GEN_OBJ
	store_descriptor_string_in_data_section (string,length,string_label);
#endif
	if (assembly_flag)
		w_as_descriptor_string_in_data_section (string,length,string_code_label_id,string_label);
}

void code_n_string (char string[],int string_length)
{
}

void code_fill1_r (char descriptor_name[],int a_size,int b_size,int root_offset,char bits[])
{
	INSTRUCTION_GRAPH graph_1,graph_2,graph_3,graph_4,graph_5,graph_6;
	LABEL *descriptor_label;
	
	graph_1=s_get_a (root_offset);

	if (bits[0]=='1'){
		descriptor_label=enter_label (descriptor_name,DATA_LABEL);

		if (!parallel_flag && descriptor_label->label_last_lea_block==last_block)
			graph_2=descriptor_label->label_last_lea;
		else {
			graph_2=g_load_des_i (descriptor_label,0);

			if (!parallel_flag ){
				descriptor_label->label_last_lea=graph_2;
				descriptor_label->label_last_lea_block=last_block;
			}
		}
	} else
		graph_2=NULL;

	switch (a_size+b_size){
		case 0:
			graph_4=g_fill_2 (graph_1,graph_2);
			break;
		case 1:
			if (bits[1]=='0')
				graph_5=NULL;
			else
				if (a_size!=0){
					graph_5=s_pop_a();
					--root_offset;
				} else
					graph_5=s_pop_b();
			graph_4=g_fill_3 (graph_1,graph_2,graph_5);
			break;
		case 2:
			switch (b_size){
				case 0:
					if (bits[1]=='0')
						graph_5=NULL;
					else {
						graph_5=s_pop_a();
						--root_offset;
					}
					if (bits[2]=='0')
						graph_6=NULL;
					else {
						graph_6=s_pop_a();
						--root_offset;
					}
					break;				
				case 1:
					if (bits[1]=='0')
						graph_5=NULL;
					else {
						graph_5=s_pop_a();
						--root_offset;
					}
					if (bits[2]=='0')
						graph_6=NULL;
					else
						graph_6=s_pop_b();
					break;
				default:
					if (bits[1]=='0')
						graph_5=NULL;
					else
						graph_5=s_pop_b();
					if (bits[2]=='0')
						graph_6=NULL;
					else
						graph_6=s_pop_b();
			}
			graph_4=g_fill_4 (graph_1,graph_2,graph_5,graph_6);
			break;
		default:
		{
			union instruction_parameter *parameter;
			int a_n,b_n;
			
			a_n=0;
			b_n=0;
			
			if (a_n<a_size){
				graph_5=s_pop_a();
				--root_offset;
				++a_n;
			} else {
				graph_5=s_pop_b();
				++b_n;
			}
			
			graph_3=g_create_m (a_size+b_size-1);
			
			parameter=graph_3->instruction_parameters;

			while (a_n<a_size){
				if (bits[a_n+1]=='0')
					parameter->p=NULL;
				else {
					parameter->p=s_pop_a();
					--root_offset;
				}
				++parameter;
				++a_n;
			}

			while (b_n<b_size){
				if (bits[b_n+a_size+1]=='0')
					parameter->p=NULL;
				else
					parameter->p=s_pop_b();
				++parameter;
				++b_n;
			}

			graph_4=g_fill_4 (graph_1,graph_2,graph_5,graph_3);
		}
	}
	
	s_put_a (root_offset,graph_4);
}

#define g_keep(g1,g2) g_instruction_2(GKEEP,(g1),(g2))

void code_fill2_r (char descriptor_name[],int a_size,int b_size,int root_offset,char bits[])
{
	INSTRUCTION_GRAPH graph_1,graph_2,graph_3,graph_4,graph_5;
	LABEL *descriptor_label;
	union instruction_parameter *parameter;
	int a_n,b_n;
	
	graph_1=s_get_a (root_offset);
	if (graph_1->instruction_code==GBEFORE0)
		graph_1->instruction_code=GBEFORE;

	if (bits[0]=='1'){
		descriptor_label=enter_label (descriptor_name,DATA_LABEL);

		if (!parallel_flag && descriptor_label->label_last_lea_block==last_block)
			graph_2=descriptor_label->label_last_lea;
		else {
			graph_2=g_load_des_i (descriptor_label,0);

			if (!parallel_flag ){
				descriptor_label->label_last_lea=graph_2;
				descriptor_label->label_last_lea_block=last_block;
			}
		}
	} else
		graph_2=NULL;

	a_n=0;
	b_n=0;
		
	if (a_n<a_size){
		if (bits[a_n+1]=='0')
			graph_5=NULL;
		else {
			graph_5=s_pop_a();
			--root_offset;
		}
		++a_n;
	} else {
		if (bits[b_n+a_size+1]=='0')
			graph_5=NULL;
		else
			graph_5=s_pop_b();
		++b_n;
	}
	
	graph_3=g_fill_m (g_load_id (2*STACK_ELEMENT_SIZE,graph_1),a_size+b_size-1);
	
	parameter=&graph_3->instruction_parameters[1];

	while (a_n<a_size){
		if (bits[a_n+1]=='0')
			parameter->p=NULL;
		else {
			parameter->p=s_pop_a();
			--root_offset;
		}
		++parameter;
		++a_n;
	}

	while (b_n<b_size){
		if (bits[b_n+a_size+1]=='0')
			parameter->p=NULL;
		else
			parameter->p=s_pop_b();
		++parameter;
		++b_n;
	}

	graph_4=g_fill_3 (g_keep (graph_3,graph_1),graph_2,graph_5);
	
	s_put_a (root_offset,graph_4);
}

extern LABEL *cycle_in_spine_label,*reserve_label;

void code_fill3_r (char descriptor_name[],int a_size,int b_size,int root_offset,char bits[])
{
	INSTRUCTION_GRAPH graph_0,graph_1,graph_2,graph_3,graph_4,graph_5,graph_6;
	LABEL *descriptor_label;
	union instruction_parameter *parameter;
	int a_n,b_n;
	
	graph_0=s_pop_a();
	if (graph_0->instruction_code==GBEFORE0)
		graph_0->instruction_code=GBEFORE;
	--root_offset;
	
#if !(defined (sparc) || defined (G_POWER))
	if (!parallel_flag){
		if (cycle_in_spine_label==NULL){
			cycle_in_spine_label=enter_label ("__cycle__in__spine",IMPORT_LABEL | NODE_ENTRY_LABEL);
			cycle_in_spine_label->label_arity=0;
			cycle_in_spine_label->label_descriptor=EMPTY_label;
		}
		graph_6=g_lea (cycle_in_spine_label);
	} else {
		if (reserve_label==NULL){
			reserve_label=enter_label ("__reserve",IMPORT_LABEL | NODE_ENTRY_LABEL);
			reserve_label->label_arity=0;
			reserve_label->label_descriptor=EMPTY_label;
		}
		graph_6=g_lea (reserve_label);
	}
#else
	graph_6=g_g_register (RESERVE_CODE_REGISTER);
#endif
	graph_0=g_fill_2 (graph_0,graph_6);
		
	graph_1=s_get_a (root_offset);
	if (graph_1->instruction_code==GBEFORE0)
		graph_1->instruction_code=GBEFORE;

	descriptor_label=enter_label (descriptor_name,DATA_LABEL);

	if (!parallel_flag && descriptor_label->label_last_lea_block==last_block)
		graph_2=descriptor_label->label_last_lea;
	else {
		graph_2=g_load_des_i (descriptor_label,0);

		if (!parallel_flag ){
			descriptor_label->label_last_lea=graph_2;
			descriptor_label->label_last_lea_block=last_block;
		}
	}

	a_n=0;
	b_n=0;

	if (bits[0]=='0'){
		graph_5=g_load_id (STACK_ELEMENT_SIZE,graph_0);
		if (a_n<a_size)
			++a_n;
		else
			++b_n;
	} else {
		if (a_n<a_size){
			graph_5=s_pop_a();
			--root_offset;
			++a_n;
		} else {
			graph_5=s_pop_b();
			++b_n;
		}
	}
	
	graph_0=g_load_id (2*STACK_ELEMENT_SIZE,graph_0);

	graph_3=g_fill_m (graph_0,a_size+b_size-1);
	
	parameter=&graph_3->instruction_parameters[1];

	while (a_n<a_size){
		if (bits[a_n]=='0')
			parameter->p=NULL;
		else {
			parameter->p=s_pop_a();
			--root_offset;
		}
		++parameter;
		++a_n;
	}

	while (b_n<b_size){
		if (bits[b_n+a_size]=='0')
			parameter->p=NULL;
		else
			parameter->p=s_pop_b();
		++parameter;
		++b_n;
	}

	graph_4=g_fill_4 (graph_1,graph_2,graph_5,graph_3);
	
	s_put_a (root_offset,graph_4);
}

#define ARGUMENTS_OFFSET	STACK_ELEMENT_SIZE

void code_push_args_u (int a_offset,int arity,int n_arguments)
{
	INSTRUCTION_GRAPH graph_1,graph_2,graph_3,graph_5,*graph_p;
	
	graph_1=s_get_a (a_offset);

	graph_5=g_before0 (graph_1,n_arguments);
	graph_p=&graph_5->instruction_parameters[1+n_arguments].p;

	s_put_a (a_offset,graph_5);

	if (n_arguments>0){
		graph_2=g_load_id (ARGUMENTS_OFFSET-NODE_POINTER_OFFSET,graph_1);

		if (n_arguments!=1)
			if (n_arguments==2 && arity==2){
				graph_3=g_load_id (2*STACK_ELEMENT_SIZE-NODE_POINTER_OFFSET,graph_1);
				*--graph_p=graph_3;
				s_push_a (graph_3);
			} else {
				INSTRUCTION_GRAPH graph_4;
				
				graph_3=g_load_id (2*STACK_ELEMENT_SIZE-NODE_POINTER_OFFSET,graph_1);
				--n_arguments;
				
				if (n_arguments==1){
					graph_4=g_load_id (0-NODE_POINTER_OFFSET,graph_3);
					*--graph_p=graph_4;
					s_push_a (graph_4);
				} else {
#ifndef I486
					if (n_arguments>=8){
#endif
						while (n_arguments!=0){
							INSTRUCTION_GRAPH graph_5;
						
							--n_arguments;
		
							graph_5=g_load_id ((n_arguments<<STACK_ELEMENT_LOG_SIZE)-NODE_POINTER_OFFSET,graph_3);
							*--graph_p=graph_5;
							s_push_a (graph_5);
						}
#ifndef I486
					} else {
						graph_4=g_movem (0-NODE_POINTER_OFFSET,graph_3,n_arguments);
						while (n_arguments!=0){
							INSTRUCTION_GRAPH graph_5;
						
							--n_arguments;
		
							graph_5=g_movemi (n_arguments,graph_4);
							*--graph_p=graph_5;
							s_push_a (graph_5);
						}
					}
#endif
				}
			}
		
		*--graph_p=graph_2;
		s_push_a (graph_2);
	}
}

void code_push_r_args_u (int a_offset,int a_size,int b_size)
{
	INSTRUCTION_GRAPH graph_1,graph_2,graph_3,graph_5,graph_6,*graph_p;

	graph_1=s_get_a (a_offset);

	graph_6=g_before0 (graph_1,a_size+b_size);
	graph_p=&graph_6->instruction_parameters[1+a_size+b_size].p;

	s_put_a (a_offset,graph_6);

	switch (a_size+b_size){
		case 0:
			return;
		case 1:
			graph_2=g_load_id (ARGUMENTS_OFFSET,graph_1);
			*--graph_p=graph_2;
			if (a_size!=0)
				s_push_a (graph_2);
			else
				s_push_b (graph_2);
			return;
		case 2:
			graph_2=g_load_id (ARGUMENTS_OFFSET,graph_1);
			graph_3=g_load_id (2*STACK_ELEMENT_SIZE,graph_1);
			*--graph_p=graph_3;
			*--graph_p=graph_2;
			switch (b_size){
				case 0:
					s_push_a (graph_3);
					s_push_a (graph_2);
					break;
				case 1:
					s_push_a (graph_2);
					s_push_b (graph_3);
					break;
				default:
					s_push_b (graph_3);
					s_push_b (graph_2);		
			}			
			return;
		default:
			graph_2=g_load_id (ARGUMENTS_OFFSET,graph_1);
			graph_3=g_load_id (2*STACK_ELEMENT_SIZE,graph_1);

#ifdef M68000
			if (a_size+b_size-1>=8){
#endif
				b_size+=a_size;
	
				while (b_size>a_size && b_size>1){
					--b_size;			
					graph_5=g_load_id ((b_size-1)<<STACK_ELEMENT_LOG_SIZE,graph_3);
					*--graph_p=graph_5;
					s_push_b (graph_5);
				}
	
				while (a_size>1){
					--a_size;
					graph_5=g_load_id ((a_size-1)<<STACK_ELEMENT_LOG_SIZE,graph_3);
					*--graph_p=graph_5;
					s_push_a (graph_5);
				}				
#ifdef M68000
			} else {
				INSTRUCTION_GRAPH graph_4;
				
				graph_4=g_movem (0,graph_3,a_size+b_size-1);
	
				b_size+=a_size;
	
				while (b_size>a_size && b_size>1){
					--b_size;			
					graph_5=g_movemi (b_size-1,graph_4);
					*--graph_p=graph_5;
					s_push_b (graph_5);
				}
	
				while (a_size>1){
					--a_size;			
					graph_5=g_movemi (a_size-1,graph_4);
					*--graph_p=graph_5;
					s_push_a (graph_5);
				}
			}
#endif
			*--graph_p=graph_2;
			if (a_size>0)
				s_push_a (graph_2);
			else
				s_push_b (graph_2);
			return;
	}
}

void code_push_r_arg_u (int a_offset,int a_size,int b_size,int a_arg_offset,int a_arg_size,int b_arg_offset,int b_arg_size)
{
	INSTRUCTION_GRAPH graph_1,graph_2,graph_3,graph_5,graph_6,*graph_p;

	graph_1=s_get_a (a_offset);

	if (graph_1->instruction_code==GBEFORE0 && graph_1->inode_arity==a_size+b_size+1)
		graph_p=&graph_1->instruction_parameters[1].p;
	else {
		graph_6=g_before0 (graph_1,a_size+b_size);
		graph_p=&graph_6->instruction_parameters[1+a_size+b_size].p;

		s_put_a (a_offset,graph_6);

		switch (a_size+b_size){
			case 0:
				break;
			case 1:
				graph_2=g_load_id (ARGUMENTS_OFFSET,graph_1);
				*--graph_p=graph_2;
				break;
			case 2:
				graph_2=g_load_id (ARGUMENTS_OFFSET,graph_1);
				graph_3=g_load_id (2*STACK_ELEMENT_SIZE,graph_1);
				*--graph_p=graph_3;
				*--graph_p=graph_2;
				break;
			default:
			{
				int ab_size;
				
				graph_2=g_load_id (ARGUMENTS_OFFSET,graph_1);
				graph_3=g_load_id (2*STACK_ELEMENT_SIZE,graph_1);

				ab_size=a_size+b_size-1;
#ifdef M68000
				if (ab_size>=8){
#endif
					while (ab_size>0){
						--ab_size;
						graph_5=g_load_id (ab_size<<STACK_ELEMENT_LOG_SIZE,graph_3);
						*--graph_p=graph_5;
					}				
#ifdef M68000
				} else {
					INSTRUCTION_GRAPH graph_4;
					
					graph_4=g_movem (0,graph_3,ab_size);
		
					while (ab_size>1){
						--ab_size;			
						graph_5=g_movemi (ab_size,graph_4);
						*--graph_p=graph_5;
					}
				}
#endif
				*--graph_p=graph_2;
				break;
			}
		}
	}

	while (a_arg_size>0){
		--a_arg_size;
		s_push_a (graph_p[a_arg_offset-1+a_arg_size]);
	}
	
	while (b_arg_size>0){
		--b_arg_size;
		s_push_b (graph_p[a_size+b_arg_offset-1+b_arg_size]);
	}
}

/* convert string to integer */

#ifdef _WIN64
# define A64
#endif
#if defined (__GNUC__) && defined (__SIZEOF_POINTER__)
# if __SIZEOF_POINTER__==8
#  define A64
# endif
#endif

#ifdef _MSC_VER
# define U_LONG_LONG unsigned __int64
#else
# define U_LONG_LONG unsigned long long
#endif

#ifdef A64
# define IF_INT_64_OR_32(if64,if32) if64
# define N_bits_in_int 64
# define Max_bit_n_in_int 63
# define N_digits_in_part 27
# define N_digits_in_part_m1 26
# define I5PD 7450580596923828125
# define I2T5PD 14901161193847656250
# define I1E18 1000000000000000000
# define IM1E18 (-1000000000000000000)
#else
# define IF_INT_64_OR_32(if64,if32) if32
# define N_bits_in_int 32
# define Max_bit_n_in_int 31
# define N_digits_in_part 13
# define N_digits_in_part_m1 12
# define I5PD 1220703125
# define I2T5PD 2441406250
#endif
#define I1E9 1000000000

#ifdef A64
# ifdef __GNUC__
# define UW unsigned long long
# define W long long
# else
# define UW unsigned __int64
# define W __int64
# endif
#else
# define UW unsigned int
# define W int
#endif

#ifdef _WIN64
UW _umul128 (UW multiplier, UW multiplicand, UW* highproduct);
# pragma intrinsic (_umul128)
#endif

#ifdef A64
# ifdef __GNUC__
#  define umul_hl(h,l,a,b) \
	__asm__ ("mulq %3"		  \
			: "=a" ((UW)(l)), \
			  "=d" ((UW)(h))  \
			: "%0" ((UW)(a)), \
			  "rm" ((UW)(b)))
# else
#  define umul_hl(h,l,a,b) l=_umul128 (a,b,&h)
# endif
#endif

struct integer {
	W   s;
	UW *a;
};

static UW convertchars (int i,int end_i,char s[])
{
	UW n;
	
	n=0;
	while (i<end_i){
		n=n*10+(s[i]-48);
		i=i+1;
	}
	return n;
}

static UW convert9c (int i,char s[])
{
	UW n;

 	n=s[i]-48;
	n=n*10+(s[i+1]-48);
	n=n*10+(s[i+2]-48);
	n=n*10+(s[i+3]-48);
	n=n*10+(s[i+4]-48);
	n=n*10+(s[i+5]-48);
	n=n*10+(s[i+6]-48);
	n=n*10+(s[i+7]-48);
	n=n*10+(s[i+8]-48);

	return n;
}

#ifdef A64
UW
#else
static U_LONG_LONG
#endif
	convert10to13c (int n_chars,char s[])
{
 	int i;
 	UW nl,nh;
#ifndef A64
	U_LONG_LONG hl;
#endif

 	i = n_chars-9;
	nl = convert9c (i,s);
	nh = convertchars (0,i,s);
#ifdef A64
	return nh*I1E9+nl;
#else
	hl = ((U_LONG_LONG)nh)*((U_LONG_LONG)I1E9);

	return hl+nl;
#endif
}

#ifndef A64
static U_LONG_LONG convert13c_32 (int i,char s[])
{
	UW nl,nh;
	U_LONG_LONG hl;
	
	nl=convert9c (i+4,s);

	nh=s[i]-48;
	nh=nh*10+(s[i+1]-48);
	nh=nh*10+(s[i+2]-48);
	nh=nh*10+(s[i+3]-48);

	hl = ((U_LONG_LONG)nh)*((U_LONG_LONG)I1E9);
	return hl+nl;
}
#endif

#ifdef A64
static UW convert18c_64 (int i,char s[])
{
	UW t48,n;

	t48 = 0x3000000030;
	n=(((UW)s[i]<<32)+s[i+9])-t48;
	n=n*10+((((UW)s[i+1]<<32)+s[i+10])-t48);
	n=n*10+((((UW)s[i+2]<<32)+s[i+11])-t48);
	n=n*10+((((UW)s[i+3]<<32)+s[i+12])-t48);
	n=n*10+((((UW)s[i+4]<<32)+s[i+13])-t48);
	n=n*10+((((UW)s[i+5]<<32)+s[i+14])-t48);
	n=n*10+((((UW)s[i+6]<<32)+s[i+15])-t48);
	n=n*10+((((UW)s[i+7]<<32)+s[i+16])-t48);
	n=n*10+((((UW)s[i+8]<<32)+s[i+17])-t48);
	return (n>>32) * I1E9 + (n & 0xffffffff);
}

static UW convert19to27c_64 (int n_chars,char *s,UW *h_p)
{
	int i;
	UW nh,nl,h,l;

	i = n_chars-18;
	nl = convert18c_64 (i,s);
	nh = convertchars (0,i,s);

	umul_hl (h,l,nh,I1E18);
	l = l+nl;
	*h_p = h+(l<nl);
	return l;
}

static UW convert27c_64 (int i,char s[],UW *h_p)
{
	UW nh,nl,h,l;
	
	nl=convert18c_64 (i+9,s);
   	nh=convert9c (i,s);

	umul_hl (h,l,nh,I1E18);
	l = l+nl;
	*h_p = h+(l<nl);
	return l;
}
#endif

static int convert_first_chars (int n_chars_in_first_part,char s[],int i_a_f,UW a[])
{
	if (n_chars_in_first_part==0)
		return i_a_f;

	if (n_chars_in_first_part<IF_INT_64_OR_32 (19,10)){
		UW n;
		
		n = convertchars (0,n_chars_in_first_part,s);
		a[i_a_f]=n;
		return i_a_f+1;
	} else {
		UW h,l;
#ifdef A64
		l = convert19to27c_64 (n_chars_in_first_part,s,&h);
#else
		U_LONG_LONG hl;

		hl = convert10to13c (n_chars_in_first_part,s);
		h=(UW)(hl>>N_bits_in_int);
		l=(UW)hl;
#endif
		a[i_a_f]=l;
		if (h==0)
			return i_a_f+1;
		else {
			a[i_a_f+1]=h;
			return i_a_f+2;
		}
	}
}

static int mul_5pd_add (int i,int i_a,UW a[])
{
	UW n;
	
	n=0;

	while (i!=i_a){
		UW ai;
#ifdef A64
		UW h,l;
#else
		U_LONG_LONG hl;
#endif	
		ai=a[i];
#ifdef A64
		umul_hl (h,l,ai,I5PD);
		l=l+n;
		h=h+(l<n);
		a[i]=l;
		n=h;
#else
		hl=((U_LONG_LONG)ai)*((U_LONG_LONG)I5PD);
		hl=hl+n;
		a[i]=(unsigned int)hl;
		n=(unsigned int)(hl>>32);
#endif
		++i;
	}

	if (n!=0){
		a[i]=n;
		return i+1;
	} else
		return i;
}

static int addi (UW n,int i_a_f,int i_a_e,UW a[])
{
	UW s;
	
	if (i_a_f==i_a_e){
		a[i_a_f]=n;
		return i_a_f+1;
	}
	s=a[i_a_f]+n;
	a[i_a_f]=s;
	if (s<n){ /* carry */
		int i;
		
		i=i_a_f+1;
		while (i<i_a_e){
			UW ai;

			ai=a[i]+1;
			a[i]=ai;
			if (ai!=0)
				return i_a_e;
			i=i+1;
		}
		a[i]=1;
		return i_a_e+1;
	}
	return i_a_e;
}

static int shift_left (int i,UW n,int shift,int i_a,UW a[])
{
	while (i<i_a){
		UW ai,new_n;
		
		ai=a[i];
		new_n = ai>>(N_bits_in_int-shift);
		ai = (ai<<shift)+n;
		a[i]=ai;
		i=i+1;
		n = new_n;
	}

	if (n==0)
		return i_a;
	else
		a[i_a]=n;
		return i_a+1;
}

static void stoi_next_parts (int i_s,char s[],int size_s,int i_a_f,int i_a_e,int shift,UW r,UW a[],int size_a)
{
	while (i_s<size_s){
#ifdef A64
		UW h,l,yh,yl;
#else
		U_LONG_LONG hl,yhl;
#endif

#ifdef A64
		l = convert27c_64 (i_s,s,&h);
		umul_hl (yh,yl,r,I5PD);
#else
		hl = convert13c_32 (i_s,s);
		yhl = ((U_LONG_LONG)r)*((U_LONG_LONG)I5PD);
#endif
		if (shift<IF_INT_64_OR_32 (37,19)){
			UW x,new_r,n;
#ifdef A64
			UW rh,rl;
			
			x = l & 0x7ffffff;
			l = (l>>N_digits_in_part)+(h<<37);

			rl = yl+l;
			rh = yh+(rl<yl);
			new_r = x | ((rl & ((((UW)1)<<shift)-1))<<N_digits_in_part);
			n = (rl>>shift)+(rh<<(N_bits_in_int-shift));
#else
			UW l;
			U_LONG_LONG rhl;

			x = (UW)hl & 0x1fff;
			l = (UW)(hl>>N_digits_in_part);
			rhl = yhl+l;
			new_r = x | ((((UW)rhl) & ((((UW)1)<<shift)-1))<<N_digits_in_part);
			n = (UW)(rhl>>shift);
#endif

			i_a_e = mul_5pd_add (i_a_f,i_a_e,a);
			i_a_e = addi (n,i_a_f,i_a_e,a);
			shift += N_digits_in_part;
			r = new_r;
		} else if (shift==IF_INT_64_OR_32 (37,19)){
#ifdef A64
			yh =(yh<<N_digits_in_part) + (yl>>IF_INT_64_OR_32 (37,19));
			yl = yl<<N_digits_in_part;
			l=l+yl;
			h=h+yh+(l<yl);
#else
			yhl = yhl<<N_digits_in_part;
			hl = yhl + hl;
#endif
			i_a_e = mul_5pd_add (i_a_f,i_a_e,a);
			i_a_e = addi (IF_INT_64_OR_32 (h,(UW)(hl>>32)),i_a_f,i_a_e,a);

			if (i_a_f<=0)
				printf ("error in stoi_next_parts\n");

			i_a_f = i_a_f-1;
			a[i_a_f]=IF_INT_64_OR_32 (l,(UW)hl);

			shift = 0;
			r = 0;
		} else {
			UW new_r;
			int n,ys;

			n = shift-IF_INT_64_OR_32 (37,19);
			new_r = (IF_INT_64_OR_32 (l,(UW)hl)) & ((((UW)1)<<n)-1);
#ifdef A64
			l =(l>>n) + (h<<(N_bits_in_int-n));
			h = h>>n;
#else
			hl = hl>>n;
#endif
			ys = N_digits_in_part-n;
#ifdef A64
			yh =(yh<<ys) + (yl>>(N_bits_in_int-ys));
			yl = yl<<ys;
			l=l+yl;
			h=h+yh+(l<yl);
#else
			yhl = yhl << ys;
			hl = yhl+hl;
#endif
			i_a_e = mul_5pd_add (i_a_f,i_a_e,a);
			i_a_e = addi (IF_INT_64_OR_32 (h,(UW)(hl>>32)),i_a_f,i_a_e,a);

			if (i_a_f<=0)
				printf ("error in stoi_next_parts\n");
			i_a_f = i_a_f-1;
			a[i_a_f]=IF_INT_64_OR_32 (l,(UW)hl);

			shift = n;
			r = new_r;
		}
		i_s += N_digits_in_part;
	}

	if (i_s==size_s && i_a_f==0 && i_a_e<=size_a){
		if (shift!=0)
			i_a_e=shift_left (0,r,shift,i_a_e,a);
		return;
	} else
		printf ("error in stoi_next_parts\n");
}

static struct integer octal_string_to_integer (W sign,char *s,int size_s)
{
	int n_bits,n_zero_bits_in_msd;
	
	while (size_s>0 && s[0]=='0'){
		--size_s;
		++s;
	}

	if (size_s>0){
		int n;

		n=s[size_s-1] & 7;
		if (n<3)
			n_zero_bits_in_msd=3-n;
		else if (n==3)
			n_zero_bits_in_msd=1;
		else
			n_zero_bits_in_msd=0;

		n_bits = 3*size_s-n_zero_bits_in_msd;
	} else {
		n_bits=0;
		n_zero_bits_in_msd=0; /* not used */
	}

	if (n_bits<=IF_INT_64_OR_32(64,32)){
		struct integer i;
		UW l;
		
		l=0;
		while (size_s>0){
			char c;
			
			c=*s++;
			l<<=(UW)3;
			l+=(UW) (c & 7);
			--size_s;
		}

		if ((UW)l < (UW)(((UW)1<<(UW)Max_bit_n_in_int)-sign)){
			i.s=(l ^ sign)-sign;
			i.a=NULL;
		
			return i;
		} else {
			UW *a;

			a=calloc (2,sizeof (UW));
			if (a==NULL)
				error ("Out of memory\n");

			a[0]=1;
			a[1]=l;
			
			i.s=sign;
			i.a=a+1;

			return i;
		}		
	} else {
		int size_a,i,j,n_auw_bits;
		struct integer si;
		UW *a,auw;

		size_a = IF_INT_64_OR_32 ((n_bits+63)>>6,(n_bits+31)>>5);

		a = calloc (size_a+1,sizeof(UW));
		if (a==NULL)
			printf ("Out of memory\n");
		++a;

		auw=0;
		n_auw_bits=0;
		
		j=size_s;
		i=0;
		
		while (j>IF_INT_64_OR_32(21,10)){
			UW uw;
			int n_uw_bits;
			
			uw=0;
			n_uw_bits=0;
			do {
				--j;
				uw |= ((UW)(s[j] & 7)) << ((UW)n_uw_bits);
				
				n_uw_bits+=3;
			} while (n_uw_bits<IF_INT_64_OR_32(63,30));

			auw |= uw << (UW)n_auw_bits;
			n_auw_bits+=n_uw_bits;
			if (n_auw_bits>=IF_INT_64_OR_32(64,32)){
				a[i]=auw;
				++i;
				n_auw_bits-=IF_INT_64_OR_32(64,32);
				auw=uw >> (UW)(n_uw_bits-n_auw_bits);
			}
		}
		
		{
			UW uw,m;
			int n_uw_bits;
			
			uw=0;
			n_uw_bits=0;
			while (j>0){
				--j;
				uw |= ((UW)(s[j] & 7)) << ((UW)n_uw_bits);
				
				n_uw_bits+=3;
			};

			n_uw_bits-=n_zero_bits_in_msd;

			auw |= uw << (UW)n_auw_bits;
			n_auw_bits+=n_uw_bits;
			if (n_auw_bits>=IF_INT_64_OR_32(64,32)){
				a[i]=auw;
				++i;
				n_auw_bits-=IF_INT_64_OR_32(64,32);
				auw=uw >> (UW)(n_uw_bits-n_auw_bits);
			}
			
			if (n_auw_bits>0)
				a[i]=auw;
				++i;
		}

		si.a=a;
		si.s=sign;
		a[-1]=size_a;
			
		return si;
	}
}

static struct integer hex_string_to_integer (W sign,char *s,int size_s)
{
	while (size_s>0 && s[0]=='0'){
		--size_s;
		++s;
	}

	if (size_s<=IF_INT_64_OR_32(16,8)){
		struct integer i;
		UW l;
		
		l=0;
		while (size_s>0){
			char c;
			
			c=*s++;
			l<<=(UW)4;
			l+=(UW) (c<='9' ? c-'0' : (c | 0x20)-('a'-10));
			--size_s;
		}

		if ((UW)l < (UW)(((UW)1<<(UW)Max_bit_n_in_int)-sign)){
			i.s=(l ^ sign)-sign;
			i.a=NULL;
		
			return i;
		} else {
			UW *a;

			a=calloc (2,sizeof (UW));
			if (a==NULL)
				error ("Out of memory\n");

			a[0]=1;
			a[1]=l;
			
			i.s=sign;
			i.a=a+1;

			return i;
		}
	} else {
		int size_a,i,j;
		UW *a,uw;
		struct integer si;

		size_a = IF_INT_64_OR_32 ((size_s+15)>>4,(size_s+7)>>3);

		a = calloc (size_a+1,sizeof(UW));
		if (a==NULL)
			printf ("Out of memory\n");
		++a;

		i=size_a-1;

		uw=0;

		j=size_s & IF_INT_64_OR_32(15,7);
		if (j==0)
			j=IF_INT_64_OR_32(16,8);

		do {
			char c;
			
			c=*s++;
			uw<<=(UW)4;
			uw+=(UW) (c<='9' ? c-'0' : (c | 0x20)-('a'-10));
		} while (--j!=0);

		a[i]=uw;
		--i;

		while (i>=0){
			uw=0;
			
			for (j=IF_INT_64_OR_32(16,8); j!=0; --j){
				char c;
				
				c=*s++;
				uw<<=(UW)4;
				uw+=(UW) (c<='9' ? c-'0' : (c | 0x20)-('a'-10));				
			}
			
			a[i]=uw;
			--i;
		}

		si.a=a;
		si.s=sign;
		a[-1]=size_a;
			
		return si;
	}
}

static struct integer string_to_integer (W sign,char *s,int size_s)
{
	if (s[0]=='-'){
		sign=-1;
		--size_s;
		++s;
	}

	if (size_s>2 && s[0]=='0'){
		if ((s[1] | 0x20)=='x')
			return hex_string_to_integer (sign,s+2,size_s-2);
		else if ((s[1] | 0x20)=='o')
			return octal_string_to_integer (sign,s+2,size_s-2);
	}

	if (size_s<=N_digits_in_part){
		if (size_s<IF_INT_64_OR_32 (19,10)){
			struct integer i;

			i.s=(convertchars (0,size_s,s) ^ sign)-sign;
			i.a=NULL;
			
			return i;
		} else {
			UW h,l;

#ifdef A64
			l = convert19to27c_64 (size_s,s,&h);
#else
			U_LONG_LONG hl;

			hl = convert10to13c (size_s,s);
			h=(UW)(hl>>N_bits_in_int);
			l=(UW)hl;
#endif

			if (h==0){
				struct integer i;

				if ((UW)l < (UW)(((UW)1<<(UW)Max_bit_n_in_int)-sign)){
					i.s=(l ^ sign)-sign;
					i.a=NULL;
				
					return i;
				} else {
					UW *a;

					a=calloc (2,sizeof (UW));
					if (a==NULL)
						error ("Out of memory\n");

					a[0]=1;
					a[1]=l;
					
					i.s=sign;
					i.a=a+1;

					return i;
				}
			} else {
				struct integer i;
				UW *a;

				a=calloc (3,sizeof (UW));
				if (a==NULL)
					error ("Out of memory\n");
				
				a[0]=2;
				a[1]=l;
				a[2]=h;
				
				i.s=sign;
				i.a=a+1;

				return i;
			}
		}
	} else {
		int n_chars,n_parts,n_chars_in_parts,n_chars_in_first_part,n_shifts,size_a,i_a_f,i_a_e,i;
		UW *a;

		n_chars = size_s;
		n_parts = n_chars/N_digits_in_part;
		n_chars_in_parts = n_parts * N_digits_in_part;
		n_chars_in_first_part = n_chars-n_chars_in_parts;
		n_shifts = n_chars_in_parts>>IF_INT_64_OR_32(6,5);
		size_a = n_parts + 3 + n_shifts;

		a = calloc (size_a+1,sizeof(UW));
		if (a==NULL)
			printf ("Out of memory\n");
		++a;

		i_a_f = n_shifts;
		i_a_e = convert_first_chars (n_chars_in_first_part,s,i_a_f,a);

		stoi_next_parts (n_chars_in_first_part,s,size_s,i_a_f,i_a_e,0,0,a,size_a);

		i=size_a-1;
		while (i!=0 && a[i]==0)
			--i;

		if (i==0 && (UW)a[0] < (UW)(((UW)1<<(UW)Max_bit_n_in_int)-sign)){
			struct integer si;

			si.a=NULL;
			si.s=(a[0] ^ sign)-sign;
			
			free (a-1);
			
			return si;
		} else if (i+1==size_a){
			struct integer si;

			si.a=a;
			si.s=sign;
			a[-1]=i+1;
			
			return si;
		} else {
			struct integer si;

			a=1+(UW*)realloc (a-1,sizeof (UW)*(i+1+1));
			if (a==0)
				printf ("realloc failed\n");			

			a[-1]=i+1;

			si.a=a;
			si.s=sign;

			return si;
		}
	}
}

#define g_cmp_eq(g1,g2) g_instruction_2(GCMP_EQ,(g1),(g2))

void code_jmp_not_eqZ (char *integer_string,int integer_string_length,char label_name[])
{
	struct integer integer;
	INSTRUCTION_GRAPH graph_1,graph_2,graph_3,graph_4;

	integer=string_to_integer (0,integer_string,integer_string_length);

	if (integer.a==NULL){
		graph_1=s_get_b (0);
		graph_2=g_load_i (integer.s);
		graph_3=g_cmp_eq (graph_2,graph_1);
		s_push_b (graph_3);
		code_jmp_false (label_name);

		graph_1=s_get_a (0);
		graph_2=g_load_id (STACK_ELEMENT_SIZE,graph_1);
		graph_3=g_load_i (0);
		graph_4=g_cmp_eq (graph_3,graph_2);
		s_push_b (graph_4);
		code_jmp_false (label_name);
	} else {
		int i,integer_size;

		integer_size=integer.a[-1];
		
		graph_1=s_get_a (0);
		graph_2=g_load_id (STACK_ELEMENT_SIZE,graph_1);
		graph_3=g_load_i (integer_size);
		graph_4=g_cmp_eq (graph_3,graph_2);
		s_push_b (graph_4);
		code_jmp_false (label_name);	

		for (i=0; i<integer_size; ++i){
			graph_1=s_get_a (0);
			graph_2=g_load_id ((i+2)<<STACK_ELEMENT_LOG_SIZE,graph_1);
			graph_3=g_load_i (integer.a[i]);
			graph_4=g_cmp_eq (graph_3,graph_2);
			s_push_b (graph_4);
			code_jmp_false (label_name);	
		}

		graph_1=s_get_b (0);
		graph_2=g_load_i (integer.s);
		graph_3=g_cmp_eq (graph_2,graph_1);
		s_push_b (graph_3);
		code_jmp_false (label_name);		
	}
}

void code_pushZ (char *integer_string,int integer_string_length)
{
	struct integer integer;
	INSTRUCTION_GRAPH graph_1,graph_2;

	integer=string_to_integer (0,integer_string,integer_string_length);
	
	graph_1=g_load_i (integer.s);
	if (integer.a==NULL)
		graph_2=g_create_unboxed_int_array (0);
	else {
		int i,n_elements;

		n_elements=integer.a[-1];
		graph_2=g_create_unboxed_int_array (n_elements);
		for (i=0; i<n_elements; ++i)
			graph_2->instruction_parameters[3+i].p=g_load_i (integer.a[i]);
	}

	s_push_b (graph_1);
	s_push_a (graph_2);
}

static struct integer shift_right (struct integer n,unsigned int n_bits)
{
	UW *a;
	
	a=n.a;
	if (a==NULL)
		n.s = n.s>>n_bits;
	else {
		UW previous_e;
		int i,n_n_elements;

		n_n_elements=a[-1];

		previous_e=0;
		for (i=n_n_elements-1; i>=0; --i){
			UW e;

			e = a[i];
			a[i] = (e>>n_bits) + (previous_e<<(N_bits_in_int-n_bits));
			previous_e = e;
		}

		if (a[n_n_elements-1]==0){
			--n_n_elements;
			a[-1]=n_n_elements;
		}
		
		if (n_n_elements==1 && (W)a[0]>=0){
			n.s=a[0];
			n.a=NULL;
		}
	}

	return n;
}

static int divisible_by_5 (struct integer n)
{
	UW s;
	
	if (n.a==NULL)
		s=n.s;
	else {
		UW *a;
		int i,n_elements;
		
		a=n.a;
		n_elements=a[-1];

		s=0;
		for (i=0; ; ){
			int end_i;
			
			end_i=i+10000;
			if (end_i>n_elements)
				end_i=n_elements;
			
			while (i<end_i){
				UW e;
				
				e=a[i];
				s+=IF_INT_64_OR_32 ((e & 0xffffffffu)+(e>>32u),(e & 0xffffu)+(e>>16u));
				++i;
			}

			if (i>=n_elements)
				break;

			s = s % 5;
		}
	}
	
	return s % 5==0;
}

static struct integer exact_div_5 (struct integer n)
{
	if (n.a==NULL)
		n.s=n.s / 5;
	else {
		int i,n_elements;
		UW borrow,*a;
		
		a=n.a;
		n_elements=a[-1];
	
		borrow=0;
		for (i=0; i<n_elements; ++i){
			UW ai,e,ed5,h;
			
			ai=a[i];

			e=ai-borrow;
			borrow = e>ai;

			ed5=e * IF_INT_64_OR_32 (0xcccccccccccccccd,0xcccccccd);

			h = (ed5 + (ed5<<2u)) < ed5;
			borrow += h;
			borrow += ed5>>IF_INT_64_OR_32 (62u,30u);

			a[i]=ed5;
		}

		if (a[n_elements-1]==0){
			--n_elements;
			a[-1]=n_elements;
		}
		
		if (n_elements==1 && (W)a[0]>=0){
			n.s=a[0];
			n.a=NULL;
		}		
	}
	
	return n;
}

void code_pushZR (int sign,char *integer_string,int integer_string_length,int exponent)
{
	struct integer numerator,denominator;
	INSTRUCTION_GRAPH graph_1,graph_2,graph_3,graph_4;
	char *numerator_string;
	int denominator_string_length;

	while (integer_string[0]=='0' && integer_string_length>1){
		++integer_string;
		--integer_string_length;
	}

	while (exponent<0 && integer_string_length>1 && integer_string[integer_string_length-1]=='0'){
		--integer_string_length;
		++exponent;
	}

	if (integer_string_length==1 && integer_string[0]=='0')
		exponent=0;	
	
	if (exponent>0){
		int i,new_string_length;

		new_string_length=integer_string_length+exponent;
		numerator_string=memory_allocate (new_string_length+1);
		
		for (i=0; i<integer_string_length; ++i)
			numerator_string[i]=integer_string[i];
		for ( ; i<new_string_length; ++i)
			numerator_string[i]='0';
		numerator_string[i]='\0';
		
		integer_string=numerator_string;
		integer_string_length=new_string_length;
	} else
		numerator_string=NULL;

	numerator=string_to_integer (sign,integer_string,integer_string_length);

	if (numerator_string!=NULL){
		memory_free (numerator_string);
		numerator_string=NULL;
	}

	if (exponent<0){
		char *denominator_string;
		int i,exponent2,exponent5;

		denominator_string_length=1-exponent;
		denominator_string=memory_allocate (denominator_string_length+1);

		denominator_string[0]='1';
		for (i=1; i<denominator_string_length; ++i)
			denominator_string[i]='0';
		denominator_string[i]='\0';

		denominator=string_to_integer (0,denominator_string,denominator_string_length);

		memory_free (denominator_string);

		exponent2=-exponent;
		exponent5=exponent2;

		if (exponent2>=N_bits_in_int && numerator.a!=NULL){
			int n_n_elements,n_d_elements;
			UW *n_a,*d_a;

			n_a=numerator.a;
			n_n_elements=n_a[-1];

			d_a=denominator.a;
			n_d_elements=d_a[-1];

			while (exponent2>=N_bits_in_int && n_a[0]==0){
				--n_n_elements;
				++n_a;

				--n_d_elements;
				++d_a;
				
				exponent2-=N_bits_in_int;
			}

			if (n_n_elements==1 && (W)n_a[0]>=0){
				numerator.s=n_a[0];
				numerator.a=NULL;
			} else {
				numerator.a=n_a;
				n_a[-1]=n_n_elements;
			}

			/* >= 32 bits, because >= 5^32 */
			denominator.a=d_a;
			d_a[-1]=n_d_elements;
		}

		if (exponent2>0){
			UW n0;

			if (numerator.a==NULL)
				n0=numerator.s;
			else
				n0=numerator.a[0];

			if ((n0 & 1)==0){
				unsigned int n_0_bits,max_bits;

				n0=n0>>1;
				n_0_bits=1;
				while (n_0_bits<exponent2 && (n0 & 1)==0){
					n0=n0>>1;
					++n_0_bits;
				}
				
				exponent2-=n_0_bits;

				numerator = shift_right (numerator,n_0_bits);
				denominator = shift_right (denominator,n_0_bits);
			}
		}
		
		while (exponent5>0 && divisible_by_5 (numerator)){
			numerator = exact_div_5 (numerator);
			denominator = exact_div_5 (denominator);
			--exponent5;
		}
	} else {
		denominator.s=1;
		denominator.a=NULL;
	}

	graph_1=g_load_i (numerator.s);
	if (numerator.a==NULL)
		graph_2=g_create_unboxed_int_array (0);
	else {
		int i,n_elements;

		n_elements=numerator.a[-1];
		graph_2=g_create_unboxed_int_array (n_elements);
		for (i=0; i<n_elements; ++i)
			graph_2->instruction_parameters[3+i].p=g_load_i (numerator.a[i]);
	}

	graph_3=g_load_i (denominator.s);
	if (denominator.a==NULL)
		graph_4=g_create_unboxed_int_array (0);
	else {
		int i,n_elements;

		n_elements=denominator.a[-1];
		graph_4=g_create_unboxed_int_array (n_elements);
		for (i=0; i<n_elements; ++i)
			graph_4->instruction_parameters[3+i].p=g_load_i (denominator.a[i]);
	}

	s_push_b (graph_3);
	s_push_a (graph_4);
	s_push_b (graph_1);
	s_push_a (graph_2);
}

extern int profile_flag;
extern LABEL *profile_function_label;

void code_pd (void)
{
	profile_flag=PROFILE_DOUBLE;
}

void code_pe (void)
{
	profile_function_label=NULL;
}

void code_pl (void)
{
	profile_flag=PROFILE_CURRIED;
}

void code_pld (void)
{
	profile_flag=PROFILE_CURRIED_DOUBLE;
}

void code_pn (void)
{
	profile_flag=PROFILE_NOT;
}

void code_pt (void)
{
	profile_flag=PROFILE_TAIL;
}

static int in_out_stack_offset=0;

#ifdef G_POWER
#	define REGISTER_R3 (-21)
#endif

void code_in (char parameters[])
{
	/* [Rn] [On]+ [W|L|S|SDn|C([Dn|Sn]+)|An|Dn] */

#if defined (M68000) || defined (G_POWER)
	register char *p;
	register int first_parameter_offset;
	int n_data_parameter_registers;

	if (parallel_flag && system_sp_label==NULL)
		system_sp_label=enter_label ("system_sp",IMPORT_LABEL);

	end_basic_block_with_registers (offered_a_stack_size,offered_b_stack_size,offered_vector);	

	begin_new_basic_block();

	if (parallel_flag){
		n_data_parameter_registers=N_DATA_PARAMETER_REGISTERS-1;
		i_move_r_r (B_STACK_POINTER,REGISTER_A3);
		i_move_l_r (system_sp_label,B_STACK_POINTER);
	} else
		n_data_parameter_registers=N_DATA_PARAMETER_REGISTERS;

	if (offered_b_stack_size<=n_data_parameter_registers)
		in_out_stack_offset=0;
	else
		in_out_stack_offset=(offered_b_stack_size-n_data_parameter_registers)<<2;
	/* in_out_stack_offset only correct when there are no reals ! */

	first_parameter_offset=0;
	
	p=parameters;
	while (*p!=0){
		register int offset,stack;
		
		stack=*p++ & ~0x20;
		offset=*p++;

		if (*p=='R'){
			int n;
			
			++p;
			n=(unsigned char)*p++;
			n=(n<<8)+(unsigned char)*p++;
			
			if (n!=0){
				i_sub_i_r (n,B_STACK_POINTER);
				first_parameter_offset+=n;
			}
		}

		while (*p=='O'){
			int n;
#ifdef G_POWER
			int d_register;
#endif
			++p;
			n=*p++;
			n=(n<<8)+*p++;
#ifdef G_POWER
			d_register=*p++;
			i_lea_id_r (n,B_STACK_POINTER,REGISTER_R3+d_register);
#else
			if (n!=0){
				i_word_i (0x486F);
				i_word_i (n);
			} else
				i_word_i (0x2F0F);

			first_parameter_offset+=4;
#endif			
		}

		switch (*p){
			case 'W':
			{
				register int n_registers;
				
				if (stack=='A'){
					n_registers=offered_a_stack_size;
					if (n_registers>N_ADDRESS_PARAMETER_REGISTERS)
						n_registers=N_ADDRESS_PARAMETER_REGISTERS;
#ifdef G_POWER
					if (offset<n_registers)
						i_movew_r_idu (num_to_a_reg (n_registers-offset-1),-2,B_STACK_POINTER);
					else
						i_movew_id_idu ((offset-n_registers)<<2,A_STACK_POINTER,-2,B_STACK_POINTER);
#else					
					if (offset<n_registers)
						i_movew_r_pd (num_to_a_reg (n_registers-offset-1),REGISTER_A7);
					else
						i_movew_id_pd ((offset-n_registers)<<2,A_STACK_POINTER,REGISTER_A7);
#endif
				} else {
					n_registers=offered_b_stack_size;
					if (n_registers>n_data_parameter_registers)
						n_registers=n_data_parameter_registers;					
#ifdef G_POWER
					if (offset<n_registers)
						i_movew_r_idu (num_to_d_reg (n_registers-offset-1),-2,B_STACK_POINTER);
					else
						i_movew_id_idu
							(first_parameter_offset+((offset-n_registers)<<2)+2,B_STACK_POINTER,-2,B_STACK_POINTER);
#else
					if (offset<n_registers)
						i_movew_r_pd (num_to_d_reg (n_registers-offset-1),REGISTER_A7);
					else
						if (!parallel_flag)
							i_movew_id_pd
								(first_parameter_offset+((offset-n_registers)<<2)+2,B_STACK_POINTER,REGISTER_A7);
						else
							i_movew_id_pd (((offset-n_registers)<<2)+2,REGISTER_A3,REGISTER_A7);
#endif
				}
				++p;
				first_parameter_offset+=2;
				break;
			}
			case 'L':
			{
				register int n_registers;
				
				if (stack=='A'){
					n_registers=offered_a_stack_size;
					if (n_registers>N_ADDRESS_PARAMETER_REGISTERS)
						n_registers=N_ADDRESS_PARAMETER_REGISTERS;
#ifdef G_POWER
					if (offset<n_registers)
						i_move_r_idu (num_to_a_reg (n_registers-offset-1),-4,B_STACK_POINTER);
					else
						i_move_id_idu ((offset-n_registers)<<2,A_STACK_POINTER,-4,B_STACK_POINTER);
#else
					if (offset<n_registers)
						i_move_r_pd (num_to_a_reg (n_registers-offset-1),REGISTER_A7);
					else
						i_move_id_pd ((offset-n_registers)<<2,A_STACK_POINTER,REGISTER_A7);
#endif
				} else {
					n_registers=offered_b_stack_size;
					if (n_registers>n_data_parameter_registers)
						n_registers=n_data_parameter_registers;					
#ifdef G_POWER
					if (offset<n_registers)
						i_move_r_idu (num_to_d_reg (n_registers-offset-1),-4,B_STACK_POINTER);
					else
						i_move_id_idu
							(first_parameter_offset+((offset-n_registers)<<2),B_STACK_POINTER,-4,B_STACK_POINTER);
#else
					if (offset<n_registers)
						i_move_r_pd (num_to_d_reg (n_registers-offset-1),REGISTER_A7);
					else
						if (!parallel_flag)
							i_move_id_pd
								(first_parameter_offset+((offset-n_registers)<<2),B_STACK_POINTER,REGISTER_A7);
						else
							i_move_id_pd (((offset-n_registers)<<2),REGISTER_A3,REGISTER_A7);
#endif
				}
				++p;
				first_parameter_offset+=4;
				break;
			}
			case 'S':
				if (stack=='A'){
					int n_registers;
					
					n_registers=offered_a_stack_size;
					if (n_registers>N_ADDRESS_PARAMETER_REGISTERS)
						n_registers=N_ADDRESS_PARAMETER_REGISTERS;
					
					if (offset<n_registers){
						int areg;
						
						areg=num_to_a_reg (n_registers-offset-1);
						++p;
#ifdef G_POWER
						i_lea_id_r (7,areg,REGISTER_R3+ *p++);
#else						
						i_word_i (0x4868+n_registers-offset-1);
						i_word_i (7);

						first_parameter_offset+=4;
#endif
						break;
					}
				}
				error ("Error in string parameter for in instruction");
				break;
			case 'C':
				if (stack=='A'){
					int n_registers;
					
					n_registers=offered_a_stack_size;
					if (n_registers>N_ADDRESS_PARAMETER_REGISTERS)
						n_registers=N_ADDRESS_PARAMETER_REGISTERS;
					
					if (offset<n_registers){
						int areg;
						
						areg=num_to_a_reg (n_registers-offset-1);
						++p;
						while (*p=='D' || *p=='S'){
							if (*p=='D'){
								++p;
#ifdef G_POWER
								i_lea_id_r (8,areg,REGISTER_R3+ *p++);
#else						
								i_word_i (0x4868+n_registers-offset-1);
								i_word_i (8);
								first_parameter_offset+=4;
#endif
							} else {
								++p;
#ifdef G_POWER
								i_move_id_r (4,areg,REGISTER_R3+ *p++);
#else
								i_move_id_pd (4,areg,REGISTER_A7);
								first_parameter_offset+=4;
#endif							
							}
						}
						break;
					}
				}
				error ("Error in characters parameter for in instruction");
				break;
			case 'A':
			{
				int n_registers;
#ifdef M68000			
				n_registers=offered_a_stack_size;
				if (n_registers>N_ADDRESS_PARAMETER_REGISTERS)
					n_registers=N_ADDRESS_PARAMETER_REGISTERS;

				if (stack!='A' || n_registers-offset-1!=p[1])
					error ("Wrong address register for in instruction");
#else /* for G_POWER */
				n_registers=offered_b_stack_size;
				if (n_registers>n_data_parameter_registers)
					n_registers=n_data_parameter_registers;

				if (stack!='B' || p[1]>N_ADDRESS_PARAMETER_REGISTERS)
					error ("Wrong address register for in instruction");

				if (offset<n_registers)
					i_move_r_r (REGISTER_D0+(n_registers-offset-1),REGISTER_A0-p[1]);
				else					
					i_move_id_r
						(first_parameter_offset+((offset-n_registers)<<2),B_STACK_POINTER,REGISTER_A0-p[1]);
#endif

				p+=2;
				break;
			}
			case 'D':
			{
				int n_registers;
				
				n_registers=offered_b_stack_size;
				if (n_registers>n_data_parameter_registers)
					n_registers=n_data_parameter_registers;
#ifdef M68000			
				if (stack!='B' || n_registers-offset-1!=p[1])
					error ("Wrong data register for in instruction");
#else /* for G_POWER */
				if (stack!='B' || p[1]>8)
					error ("Wrong data register for in instruction");

				if (offset<n_registers)
					i_move_r_r (REGISTER_D0+(n_registers-offset-1),REGISTER_R3+p[1]);
				else
					i_move_id_r
						(first_parameter_offset+((offset-n_registers)<<2),B_STACK_POINTER,REGISTER_R3+p[1]);
#endif
				p+=2;
				break;
			}
			case 'U':
				++p;
				break;
			default:
				error ("Error in parameters for in instruction");
		}
	}
#else
	error ("ABC instruction 'in' not implemented");
#endif
}

static void out_parameter_error (void)
{
	error_i ("Error in parameters for out instruction at line %d",line_number);
}

void code_out (char parameters[])
{
	/* [Rn] [In] [W|L|Z|An|Dn] */
#if defined (M68000) || defined (G_POWER)
	register char *p;
	int deschedule_count;
	
	deschedule_count=-1;

	p=parameters;
	while (*p!=0){
		int offset,stack;
		
		stack=*p++;
		offset=*p++;

		if (*p=='R' && deschedule_count<0){
			int n;
			
			++p;
			n=(unsigned char)*p++;
			n=(n<<8)+(unsigned char)*p++;
			
			deschedule_count=n;
		}

		if (*p=='I'){
			int n;
			
			++p;
			n=(unsigned char)*p++;
			n=(n<<8)+(unsigned char)*p++;
				
			i_add_i_r (n,B_STACK_POINTER);
		}
		
		switch (*p){
			case 'W':
			{
				int n_registers;
				
				if (stack=='A'){
					n_registers=offered_a_stack_size;
					if (n_registers>N_ADDRESS_PARAMETER_REGISTERS)
						n_registers=N_ADDRESS_PARAMETER_REGISTERS;
					
					if (offset<n_registers){
#ifdef G_POWER
						i_movew_id_r (0,B_STACK_POINTER,num_to_a_reg (n_registers-offset-1));
						i_add_i_r (2,B_STACK_POINTER);
#else
						i_movew_pi_r (REGISTER_A7,num_to_a_reg (n_registers-offset-1));
#endif
					} else
						out_parameter_error();
						/* i_movew_pi_id (REGISTER_A7,2+((offset-n_registers)<<2),A_STACK_POINTER); */
				} else {
					n_registers=offered_b_stack_size;
					if (n_registers>N_DATA_PARAMETER_REGISTERS)
						n_registers=N_DATA_PARAMETER_REGISTERS;
					
					if (offset<n_registers){
						int d_register;

						d_register=num_to_d_reg (n_registers-offset-1);
#ifdef G_POWER
						i_movew_id_r (0,B_STACK_POINTER,d_register);
						i_add_i_r (2,B_STACK_POINTER);
#else
						i_movew_pi_r (REGISTER_A7,d_register);
						i_ext_r (d_register);
#endif
					} else
						out_parameter_error();
						/* i_movew_pi_id (REGISTER_A7,2-((1+offset-n_registers)<<2),B_STACK_POINTER); */
				}
				++p;
				break;
			}
			case 'L':
			{
				int n_registers;
				
				if (stack=='A'){
					n_registers=offered_a_stack_size;
					if (n_registers>N_ADDRESS_PARAMETER_REGISTERS)
						n_registers=N_ADDRESS_PARAMETER_REGISTERS;
					
					if (offset<n_registers){
#ifdef G_POWER
						i_move_id_r (0,B_STACK_POINTER,num_to_a_reg (n_registers-offset-1));
						i_add_i_r (4,B_STACK_POINTER);
#else
						i_move_pi_r (REGISTER_A7,num_to_a_reg (n_registers-offset-1));
#endif
					} else
						out_parameter_error();
						/* i_move_pi_id (REGISTER_A7,(offset-n_registers)<<2,A_STACK_POINTER); */
				} else {
					n_registers=offered_b_stack_size;
					if (n_registers>N_DATA_PARAMETER_REGISTERS)
						n_registers=N_DATA_PARAMETER_REGISTERS;
					
					if (offset<n_registers){
						int d_register;
					
						d_register=num_to_d_reg (n_registers-offset-1);
#ifdef G_POWER
						i_move_id_r (0,B_STACK_POINTER,d_register);
						i_add_i_r (4,B_STACK_POINTER);
#else
						i_move_pi_r (REGISTER_A7,d_register);
#endif
					} else
						out_parameter_error();
						/* i_move_pi_id (REGISTER_A7,-(1+offset-n_registers)<<2,B_STACK_POINTER); */
				}
				++p;
				break;
			}
			case 'D':
#ifdef G_POWER
			{
				int d_register,n_registers;
			
				++p;
				d_register=*p++;

				n_registers=offered_b_stack_size;
				if (n_registers>N_DATA_PARAMETER_REGISTERS)
					n_registers=N_DATA_PARAMETER_REGISTERS;

				if (d_register>8 || offset>=n_registers)
					out_parameter_error();
					
				i_move_r_r (REGISTER_R3+d_register,num_to_d_reg (n_registers-offset-1));
			}
#else
				p+=2;
#endif
				break;
			case 'A':
				p+=2;
				break;
			case 'Z':
			{
				int n_registers;
				
				if (stack=='A'){
					n_registers=offered_a_stack_size;
					if (n_registers>N_ADDRESS_PARAMETER_REGISTERS)
						n_registers=N_ADDRESS_PARAMETER_REGISTERS;
					
					if (offset<n_registers)
						i_move_i_r (0,num_to_a_reg (n_registers-offset-1));
					else
						out_parameter_error();
				} else {
					n_registers=offered_b_stack_size;
					if (n_registers>N_DATA_PARAMETER_REGISTERS)
						n_registers=N_DATA_PARAMETER_REGISTERS;
					
					if (offset<n_registers)
						i_move_i_r (0,num_to_d_reg (n_registers-offset-1));
					else
						out_parameter_error();
				}
				++p;
				break;
			}
			case 'B':
			{
				int n_registers,result_d_register;
#ifdef G_POWER
				int d_register;
#endif
				++p;

				n_registers=offered_b_stack_size;
				if (n_registers>N_DATA_PARAMETER_REGISTERS)
					n_registers=N_DATA_PARAMETER_REGISTERS;
#ifdef G_POWER
				d_register=*p++;

				if (d_register>8 || offset>=n_registers)
					out_parameter_error();
				
				result_d_register=num_to_d_reg (n_registers-offset-1);
				i_move_r_r (REGISTER_R3+d_register,result_d_register);
				i_and_i_r (1,result_d_register);
				/* neg rn,rn: */
				i_word_i (0x7C0000D0|((24+result_d_register)<<21)|((24+result_d_register)<<16));
				break;
#else
				if (offset<n_registers){
					result_d_register=num_to_d_reg (n_registers-offset-1);
					i_move_i_r (1,result_d_register);
					i_word_i (0xC01F | (result_d_register<<9));	/* and.b (sp)+,dn */
					i_word_i (0x4480 | result_d_register);		/* neg.l dn */
				} else
					out_parameter_error();
				break;
#endif
			}
			default:
				out_parameter_error();
		}
	}
	
	if (parallel_flag){
		if (in_out_stack_offset!=0)
			i_add_i_r (in_out_stack_offset,REGISTER_A3);
		i_move_r_r (REGISTER_A3,B_STACK_POINTER);

		if (deschedule_count>0){
			i_sub_i_r (deschedule_count,REGISTER_D6);
			i_word_i (0x6404);
			i_schedule_i (offered_a_stack_size<<4);
		}
	} else
		if (in_out_stack_offset!=0)
			i_add_i_r (in_out_stack_offset,B_STACK_POINTER);

	if (last_block->block_instructions!=NULL)
		begin_new_basic_block();
	else {
		release_a_stack();
		release_b_stack();
	}
	
	init_a_stack (offered_a_stack_size);	
	init_b_stack (offered_b_stack_size,offered_vector);
#else
	error ("ABC instruction 'out' not implemented");
#endif
}

#ifdef ALIGN_C_CALLS
# define REGISTER_O0 (-13)
#endif

#if defined (M68000) || defined (G_POWER)
void code_call (char *s1,int length,char *s2)
{
	LABEL *label;

# if defined (G_POWER) && defined (MACH_O)
	if (s2[0]=='.'){
		char label_name [202];

		label_name[0]='_';
		strcpy (&label_name[1],s2+1);
		
		label=enter_label (label_name,0);
		
		if (dyld_stub_binding_helper_p_label==NULL)
			dyld_stub_binding_helper_p_label=enter_label ("dyld_stub_binding_helper",IMPORT_LABEL);
	} else
#endif
	label=enter_label (s2,0);

#ifdef M68000
	i_jsr_l (label,0);
#else
	if (length>0 && s1[0]=='G'){
		if (saved_heap_p_label==NULL)
			saved_heap_p_label=enter_label ("saved_heap_p",IMPORT_LABEL);
		if (saved_a_stack_p_label==NULL)
			saved_a_stack_p_label=enter_label ("saved_a_stack_p",IMPORT_LABEL);

		i_lea_l_i_r (saved_a_stack_p_label,0,REGISTER_A3);
		i_move_r_id (A_STACK_POINTER,0,REGISTER_A3);
		i_lea_l_i_r (saved_heap_p_label,0,REGISTER_A3);
		i_move_r_id (HEAP_POINTER,0,REGISTER_A3);
		i_move_r_id (REGISTER_D7,4,REGISTER_A3);

# ifdef ALIGN_C_CALLS
		i_move_r_r (B_STACK_POINTER,REGISTER_O0);
		i_or_i_r (28,B_STACK_POINTER);
# endif
		i_call_l (label,64);

		i_lea_l_i_r (saved_a_stack_p_label,0,REGISTER_A3);
		i_move_id_r (0,REGISTER_A3,A_STACK_POINTER);
		i_lea_l_i_r (saved_heap_p_label,0,REGISTER_A3);
		i_move_id_r (0,REGISTER_A3,HEAP_POINTER);
		i_move_id_r (4,REGISTER_A3,REGISTER_D7);
	} else {
# ifdef ALIGN_C_CALLS
		i_move_r_r (B_STACK_POINTER,REGISTER_O0);
		i_or_i_r (28,B_STACK_POINTER);
# endif
		i_call_l (label,64);
	}
#endif
}
#endif

static char ccall_error_string[] = "Error in ccall of '%s'";

#if defined (sparc) || defined (G_POWER)
#	ifdef sparc
#		define N_C_PARAMETER_REGISTERS 6
#		define C_PARAMETER_REGISTER_0 8
#		define FIRST_C_STACK_PARAMETER_WORD_OFFSET 17
#		define SP_REGISTER 14
#	else
#		define N_C_PARAMETER_REGISTERS 8
#		define C_PARAMETER_REGISTER_0 (-21)
#    ifdef LINUX_ELF
#		define FIRST_C_STACK_PARAMETER_WORD_OFFSET (2-8-32)
#    else
#	  ifdef ALIGN_C_CALLS
#		define FIRST_C_STACK_PARAMETER_WORD_OFFSET (6-32-7)
#	  else
#		define FIRST_C_STACK_PARAMETER_WORD_OFFSET (6-32)
#	  endif
#    endif
#	 define SP_REGISTER B_STACK_POINTER
#	endif
#endif

#ifdef G_AI64
# define REGISTER_RBP (-5)
#endif

#ifdef ALIGN_C_CALLS
# define B_STACK_REGISTER REGISTER_O0
#else
# define B_STACK_REGISTER B_STACK_POINTER
#endif

#ifdef G_AI64
static void remove_at_sign_size_from_function_name (char c_function_name[])
{
	int l;
	
	l=strlen (c_function_name)-1;
	if (l>=0 && isdigit (c_function_name[l])){
		do
			--l;
		while (l>=0 && isdigit (c_function_name[l]));
		if (l>0 && c_function_name[l]=='@')
			c_function_name[l]='\0';
	}
}
#endif

static void push_extra_clean_b_register_parameters (int n_extra_clean_b_register_parameters)
{
	int n,offset;
	
	offset=-STACK_ELEMENT_SIZE;
	for (n=0; n<n_extra_clean_b_register_parameters-1; ++n){
#ifdef i486
		i_move_r_pd (REGISTER_D0+n,B_STACK_POINTER);
#else
		i_move_r_id (REGISTER_D0+n,offset,B_STACK_POINTER);
#endif
		offset-=STACK_ELEMENT_SIZE;
	}

#ifdef G_POWER
	i_move_r_idu (REGISTER_D0+n,offset,B_STACK_POINTER);
#elif defined (sparc)
	i_move_r_id (REGISTER_D0+n,offset,B_STACK_POINTER);
	i_sub_i_r (-offset,B_STACK_POINTER);
#else
	i_move_r_pd (REGISTER_D0+n,B_STACK_POINTER);
#endif
}

#if (defined (sparc) && !defined (SOLARIS)) || (defined (I486) && !defined (LINUX_ELF) && !defined (G_AI64)) || (defined (G_POWER) && !defined (LINUX_ELF)) || defined (MACH_O) || defined (MACH_O64)
static LABEL *enter_c_function_name_label (char *c_function_name)
{
	char label_name [202];

# if defined (G_POWER) && !defined (MACH_O)
	label_name[0]='.';
# else
	label_name[0]='_';
# endif
	strcpy (&label_name[1],c_function_name);

	return enter_label (label_name,0);
}
#else
# define enter_c_function_name_label(c_function_name) enter_label (c_function_name,0)
#endif

#if defined (G_POWER) || defined (sparc)
static void ccall_load_b_offset (int b_o,int c_parameter_n)
{
	if (c_parameter_n<N_C_PARAMETER_REGISTERS)
		i_lea_id_r (b_o,B_STACK_REGISTER,C_PARAMETER_REGISTER_0+c_parameter_n);
	else {
		i_lea_id_r (b_o,B_STACK_REGISTER,REGISTER_A3);
		i_move_r_id (REGISTER_A3,(FIRST_C_STACK_PARAMETER_WORD_OFFSET+c_parameter_n)<<2,SP_REGISTER);
	}
}

static void ccall_load_string_or_array_offset (int offset,int c_parameter_n,int a_o)
{
	i_move_id_r (a_o,A_STACK_POINTER,REGISTER_A0);
	if (c_parameter_n<N_C_PARAMETER_REGISTERS)
		i_lea_id_r (offset,REGISTER_A0,C_PARAMETER_REGISTER_0+c_parameter_n);
	else {
		i_lea_id_r (offset,REGISTER_A0,REGISTER_A3);
		i_move_r_id (REGISTER_A3,(FIRST_C_STACK_PARAMETER_WORD_OFFSET+c_parameter_n)<<2,SP_REGISTER);
	}
}
#endif

#if defined (THREAD64) && (defined (LINUX_ELF) || defined (MACH_O64))
LABEL *pthread_getspecific_label=NULL;
#endif

#ifdef THREAD32
# define SAVED_A_STACK_P_OFFSET 12
# define STRING_tlsp_tls_index "tlsp_tls_index"
#else
# ifdef THREAD64
#  define SAVED_HEAP_P_OFFSET 24
#  define SAVED_R15_OFFSET 32
#  define SAVED_A_STACK_P_OFFSET 40
#  ifdef MACH_O64
#   define STRING_tlsp_tls_index "_tlsp_tls_index"
#   define STRING_pthread_getspecific "_pthread_getspecific"
#  else
#   define STRING_tlsp_tls_index "tlsp_tls_index"
#   define STRING_pthread_getspecific "pthread_getspecific"
#  endif
# endif
#endif

void code_ccall (char *c_function_name,char *s,int length)
{
	LABEL *label;
	int l,min_index;
	int a_offset,b_offset,a_result_offset,b_result_offset;
	int result,a_o,b_o,float_parameters;
	int n_clean_b_register_parameters,clean_b_register_parameter_n;
	int n_extra_clean_b_register_parameters;
	int first_pointer_result_index,callee_pops_arguments,save_state_in_global_variables;
	int function_address_parameter;
	int n_a_c_in_clean_out_parameters_size,n_b_c_in_clean_out_parameters_size;

#if defined (sparc) || defined (G_POWER)
		int	c_parameter_n;
# ifdef G_POWER
		int c_offset;
# endif
#elif defined (I486)
		int c_offset;		
#else
		error ("ABC instruction 'ccall' not implemented");
#endif
#if defined (G_POWER) || (defined (G_A64) && (defined (LINUX_ELF) || defined (MACH_O64)))
		int c_fp_parameter_n;
		
		c_fp_parameter_n=0;
#endif

	function_address_parameter=0;

	if (*s=='G'){
		++s;
		--length;
		save_state_in_global_variables=1;
#if (defined (I486) && !defined (THREAD64)) || defined (G_POWER)
		if (saved_heap_p_label==NULL)
			saved_heap_p_label=enter_label ("saved_heap_p",IMPORT_LABEL);
		if (saved_a_stack_p_label==NULL)
			saved_a_stack_p_label=enter_label ("saved_a_stack_p",IMPORT_LABEL);
#endif
	} else	
		save_state_in_global_variables=0;

	if (*s=='P'){
		++s;
		--length;
		callee_pops_arguments=1;

#ifdef G_AI64
		remove_at_sign_size_from_function_name (c_function_name);
#endif
	} else
		callee_pops_arguments=0;

#if defined (sparc) || defined (I486) || defined (G_POWER)
	float_parameters=0;
			
	a_offset=0;
	b_offset=0;
	n_clean_b_register_parameters=0;
	n_a_c_in_clean_out_parameters_size=0;
	n_b_c_in_clean_out_parameters_size=0;

	for (l=0; l<length; ++l){
		switch (s[l]){
			case '-':
			case ':':
				min_index=l;
				break;
			case 'I':
			case 'p':
				b_offset+=STACK_ELEMENT_SIZE;
				if (!float_parameters)
					++n_clean_b_register_parameters;
#if defined (I486) && !defined (G_AI64)
				if (s[l+1]=='>'){
					++l;
					n_b_c_in_clean_out_parameters_size+=STACK_ELEMENT_SIZE;
				}
#endif
				continue;
# if defined (I486) || defined (G_POWER)
			case 'r':
# endif
			case 'R':
				float_parameters=1;
				b_offset+=8;
# if defined (G_A64) && (defined (LINUX_ELF) || defined (MACH_O64))
				++c_fp_parameter_n;
# endif
				continue;
			case 'S':
			case 's':
			case 'A':
				a_offset+=STACK_ELEMENT_SIZE;
#if defined (I486) && !defined (G_AI64)
				if (s[l+1]=='>'){
					++l;
					n_a_c_in_clean_out_parameters_size+=STACK_ELEMENT_SIZE;
				}
#endif
				continue;
			case 'O':
			case 'F':
				if (function_address_parameter)
					error_s (ccall_error_string,c_function_name);
				function_address_parameter=s[l];
				
				while (l+1<length && (s[l+1]=='*' || s[l+1]=='[')){
					++l;
					if (s[l]=='['){
						++l;
						while (l<length && (unsigned)(s[l]-'0')<(unsigned)10)
							++l;
						if (!(l<length && s[l]==']'))
							error_s (ccall_error_string,c_function_name);
					}
				}
				b_offset+=STACK_ELEMENT_SIZE;
				if (!float_parameters)
					++n_clean_b_register_parameters;
				continue;
			default:
				error_s (ccall_error_string,c_function_name);
		}
		break;
	}
	if (l>=length)
		error_s (ccall_error_string,c_function_name);
	
	a_result_offset=0;
	b_result_offset=0;

	n_extra_clean_b_register_parameters=0;

	for (++l; l<length; ++l){
		switch (s[l]){
			case 'I':
			case 'p':
				b_result_offset+=STACK_ELEMENT_SIZE;
				continue;
			case 'R':
				float_parameters=1;
				b_result_offset+=8;
				continue;
			case 'S':
				a_result_offset+=STACK_ELEMENT_SIZE;
				continue;
			case 'A':
				++l;
				if (l<length && (s[l]=='i' || s[l]=='r')){
					a_result_offset+=STACK_ELEMENT_SIZE;
					continue;
				} else {
					error_s (ccall_error_string,c_function_name);
					break;
				}
			case ':':
				if (l==min_index+1 || l==length-1)
					error_s (ccall_error_string,c_function_name);
				else {
					int new_length;
					
					new_length=l;
					
					for (++l; l<length; ++l){
						switch (s[l]){
							case 'I':
							case 'p':
								if (!float_parameters)
									++n_extra_clean_b_register_parameters;
								break;
							case 'R':
								float_parameters=1;
								break;
							case 'S':
							case 'A':
								continue;
							default:
								error_s (ccall_error_string,c_function_name);
						}
					}
					
					length=new_length;
				}
				break;
			case 'V':
				if ((l==min_index+1 && l!=length-1) || n_a_c_in_clean_out_parameters_size+n_b_c_in_clean_out_parameters_size!=0)
					continue;
			default:
				error_s (ccall_error_string,c_function_name);
		}
	}

	if (n_clean_b_register_parameters>N_DATA_PARAMETER_REGISTERS){
		n_clean_b_register_parameters=N_DATA_PARAMETER_REGISTERS;
		n_extra_clean_b_register_parameters=0;
	} else if (n_clean_b_register_parameters+n_extra_clean_b_register_parameters>N_DATA_PARAMETER_REGISTERS)
		n_extra_clean_b_register_parameters=N_DATA_PARAMETER_REGISTERS-n_clean_b_register_parameters;

	end_basic_block_with_registers (0,n_clean_b_register_parameters+n_extra_clean_b_register_parameters,e_vector);

	b_offset-=n_clean_b_register_parameters<<STACK_ELEMENT_LOG_SIZE;

	if (n_extra_clean_b_register_parameters!=0)
		push_extra_clean_b_register_parameters (n_extra_clean_b_register_parameters);

# ifndef sparc
	c_offset=b_offset;
# endif

	if (s[min_index]=='-' && length-1!=min_index+1){
		result='V';
		first_pointer_result_index=min_index+1;
	} else {
		result=s[min_index+1];
		first_pointer_result_index=min_index+2;

		switch (result){
			case 'I':
			case 'p':
				b_result_offset-=STACK_ELEMENT_SIZE;
				break;
			case 'R':
				b_result_offset-=8;
				break;
			case 'S':
				a_result_offset-=STACK_ELEMENT_SIZE;
				break;
			case 'A':
				a_result_offset-=STACK_ELEMENT_SIZE;
				++first_pointer_result_index;
		}
	}
#endif

	if (!function_address_parameter){
		label = enter_c_function_name_label (c_function_name);

#if defined (G_POWER) && defined (MACH_O)
		if (dyld_stub_binding_helper_p_label==NULL)
			dyld_stub_binding_helper_p_label=enter_label ("dyld_stub_binding_helper",IMPORT_LABEL);
#endif
	}

#if defined (G_POWER) || defined (sparc)
	{
		int b_a_offset;

# ifdef G_POWER
		if (a_result_offset+b_result_offset>b_offset){
			i_sub_i_r (a_result_offset+b_result_offset-b_offset,B_STACK_POINTER);
			c_offset=a_result_offset+b_result_offset;
		}
		b_o=c_offset-b_result_offset;
# else
		b_o=b_offset-b_result_offset;
# endif
		b_a_offset=b_o;

# ifdef ALIGN_C_CALLS
		i_move_r_r (B_STACK_POINTER,REGISTER_O0);
		i_or_i_r (28,B_STACK_POINTER);
# endif

		c_parameter_n=(b_offset+a_offset>>2)+n_clean_b_register_parameters-(function_address_parameter=='F');
		
		for (l=first_pointer_result_index; l<length; ++l){
			switch (s[l]){
				case 'I':
				case 'p':
					ccall_load_b_offset (b_o,c_parameter_n);
					++c_parameter_n;
					b_o+=STACK_ELEMENT_SIZE;
					break;
				case 'R':
					ccall_load_b_offset (b_o,c_parameter_n);
					++c_parameter_n;
					b_o+=8;
					break;
				case 'S':
					b_a_offset-=STACK_ELEMENT_SIZE;
					ccall_load_b_offset (b_a_offset,c_parameter_n);
					++c_parameter_n;
					break;
				case 'V':
					break;
				default:
					error_s (ccall_error_string,c_function_name);
			}
		}
	}

	a_o=0;
# ifdef G_POWER
	b_o=c_offset-b_offset;
# else
	b_o=0;
# endif
	c_parameter_n=0;
# ifdef G_POWER
	c_fp_parameter_n=0;
# endif

	{
	int function_address_reg;
	
	clean_b_register_parameter_n=0;
	for (l=0; l<min_index; ++l){
		switch (s[l]){
			case 'I':
			case 'p':
				if (clean_b_register_parameter_n < n_clean_b_register_parameters){
					int clean_b_reg_n;
					
					clean_b_reg_n=REGISTER_D0+n_extra_clean_b_register_parameters+n_clean_b_register_parameters-1-clean_b_register_parameter_n;
					if (c_parameter_n<N_C_PARAMETER_REGISTERS)
						i_move_r_r (clean_b_reg_n,C_PARAMETER_REGISTER_0+c_parameter_n);
					else
						i_move_r_id (clean_b_reg_n,(FIRST_C_STACK_PARAMETER_WORD_OFFSET+c_parameter_n)<<2,SP_REGISTER);
					++c_parameter_n;
					++clean_b_register_parameter_n;
				} else {
					if (c_parameter_n<N_C_PARAMETER_REGISTERS)
						i_move_id_r (b_o,B_STACK_REGISTER,C_PARAMETER_REGISTER_0+c_parameter_n++);
					else {
						i_move_id_r (b_o,B_STACK_REGISTER,REGISTER_A3);
						i_move_r_id (REGISTER_A3,(FIRST_C_STACK_PARAMETER_WORD_OFFSET+c_parameter_n++)<<2,SP_REGISTER);
					}
					b_o+=STACK_ELEMENT_SIZE;
				}					
				break;
# ifdef G_POWER
			case 'r':
				if (c_fp_parameter_n<13){
					++c_parameter_n;
					i_fmove_id_fr (b_o,B_STACK_REGISTER,1+c_fp_parameter_n-14);
					i_word_i (0xFC000018 | ((1+c_fp_parameter_n) << 21) | ((1+c_fp_parameter_n) << 11)); // frsp frp,frp
				} else
					error_s ("Passing single precision argument in fp position > 13 not implemented (in '%s')",c_function_name);
				++c_fp_parameter_n;
				b_o+=8;
				break;
# endif
			case 'R':
# ifdef G_POWER
#  ifdef LINUX_ELF
				if (c_fp_parameter_n<8){
#  else
				if (c_fp_parameter_n<13){
					c_parameter_n+=2;
#  endif
					i_fmove_id_fr (b_o,B_STACK_REGISTER,1+c_fp_parameter_n-14);
				} else {
#  ifdef LINUX_ELF
					error_s ("Passing more than 8 fp registers not implemented (in '%s')",c_function_name);
#  else
					i_move_id_r (b_o,B_STACK_REGISTER,REGISTER_A3);
					i_move_r_id (REGISTER_A3,(FIRST_C_STACK_PARAMETER_WORD_OFFSET+c_parameter_n++)<<2,SP_REGISTER);
					i_move_id_r (b_o+4,B_STACK_REGISTER,REGISTER_A3);
					i_move_r_id (REGISTER_A3,(FIRST_C_STACK_PARAMETER_WORD_OFFSET+c_parameter_n++)<<2,SP_REGISTER);
#  endif
				}
				++c_fp_parameter_n;
# else
				if (c_parameter_n<N_C_PARAMETER_REGISTERS)
					i_move_id_r (b_o,B_STACK_REGISTER,C_PARAMETER_REGISTER_0+c_parameter_n++);
				else {
					i_move_id_r (b_o,B_STACK_REGISTER,REGISTER_A3);
					i_move_r_id (REGISTER_A3,(FIRST_C_STACK_PARAMETER_WORD_OFFSET+c_parameter_n++)<<2,SP_REGISTER);
				}
				if (c_parameter_n<N_C_PARAMETER_REGISTERS)
					i_move_id_r (b_o+4,B_STACK_REGISTER,C_PARAMETER_REGISTER_0+c_parameter_n++);
				else {
					i_move_id_r (b_o+4,B_STACK_REGISTER,REGISTER_A3);
					i_move_r_id (REGISTER_A3,(FIRST_C_STACK_PARAMETER_WORD_OFFSET+c_parameter_n++)<<2,SP_REGISTER);
				}
# endif
				b_o+=8;
				break;
			case 'S':
				a_o-=STACK_ELEMENT_SIZE;
				ccall_load_string_or_array_offset (4,c_parameter_n,a_o);
				++c_parameter_n;
				break;
			case 's':
				a_o-=STACK_ELEMENT_SIZE;
				ccall_load_string_or_array_offset (8,c_parameter_n,a_o);
				++c_parameter_n;
				break;
			case 'A':
				a_o-=STACK_ELEMENT_SIZE;
				ccall_load_string_or_array_offset (12,c_parameter_n,a_o);
				++c_parameter_n;
				break;
			case 'F':
			case 'O':
				if (clean_b_register_parameter_n < n_clean_b_register_parameters){
					int clean_b_reg_n;
					
					clean_b_reg_n=REGISTER_D0+n_extra_clean_b_register_parameters+n_clean_b_register_parameters-1-clean_b_register_parameter_n;

					if (function_address_parameter=='O'){
						if (c_parameter_n<N_C_PARAMETER_REGISTERS)
							i_move_r_r (clean_b_reg_n,C_PARAMETER_REGISTER_0+c_parameter_n);
						else
							i_move_r_id (clean_b_reg_n,(FIRST_C_STACK_PARAMETER_WORD_OFFSET+c_parameter_n)<<2,SP_REGISTER);
						++c_parameter_n;
					}

					function_address_reg=clean_b_reg_n;

					while (l+1<length && (s[l+1]=='*' || s[l+1]=='[')){
						int n;
						
						++l;
						n=0;
						
						if (s[l]=='['){
							++l;
							while (l<length && (unsigned)(s[l]-'0')<(unsigned)10){
								n=n*10+(s[l]-'0');
								++l;
							}
						}
						
						i_move_id_r (n,clean_b_reg_n,clean_b_reg_n);
					}


					++clean_b_register_parameter_n;
					break;
				}
			default:
				error_s (ccall_error_string,c_function_name);
		}
	}
# ifdef G_POWER
	if (save_state_in_global_variables){
		i_lea_l_i_r (saved_a_stack_p_label,0,REGISTER_A3);
		i_move_r_id (A_STACK_POINTER,0,REGISTER_A3);
		i_lea_l_i_r (saved_heap_p_label,0,REGISTER_A3);
		i_move_r_id (HEAP_POINTER,0,REGISTER_A3);
		i_move_r_id (REGISTER_D7,4,REGISTER_A3);
	}

	if (!function_address_parameter)
		i_call_l (label,128);
	else
		i_call_r (function_address_reg,128);

	if (save_state_in_global_variables){
		i_lea_l_i_r (saved_a_stack_p_label,0,REGISTER_A3);
		i_move_id_r (0,REGISTER_A3,A_STACK_POINTER);
		i_lea_l_i_r (saved_heap_p_label,0,REGISTER_A3);
		i_move_id_r (0,REGISTER_A3,HEAP_POINTER);
		i_move_id_r (4,REGISTER_A3,REGISTER_D7);
	}

	begin_new_basic_block(); /* MTLR/MFLR optimization only finds IJSR at end of basic block */
# else
	if (!function_address_parameter)
		i_call_l (label);
	else
		i_call_r (function_address_reg);
# endif
	}

	if (a_offset!=0)
		i_add_i_r (-a_offset,A_STACK_POINTER);
# ifdef G_POWER
	if (c_offset-(b_result_offset+a_result_offset)!=0)
		i_add_i_r (c_offset-(b_result_offset+a_result_offset),B_STACK_POINTER);
# else
	if (b_offset-(b_result_offset+a_result_offset)!=0)
		i_add_i_r (b_offset-(b_result_offset+a_result_offset),B_STACK_POINTER);
# endif

	for (l=first_pointer_result_index; l<length; ++l){
		switch (s[l]){
			case 'I':
			case 'p':
			case 'R':
				break;
			case 'S':
				if (string_to_string_node_label==NULL)
					string_to_string_node_label=enter_label ("string_to_string_node",IMPORT_LABEL);

				i_move_id_r (0,B_STACK_POINTER,REGISTER_A0);
				i_jsr_l_id (string_to_string_node_label,0);
				i_move_r_id (REGISTER_A0,0,A_STACK_POINTER);
				i_add_i_r (STACK_ELEMENT_SIZE,A_STACK_POINTER);
				break;
			case 'V':
				break;
			default:
				error_s (ccall_error_string,c_function_name);
		}
	}
	
	switch (result){
		case 'I':
		case 'p':
			i_move_r_r (C_PARAMETER_REGISTER_0,REGISTER_D0);
			begin_new_basic_block();
			init_b_stack (1,i_vector);
			break;
		case 'R':
# ifdef G_POWER
			i_fmove_fr_fr (1-14,0);
# endif
			begin_new_basic_block();
			init_b_stack (2,r_vector);
			break;
		case 'S':
			if (string_to_string_node_label==NULL)
				string_to_string_node_label=enter_label ("string_to_string_node",IMPORT_LABEL);

			i_move_r_r (C_PARAMETER_REGISTER_0,REGISTER_A0);
			i_sub_i_r (STACK_ELEMENT_SIZE,B_STACK_POINTER);
			i_jsr_l_id (string_to_string_node_label,0);

			begin_new_basic_block();
			init_a_stack (1);
			break;
		case 'V':
			begin_new_basic_block();
			break;
		default:
			error_s (ccall_error_string,c_function_name);
	}

#elif defined (I486)

# ifndef G_AI64 /* for I486 && ! G_AI64 */
	{
		int c_offset_before_pushing_arguments,function_address_reg;
		int b_out_and_ab_result_size;

		b_out_and_ab_result_size = n_b_c_in_clean_out_parameters_size+a_result_offset+b_result_offset;

		a_o = -b_out_and_ab_result_size;
		b_o = -n_b_c_in_clean_out_parameters_size;

		if (b_out_and_ab_result_size>b_offset){
			i_sub_i_r (b_out_and_ab_result_size-b_offset,B_STACK_POINTER);
			c_offset=b_out_and_ab_result_size;
		}
		
		c_offset_before_pushing_arguments=c_offset;

		for (l=length-1; l>=first_pointer_result_index; --l){
			switch (s[l]){
				case 'I':
				case 'p':
					b_o-=STACK_ELEMENT_SIZE;
					i_lea_id_r (b_o+c_offset,B_STACK_POINTER,REGISTER_A0);
					i_move_r_pd (REGISTER_A0,B_STACK_POINTER);
					c_offset+=STACK_ELEMENT_SIZE;
					break;
				case 'R':
					b_o-=8;
					i_lea_id_r (b_o+c_offset,B_STACK_POINTER,REGISTER_A0);
					i_move_r_pd (REGISTER_A0,B_STACK_POINTER);
					c_offset+=STACK_ELEMENT_SIZE;
					break;
				case 'i':
				case 'r':
					--l;
				case 'S':
					i_lea_id_r (a_o+c_offset,B_STACK_POINTER,REGISTER_A0);
					i_move_r_pd (REGISTER_A0,B_STACK_POINTER);
					a_o+=STACK_ELEMENT_SIZE;
					c_offset+=STACK_ELEMENT_SIZE;
					break;
				case 'V':
					break;
				default:
					error_s (ccall_error_string,c_function_name);
			}
		}

		{
			int last_register_parameter_index,reg_n,a_out_offset,b_out_offset;
			
			last_register_parameter_index=-1;
			
			reg_n=0;
			l=0;
			while (reg_n<n_clean_b_register_parameters && l<min_index){
				if (s[l]=='I' || s[l]=='p' || s[l]=='F' || s[l]=='O'){
					++reg_n;
					last_register_parameter_index=l;
				}
				++l;
			}
			
			reg_n=0;
			a_o=-a_offset;
			b_o=0;
			a_out_offset=a_o;
			b_out_offset=0;

			for (l=min_index-1; l>=0; --l){
				switch (s[l]){
					case 'I':
					case 'p':
						if (l<=last_register_parameter_index){
							i_move_r_pd (REGISTER_D0+n_extra_clean_b_register_parameters+reg_n,B_STACK_POINTER);
							++reg_n;
						} else {
							b_o-=STACK_ELEMENT_SIZE;
							i_move_id_pd (b_o+c_offset,B_STACK_POINTER,B_STACK_POINTER);
						}
						c_offset+=STACK_ELEMENT_SIZE;
						break;
					case 'r':
					{
						int offset;
						
						b_o-=8;

						i_lea_id_r (-4,B_STACK_POINTER,B_STACK_POINTER);

						offset=b_o+c_offset+4;

						i_word_i (0xDD);	//	fldl <b_o+c_offset+4>(%esp)
						if ((signed char)offset==offset){
							i_word_i (0x44);
							i_word_i (0x24);
							i_word_i (offset);
						} else {
							i_word_i (0x84);
							i_word_i (0x24);
							i_word_i (offset);
							i_word_i (offset>>8);						
							i_word_i (offset>>16);
							i_word_i (offset>>24);
						}

						i_word_i (0xD9);	//	fstps (%esp)
						i_word_i (0x1C);
						i_word_i (0x24);

						c_offset+=4;
						break;
					}
					case 'R':
						b_o-=8;
						i_move_id_pd (b_o+c_offset+4,B_STACK_POINTER,B_STACK_POINTER);
						i_move_id_pd (b_o+(c_offset+4),B_STACK_POINTER,B_STACK_POINTER);
						c_offset+=8;
						break;
					case 'S':
						i_move_id_r (a_o,A_STACK_POINTER,REGISTER_A0);
						i_add_i_r (STACK_ELEMENT_SIZE,REGISTER_A0);
						i_move_r_pd (REGISTER_A0,B_STACK_POINTER);
						a_o+=STACK_ELEMENT_SIZE;
						c_offset+=STACK_ELEMENT_SIZE;
						break;
					case 's':
						i_move_id_r (a_o,A_STACK_POINTER,REGISTER_A0);
						i_add_i_r (8,REGISTER_A0);
						i_move_r_pd (REGISTER_A0,B_STACK_POINTER);
						a_o+=STACK_ELEMENT_SIZE;
						c_offset+=STACK_ELEMENT_SIZE;
						break;
					case 'A':
						i_move_id_r (a_o,A_STACK_POINTER,REGISTER_A0);
						i_add_i_r (12,REGISTER_A0);
						i_move_r_pd (REGISTER_A0,B_STACK_POINTER);
						a_o+=STACK_ELEMENT_SIZE;
						c_offset+=STACK_ELEMENT_SIZE;
						break;
					case 'F':
					case 'O':
					case '*':
					case ']':
						/* while (l>=0 && !(s[l]=='F' || s[l]=='O')) bug in watcom c */
						while (l>=0 && (s[l]!='F' && s[l]!='O'))
							--l;
						
						if (l<=last_register_parameter_index){
							int clean_b_reg_n,i;
							
							clean_b_reg_n=REGISTER_D0+n_extra_clean_b_register_parameters+reg_n;

							if (function_address_parameter=='O'){
								i_move_r_pd (clean_b_reg_n,B_STACK_POINTER);
								c_offset+=STACK_ELEMENT_SIZE;
							}
							
							++reg_n;

							function_address_reg=clean_b_reg_n;
							i=l;
							while (i+1<length && (s[i+1]=='*' || s[i+1]=='[')){
								int n;
								
								++i;
								n=0;
								
								if (s[i]=='['){
									++i;
									while (i<length && (unsigned)(s[i]-'0')<(unsigned)10){
										n=n*10+(s[i]-'0');
										++i;
									}
								}
								
								i_move_id_r (n,clean_b_reg_n,clean_b_reg_n);
							}
							break;
						}
					case '>':
					{
						char c;

						--l;
						c = s[l];
						if (c=='I' || c=='p'){
							int parameter_reg_n;
							
							if (l<=last_register_parameter_index){
								parameter_reg_n=REGISTER_D0+n_extra_clean_b_register_parameters+reg_n;
								i_move_r_pd (parameter_reg_n,B_STACK_POINTER);
								++reg_n;
							} else {
								parameter_reg_n=REGISTER_A0;
								b_o-=STACK_ELEMENT_SIZE;
								i_move_id_r (b_o+c_offset,B_STACK_POINTER,parameter_reg_n);
								i_move_r_pd (parameter_reg_n,B_STACK_POINTER);
							}
							c_offset+=STACK_ELEMENT_SIZE;
							b_out_offset-=STACK_ELEMENT_SIZE;
							i_move_r_id (parameter_reg_n,b_out_offset+c_offset,B_STACK_POINTER);
						} else {
							int string_or_array_offset;
							
							switch (c){
								case 'S':
									string_or_array_offset=STACK_ELEMENT_SIZE;
									break;
								case 's':
									string_or_array_offset=8;
									break;
								case 'A':
									string_or_array_offset=12;
									break;
								default:
									error_s (ccall_error_string,c_function_name);
							}

							i_move_id_r (a_o,A_STACK_POINTER,REGISTER_A0);
							if (a_o!=a_out_offset)
								i_move_r_id (REGISTER_A0,a_out_offset,A_STACK_POINTER);
							i_add_i_r (string_or_array_offset,REGISTER_A0);
							i_move_r_pd (REGISTER_A0,B_STACK_POINTER);
							a_o+=STACK_ELEMENT_SIZE;
							c_offset+=STACK_ELEMENT_SIZE;
							a_out_offset+=STACK_ELEMENT_SIZE;
						}
						break;
					}
					default:
						error_s (ccall_error_string,c_function_name);
				}
			}
		}
		
		if (float_parameters){
			int freg_n;

			for (freg_n=0; freg_n<8; ++freg_n){
	 			i_word_i (0xdd);
				i_word_i (0xc0+freg_n); /* ffree */
			}
		}

		if (save_state_in_global_variables){
#  ifndef THREAD32
			i_move_r_l (-4/*ESI*/,saved_a_stack_p_label);
			i_move_r_l (-5/*EDI*/,saved_heap_p_label);
#  else
			i_move_r_id (A_STACK_POINTER,SAVED_A_STACK_P_OFFSET,-5/*EDI*/);
#  endif
		}

		if (!function_address_parameter)
			i_jsr_l (label,0);
		else
			i_jsr_r (function_address_reg);

		if (save_state_in_global_variables){
#  ifndef THREAD32
			i_move_l_r (saved_a_stack_p_label,-4/*ESI*/);
			i_move_l_r (saved_heap_p_label,-5/*EDI*/);
#  else
			i_move_id_r (SAVED_A_STACK_P_OFFSET,-5/*EDI*/,A_STACK_POINTER);
#  endif
		}

		if (callee_pops_arguments)
			c_offset=c_offset_before_pushing_arguments;
		
		if (a_offset-n_a_c_in_clean_out_parameters_size!=0)
			i_sub_i_r (a_offset-n_a_c_in_clean_out_parameters_size,A_STACK_POINTER);
		if (c_offset-b_out_and_ab_result_size!=0)
			i_add_i_r (c_offset-b_out_and_ab_result_size,B_STACK_POINTER);

		}
		
		for (l=length-1; l>=first_pointer_result_index; --l){
			switch (s[l]){
				case 'I':
				case 'p':
				case 'R':
					break;
				case 'S':
					if (string_to_string_node_label==NULL)
						string_to_string_node_label=enter_label ("string_to_string_node",IMPORT_LABEL);
					i_move_pi_r (B_STACK_POINTER,REGISTER_A0);
					i_jsr_l (string_to_string_node_label,0);
					i_move_r_id (REGISTER_A0,0,A_STACK_POINTER);
					i_add_i_r (STACK_ELEMENT_SIZE,A_STACK_POINTER);
					break;
				case 'i':
					--l;
					if (int_array_to_node_label==NULL)
						int_array_to_node_label=enter_label ("int_array_to_node",IMPORT_LABEL);
					i_move_pi_r (B_STACK_POINTER,REGISTER_A0);
					i_jsr_l (int_array_to_node_label,0);
					i_move_r_id (REGISTER_A0,0,A_STACK_POINTER);
					i_add_i_r (STACK_ELEMENT_SIZE,A_STACK_POINTER);
					break;
				case 'r':
					--l;
					if (real_array_to_node_label==NULL)
						real_array_to_node_label=enter_label ("real_array_to_node",IMPORT_LABEL);
					i_move_pi_r (B_STACK_POINTER,REGISTER_A0);
					i_jsr_l (real_array_to_node_label,0);
					i_move_r_id (REGISTER_A0,0,A_STACK_POINTER);
					i_add_i_r (STACK_ELEMENT_SIZE,A_STACK_POINTER);
					break;
				case 'V':
					break;
				default:
					error_s (ccall_error_string,c_function_name);
			}
		}
			
		switch (result){
			case 'I':
			case 'p':
				begin_new_basic_block();
				init_b_stack (1,i_vector);
				break;
			case 'R':
				begin_new_basic_block();
				init_b_stack (2,r_vector);
				break;
			case 'S':
				if (string_to_string_node_label==NULL)
					string_to_string_node_label=enter_label ("string_to_string_node",IMPORT_LABEL);

				i_move_r_r (REGISTER_D0,REGISTER_A0);
				i_jsr_l (string_to_string_node_label,0);

				begin_new_basic_block();
				init_a_stack (1);
				break;
			case 'A':
				i_move_r_r (REGISTER_D0,REGISTER_A0);
				if (s[min_index+2]=='i'){
					if (int_array_to_node_label==NULL)
						int_array_to_node_label=enter_label ("int_array_to_node",IMPORT_LABEL);
					i_jsr_l (int_array_to_node_label,0);
				} else if (s[min_index+2]=='r'){
					if (real_array_to_node_label==NULL)
						real_array_to_node_label=enter_label ("real_array_to_node",IMPORT_LABEL);
					i_jsr_l (real_array_to_node_label,0);
				}
				begin_new_basic_block();
				init_a_stack (1);
				break;
			case 'V':
				begin_new_basic_block();
				break;
			default:
				error_s (ccall_error_string,c_function_name);
		}
# else /* for I486 && G_AI64 */
		a_o=-b_result_offset-a_result_offset;
		b_o=0;

		if (a_result_offset+b_result_offset>b_offset){
			i_sub_i_r (a_result_offset+b_result_offset-b_offset,B_STACK_POINTER);
			c_offset=a_result_offset+b_result_offset;
		}

#  ifdef THREAD64
	if (save_state_in_global_variables){
		if (tlsp_tls_index_label==NULL)
			tlsp_tls_index_label=enter_label (STRING_tlsp_tls_index,IMPORT_LABEL);

		i_move_r_id (A_STACK_POINTER,SAVED_A_STACK_P_OFFSET,-4/*R9*/);
		i_move_r_id (-7/*RDI*/,SAVED_HEAP_P_OFFSET,-4/*R9*/);
		i_move_r_id (REGISTER_D7,SAVED_R15_OFFSET,-4/*R9*/);
	}
#  endif

#  if defined (LINUX_ELF) || defined (MACH_O64) /* for I486 && G_AI64 && (LINUX_ELF || MACH_O64) */
		{
		int c_offset_before_pushing_arguments,function_address_reg,c_parameter_n,n_c_parameters,n_c_fp_register_parameters;
		int a_stack_pointer,heap_pointer;
		unsigned int used_clean_b_parameter_registers;
		static int c_parameter_registers[6] = { HEAP_POINTER, A_STACK_POINTER, REGISTER_A1, REGISTER_A0, REGISTER_A2, REGISTER_A3 };

		c_offset_before_pushing_arguments=c_offset;

		n_c_parameters=((a_offset+b_offset+a_result_offset+b_result_offset)>>3)+n_clean_b_register_parameters;
		used_clean_b_parameter_registers = ((1<<n_clean_b_register_parameters)-1)<<n_extra_clean_b_register_parameters;
		c_parameter_n=n_c_parameters;
		n_c_fp_register_parameters = c_fp_parameter_n<=8 ? c_fp_parameter_n : 8;

		i_move_r_r (B_STACK_POINTER,REGISTER_RBP);
#   ifdef THREAD64
		if (!save_state_in_global_variables){
			if ((c_parameter_n-n_c_fp_register_parameters)>6 && ((c_parameter_n-n_c_fp_register_parameters) & 1)!=0){
				i_sub_i_r (16+8,B_STACK_POINTER);
				i_move_r_id (-4/*R9*/,8,B_STACK_POINTER);
				i_or_i_r (8,B_STACK_POINTER);		
			} else {
				i_sub_i_r (16,B_STACK_POINTER);
				i_move_r_id (-4/*R9*/,0,B_STACK_POINTER);
				i_and_i_r (-16,B_STACK_POINTER);		
			}
		} else
#   endif
		if ((c_parameter_n-n_c_fp_register_parameters)>6 && ((c_parameter_n-n_c_fp_register_parameters) & 1)!=0){
			i_sub_i_r (8,B_STACK_POINTER);
			i_or_i_r (8,B_STACK_POINTER);		
		} else {
			i_and_i_r (-16,B_STACK_POINTER);		
		}

		a_stack_pointer=A_STACK_POINTER;
		heap_pointer=HEAP_POINTER;

		for (l=length-1; l>=first_pointer_result_index; --l){
			char sl;
			
			sl=s[l];
			if (sl!='V'){
				int c_int_parameter_n;
				
				--c_parameter_n;
				c_int_parameter_n = c_parameter_n - n_c_fp_register_parameters;
				if (c_int_parameter_n<6){
					int c_parameter_reg;					
					
					c_parameter_reg=c_parameter_registers[c_int_parameter_n];
					if (c_int_parameter_n<2){
						if (c_int_parameter_n==0){
							if ((used_clean_b_parameter_registers & (1<<6))==0){
								heap_pointer=REGISTER_D6;
								used_clean_b_parameter_registers |= 1<<6;
							} else if ((used_clean_b_parameter_registers & (1<<5))==0){
								heap_pointer=REGISTER_D5;
								used_clean_b_parameter_registers |= 1<<5;
							} else
								error_s (ccall_error_string,c_function_name);								
							i_move_r_r (HEAP_POINTER,heap_pointer);
						} else {
							if ((used_clean_b_parameter_registers & (1<<5))==0){
								a_stack_pointer=REGISTER_D5;
								used_clean_b_parameter_registers |= 1<<5;
							} else if ((used_clean_b_parameter_registers & (1<<6))==0){
								a_stack_pointer=REGISTER_D6;
								used_clean_b_parameter_registers |= 1<<6;
							} else
								error_s (ccall_error_string,c_function_name);								
							i_move_r_r (A_STACK_POINTER,a_stack_pointer);
						}
					}
					switch (sl){
						case 'I':
						case 'p':
							b_o-=STACK_ELEMENT_SIZE;
							i_lea_id_r (b_o+c_offset_before_pushing_arguments,REGISTER_RBP,c_parameter_reg);
							break;
						case 'R':
							b_o-=8;
							i_lea_id_r (b_o+c_offset_before_pushing_arguments,REGISTER_RBP,c_parameter_reg);
							break;
						case 'S':
							i_lea_id_r (a_o+c_offset_before_pushing_arguments,REGISTER_RBP,c_parameter_reg);
							a_o+=STACK_ELEMENT_SIZE;
							break;
						default:
							error_s (ccall_error_string,c_function_name);
					}					
				} else {
					switch (sl){
						case 'I':
						case 'p':
							b_o-=STACK_ELEMENT_SIZE;
							i_lea_id_r (b_o+c_offset_before_pushing_arguments,REGISTER_RBP,REGISTER_A0);
							i_move_r_pd (REGISTER_A0,B_STACK_POINTER);
							c_offset+=STACK_ELEMENT_SIZE;
							break;
						case 'R':
							b_o-=8;
							i_lea_id_r (b_o+c_offset_before_pushing_arguments,REGISTER_RBP,REGISTER_A0);
							i_move_r_pd (REGISTER_A0,B_STACK_POINTER);
							c_offset+=STACK_ELEMENT_SIZE;
							break;
						case 'S':
							i_lea_id_r (a_o+c_offset_before_pushing_arguments,REGISTER_RBP,REGISTER_A0);
							i_move_r_pd (REGISTER_A0,B_STACK_POINTER);
							c_offset+=STACK_ELEMENT_SIZE;
							a_o+=STACK_ELEMENT_SIZE;
							break;
						default:
							error_s (ccall_error_string,c_function_name);
					}
				}
			}
		}
		
		{
			int last_register_parameter_index,reg_n;
			
			last_register_parameter_index=-1;
			
			reg_n=0;
			l=0;
			while (reg_n<n_clean_b_register_parameters && l<min_index){
				if (s[l]=='I' || s[l]=='p' || s[l]=='F' || s[l]=='O'){
					++reg_n;
					last_register_parameter_index=l;
				}
				++l;
			}
			
			reg_n=0;
			a_o=-a_offset;
			b_o=0;
			for (l=min_index-1; l>=0; --l){
				char sl;
				
				sl=s[l];
				switch (sl){
					case 'I':
					case 'p':
					{
						int c_int_parameter_n;
				
						--c_parameter_n;
						c_int_parameter_n = c_parameter_n - n_c_fp_register_parameters;
						if (c_int_parameter_n<6){
							int c_parameter_reg;					
					
							c_parameter_reg=c_parameter_registers[c_int_parameter_n];
							if (l<=last_register_parameter_index){
								if (c_int_parameter_n<2){
									if (c_int_parameter_n==0){
										if (n_extra_clean_b_register_parameters+reg_n==6){
											i_exg_r_r (HEAP_POINTER,REGISTER_D6);
											heap_pointer=REGISTER_D6;
											++reg_n;
											break;
										} else if (n_extra_clean_b_register_parameters+reg_n==5){
											i_exg_r_r (HEAP_POINTER,REGISTER_D5);
											heap_pointer=REGISTER_D5;
											++reg_n;
											break;											
										} else if ((used_clean_b_parameter_registers & (1<<6))==0){
											heap_pointer=REGISTER_D6;
											used_clean_b_parameter_registers |= 1<<6;
										} else if ((used_clean_b_parameter_registers & (1<<5))==0){
											heap_pointer=REGISTER_D5;
											used_clean_b_parameter_registers |= 1<<5;
										} else
											error_s (ccall_error_string,c_function_name);								
										i_move_r_r (HEAP_POINTER,heap_pointer);
									} else {
										if (n_extra_clean_b_register_parameters+reg_n==6){
											i_exg_r_r (A_STACK_POINTER,REGISTER_D6);
											a_stack_pointer=REGISTER_D6;
											++reg_n;
											break;
										} else if (n_extra_clean_b_register_parameters+reg_n==5){
											i_exg_r_r (A_STACK_POINTER,REGISTER_D5);
											a_stack_pointer=REGISTER_D5;
											++reg_n;
											break;											
										} else if ((used_clean_b_parameter_registers & (1<<5))==0){
											a_stack_pointer=REGISTER_D5;
											used_clean_b_parameter_registers |= 1<<5;
										} else if ((used_clean_b_parameter_registers & (1<<6))==0){
											a_stack_pointer=REGISTER_D6;
											used_clean_b_parameter_registers |= 1<<6;
										} else
											error_s (ccall_error_string,c_function_name);								
										i_move_r_r (A_STACK_POINTER,a_stack_pointer);
									}
								}
								i_move_r_r (REGISTER_D0+n_extra_clean_b_register_parameters+reg_n,c_parameter_reg);
								used_clean_b_parameter_registers &= ~ (1<<(n_extra_clean_b_register_parameters+reg_n));
								++reg_n;
							} else {
								if (c_int_parameter_n<2){
									if (c_int_parameter_n==0){
										if ((used_clean_b_parameter_registers & (1<<6))==0){
											heap_pointer=REGISTER_D6;
											used_clean_b_parameter_registers |= 1<<6;
										} else if ((used_clean_b_parameter_registers & (1<<5))==0){
											heap_pointer=REGISTER_D5;
											used_clean_b_parameter_registers |= 1<<5;
										} else
											error_s (ccall_error_string,c_function_name);								
										i_move_r_r (HEAP_POINTER,heap_pointer);
									} else {
										if ((used_clean_b_parameter_registers & (1<<5))==0){
											a_stack_pointer=REGISTER_D5;
											used_clean_b_parameter_registers |= 1<<5;
										} else if ((used_clean_b_parameter_registers & (1<<6))==0){
											a_stack_pointer=REGISTER_D6;
											used_clean_b_parameter_registers |= 1<<6;
										} else
											error_s (ccall_error_string,c_function_name);								
										i_move_r_r (A_STACK_POINTER,a_stack_pointer);
									}
								}
								b_o-=STACK_ELEMENT_SIZE;
								i_move_id_r (b_o+c_offset_before_pushing_arguments,REGISTER_RBP,c_parameter_reg);
							}
						} else {
							if (l<=last_register_parameter_index){
								i_move_r_pd (REGISTER_D0+n_extra_clean_b_register_parameters+reg_n,B_STACK_POINTER);
								used_clean_b_parameter_registers &= ~ (1<<(n_extra_clean_b_register_parameters+reg_n));
								++reg_n;
							} else {
								b_o-=STACK_ELEMENT_SIZE;
								i_move_id_r (b_o+c_offset_before_pushing_arguments,REGISTER_RBP,REGISTER_A0);
								i_move_r_pd (REGISTER_A0,B_STACK_POINTER);
							}
							c_offset+=STACK_ELEMENT_SIZE;
						}
						break;
					}
					case 'r':
						--c_parameter_n;
						b_o-=8;
						if (--c_fp_parameter_n<8){
							i_fcvt2s_id_fr (b_o+c_offset_before_pushing_arguments,REGISTER_RBP,c_fp_parameter_n);
							--n_c_fp_register_parameters;
						} else {
							/* xmm8 is a 64 bit linux ABI scratch register */
							i_fcvt2s_id_fr (b_o+c_offset_before_pushing_arguments,REGISTER_RBP,8);
							i_fmoves_fr_id (8,-8,B_STACK_POINTER);
							i_sub_i_r (8,B_STACK_POINTER);
							c_offset+=8;
						}
						break;
					case 'R':
						--c_parameter_n;
						b_o-=8;
						if (--c_fp_parameter_n<8){
							i_fmove_id_fr (b_o+c_offset_before_pushing_arguments,REGISTER_RBP,c_fp_parameter_n);
							--n_c_fp_register_parameters;
						} else {
							int temp_register;

							if ((c_parameter_n-n_c_fp_register_parameters)>2 || n_c_parameters<=2)
								temp_register=REGISTER_A1;
							else if ((used_clean_b_parameter_registers & 1)==0)
								temp_register=REGISTER_D0;
							else if ((used_clean_b_parameter_registers & 2)==0)
								temp_register=REGISTER_D1;
							else if ((used_clean_b_parameter_registers & 4)==0)
								temp_register=REGISTER_D2;
							else
								error_s (ccall_error_string,c_function_name);
	
							i_move_id_r (b_o+c_offset_before_pushing_arguments,REGISTER_RBP,temp_register);
							i_move_r_pd (temp_register,B_STACK_POINTER);
							c_offset+=8;
						}
						break;
					case 'S':
					case 's':
					case 'A':
					{
						int offset,c_int_parameter_n;
				
 						offset = sl=='S' ? STACK_ELEMENT_SIZE : sl=='s' ? 2*STACK_ELEMENT_SIZE : 3*STACK_ELEMENT_SIZE;

						--c_parameter_n;
						c_int_parameter_n = c_parameter_n - n_c_fp_register_parameters;
						if (c_int_parameter_n<6){
							int c_parameter_reg;
					
							c_parameter_reg=c_parameter_registers[c_int_parameter_n];
							
							if (c_int_parameter_n<2){
								if (c_int_parameter_n==0){
									if ((used_clean_b_parameter_registers & (1<<6))==0){
										heap_pointer=REGISTER_D6;
										used_clean_b_parameter_registers |= 1<<6;
									} else if ((used_clean_b_parameter_registers & (1<<5))==0){
										heap_pointer=REGISTER_D5;
										used_clean_b_parameter_registers |= 1<<5;
									} else
										error_s (ccall_error_string,c_function_name);								
									i_move_r_r (HEAP_POINTER,heap_pointer);
								} else {
									if ((used_clean_b_parameter_registers & (1<<5))==0){
										a_stack_pointer=REGISTER_D5;
										used_clean_b_parameter_registers |= 1<<5;
									} else if ((used_clean_b_parameter_registers & (1<<6))==0){
										a_stack_pointer=REGISTER_D6;
										used_clean_b_parameter_registers |= 1<<6;
									} else
										error_s (ccall_error_string,c_function_name);								
									i_move_r_r (A_STACK_POINTER,a_stack_pointer);
								}
							}

							i_move_id_r (a_o,a_stack_pointer,c_parameter_reg);
							i_add_i_r (offset,c_parameter_reg);
						} else {
							i_move_id_r (a_o,a_stack_pointer,REGISTER_A0);
							i_add_i_r (offset,REGISTER_A0);
							i_move_r_pd (REGISTER_A0,B_STACK_POINTER);
							c_offset+=STACK_ELEMENT_SIZE;
						}
						a_o+=STACK_ELEMENT_SIZE;
						break;
					}
					case 'F':
					case 'O':
					case '*':
					case ']':
						/* while (l>=0 && !(s[l]=='F' || s[l]=='O')) bug in watcom c */
						while (l>=0 && (s[l]!='F' && s[l]!='O'))
							--l;
						
						if (l<=last_register_parameter_index){
							int clean_b_reg_n,i;
							
							clean_b_reg_n=REGISTER_D0+n_extra_clean_b_register_parameters+reg_n;

							if (function_address_parameter=='O'){
								i_move_r_pd (clean_b_reg_n,B_STACK_POINTER);
								c_offset+=STACK_ELEMENT_SIZE;
							}
							
							++reg_n;

							function_address_reg=clean_b_reg_n;
							i=l;
							while (i+1<length && (s[i+1]=='*' || s[i+1]=='[')){
								int n;
								
								++i;
								n=0;
								
								if (s[i]=='['){
									++i;
									while (i<length && (unsigned)(s[i]-'0')<(unsigned)10){
										n=n*10+(s[i]-'0');
										++i;
									}
								}
								
								i_move_id_r (n,clean_b_reg_n,clean_b_reg_n);
							}
							break;
						}
					default:
						error_s (ccall_error_string,c_function_name);
				}
			}
		}

		if (!save_state_in_global_variables){
			if (a_stack_pointer==A_STACK_POINTER){
				a_stack_pointer = heap_pointer!=REGISTER_D5 ? REGISTER_D5 : REGISTER_D6;
				i_move_r_r (A_STACK_POINTER,a_stack_pointer);
			}
			if (heap_pointer==HEAP_POINTER){
				heap_pointer = a_stack_pointer!=REGISTER_D6 ? REGISTER_D6 : REGISTER_D5;
				i_move_r_r (HEAP_POINTER,heap_pointer);
			}
		}
#   ifndef THREAD64
		else {
			i_move_r_l (a_stack_pointer,saved_a_stack_p_label);
			i_lea_l_i_r (saved_heap_p_label,0,a_stack_pointer);
			i_move_r_id (heap_pointer,0,a_stack_pointer);
			i_move_r_id (REGISTER_D7,8,a_stack_pointer);
		}
#   endif

		if (!function_address_parameter)
			i_jsr_l (label,0);
		else
			i_jsr_r (function_address_reg);

#   ifdef THREAD64
		if (save_state_in_global_variables){
			if (tlsp_tls_index_label==NULL)
				tlsp_tls_index_label=enter_label (STRING_tlsp_tls_index,IMPORT_LABEL);
			if (pthread_getspecific_label==NULL)
				pthread_getspecific_label=enter_label (STRING_pthread_getspecific,IMPORT_LABEL);

			i_sub_i_r (16,B_STACK_POINTER);

			switch (result){
				case 'V':
					i_move_l_r (tlsp_tls_index_label,-7/*RDI*/);
					i_jsr_l (pthread_getspecific_label,0);
					i_move_r_r (REGISTER_D0,-4/*R9*/);
					break;
				case 'R':
					i_fmove_fr_id (0,0,B_STACK_POINTER);
					i_move_l_r (tlsp_tls_index_label,-7/*RDI*/);
					i_jsr_l (pthread_getspecific_label,0);
					i_move_r_r (REGISTER_D0,-4/*R9*/);
					i_fmove_id_fr (0,B_STACK_POINTER,0);
					break;
				default:
					i_move_r_id (REGISTER_D0,0,B_STACK_POINTER);
					i_move_l_r (tlsp_tls_index_label,-7/*RDI*/);
					i_jsr_l (pthread_getspecific_label,0);
					i_move_r_r (REGISTER_D0,-4/*R9*/);
					i_move_id_r (0,B_STACK_POINTER,REGISTER_D0);
			}
		}
#   endif
		
		if (c_offset_before_pushing_arguments-(b_result_offset+a_result_offset)==0)
			i_move_r_r (REGISTER_RBP,B_STACK_POINTER);
		else
			i_lea_id_r (c_offset_before_pushing_arguments-(b_result_offset+a_result_offset),REGISTER_RBP,B_STACK_POINTER);	

		if (!save_state_in_global_variables){
			i_move_r_r (a_stack_pointer,A_STACK_POINTER);
			i_move_r_r (heap_pointer,HEAP_POINTER);
			i_move_id_r (-16,REGISTER_RBP,-4/*R9*/);
		} else {
#   ifdef THREAD64
			i_move_id_r (SAVED_A_STACK_P_OFFSET,-4/*R9*/,A_STACK_POINTER);
			i_move_id_r (SAVED_R15_OFFSET,-4/*R9*/,REGISTER_D7);
			i_move_id_r (SAVED_HEAP_P_OFFSET,-4/*R9*/,-7/*RDI*/);
#   else
			i_lea_l_i_r (saved_heap_p_label,0,-7/*RDI*/);
			i_move_l_r (saved_a_stack_p_label,-6/*RSI*/);
			i_move_id_r (8,-7/*RDI*/,REGISTER_D7);
			i_move_id_r (0,-7/*RDI*/,-7/*RDI*/);
#   endif
		}
#  else /* for I486 && G_AI64 && ! (LINUX_ELF || MACHO_64) */
		{
		int c_offset_before_pushing_arguments,function_address_reg,c_parameter_n;
		
		c_offset_before_pushing_arguments=c_offset;

		c_parameter_n=((a_offset+b_offset+a_result_offset+b_result_offset)>>3)+n_clean_b_register_parameters;

		i_move_r_r (B_STACK_POINTER,REGISTER_RBP);
#   ifdef THREAD64
		if (!save_state_in_global_variables){
			if (c_parameter_n>=4 && (c_parameter_n & 1)!=0){
				i_sub_i_r (16+8,B_STACK_POINTER);
				i_move_r_id (-4/*R9*/,8,B_STACK_POINTER);
				i_or_i_r (8,B_STACK_POINTER);		
			} else {
				i_sub_i_r (16,B_STACK_POINTER);
				i_move_r_id (-4/*R9*/,0,B_STACK_POINTER);
				i_and_i_r (-16,B_STACK_POINTER);		
			}
		} else
#   endif
		if (c_parameter_n>=4 && (c_parameter_n & 1)!=0){
			i_sub_i_r (8,B_STACK_POINTER);
			i_or_i_r (8,B_STACK_POINTER);		
		} else {
			i_and_i_r (-16,B_STACK_POINTER);		
		}

		for (l=length-1; l>=first_pointer_result_index; --l){
			switch (s[l]){
				case 'I':
				case 'p':
					b_o-=STACK_ELEMENT_SIZE;
					if (--c_parameter_n<4)
						i_lea_id_r (b_o+c_offset_before_pushing_arguments,REGISTER_RBP,REGISTER_A0-c_parameter_n);
					else {
						i_lea_id_r (b_o+c_offset_before_pushing_arguments,REGISTER_RBP,REGISTER_A0);
						i_move_r_pd (REGISTER_A0,B_STACK_POINTER);
						c_offset+=STACK_ELEMENT_SIZE;
					}
					break;
				case 'R':
					b_o-=8;
					if (--c_parameter_n<4)
						i_lea_id_r (b_o+c_offset_before_pushing_arguments,REGISTER_RBP,REGISTER_A0-c_parameter_n);
					else {
						i_lea_id_r (b_o+c_offset_before_pushing_arguments,REGISTER_RBP,REGISTER_A0);
						i_move_r_pd (REGISTER_A0,B_STACK_POINTER);
						c_offset+=STACK_ELEMENT_SIZE;
					}
					break;
				case 'i':
				case 'r':
					--l;
				case 'S':
					if (--c_parameter_n<4)
						i_lea_id_r (a_o+c_offset_before_pushing_arguments,REGISTER_RBP,REGISTER_A0-c_parameter_n);
					else {
						i_lea_id_r (a_o+c_offset_before_pushing_arguments,REGISTER_RBP,REGISTER_A0);
						i_move_r_pd (REGISTER_A0,B_STACK_POINTER);
						c_offset+=STACK_ELEMENT_SIZE;
					}
					a_o+=STACK_ELEMENT_SIZE;
					break;
				case 'V':
					break;
				default:
					error_s (ccall_error_string,c_function_name);
			}
		}
		
		{
			int last_register_parameter_index,reg_n;
			
			last_register_parameter_index=-1;
			
			reg_n=0;
			l=0;
			while (reg_n<n_clean_b_register_parameters && l<min_index){
				if (s[l]=='I' || s[l]=='p' || s[l]=='F' || s[l]=='O'){
					++reg_n;
					last_register_parameter_index=l;
				}
				++l;
			}
			
			reg_n=0;
			a_o=-a_offset;
			b_o=0;
			for (l=min_index-1; l>=0; --l){
				switch (s[l]){
					case 'I':
					case 'p':
						if (--c_parameter_n<4){
							if (l<=last_register_parameter_index){
								i_move_r_r (REGISTER_D0+n_extra_clean_b_register_parameters+reg_n,REGISTER_A0-c_parameter_n);
								++reg_n;
							} else {
								b_o-=STACK_ELEMENT_SIZE;
								i_move_id_r (b_o+c_offset_before_pushing_arguments,REGISTER_RBP,REGISTER_A0-c_parameter_n);
							}
						} else {
							if (l<=last_register_parameter_index){
								i_move_r_pd (REGISTER_D0+n_extra_clean_b_register_parameters+reg_n,B_STACK_POINTER);
								++reg_n;
							} else {
								b_o-=STACK_ELEMENT_SIZE;
								i_move_id_r (b_o+c_offset_before_pushing_arguments,REGISTER_RBP,REGISTER_A0);
								i_move_r_pd (REGISTER_A0,B_STACK_POINTER);
							}
							c_offset+=STACK_ELEMENT_SIZE;
						}
						break;
					case 'r':
						b_o-=8;
						if (--c_parameter_n<4)
							i_fcvt2s_id_fr (b_o+c_offset_before_pushing_arguments,REGISTER_RBP,c_parameter_n);
						else {
							/* xmm4 is a 64 bit windows ABI scratch register */
							i_fcvt2s_id_fr (b_o+c_offset_before_pushing_arguments,REGISTER_RBP,4);
							i_fmoves_fr_id (4,-8,B_STACK_POINTER);
							i_sub_i_r (8,B_STACK_POINTER);
							c_offset+=8;
						}
						break;
					case 'R':
						b_o-=8;
						if (--c_parameter_n<4)
							i_fmove_id_fr (b_o+c_offset_before_pushing_arguments,REGISTER_RBP,c_parameter_n);
						else {
							i_move_id_r (b_o+c_offset_before_pushing_arguments,REGISTER_RBP,REGISTER_A0);
							i_move_r_pd (REGISTER_A0,B_STACK_POINTER);
							c_offset+=8;
						}
						break;
					case 'S':
						if (--c_parameter_n<4){
							i_move_id_r (a_o,A_STACK_POINTER,REGISTER_A0-c_parameter_n);
							i_add_i_r (STACK_ELEMENT_SIZE,REGISTER_A0-c_parameter_n);
						} else {
							i_move_id_r (a_o,A_STACK_POINTER,REGISTER_A0);
							i_add_i_r (STACK_ELEMENT_SIZE,REGISTER_A0);
							i_move_r_pd (REGISTER_A0,B_STACK_POINTER);
							c_offset+=STACK_ELEMENT_SIZE;
						}
						a_o+=STACK_ELEMENT_SIZE;
						break;
					case 's':
						if (--c_parameter_n<4){
							i_move_id_r (a_o,A_STACK_POINTER,REGISTER_A0-c_parameter_n);
							i_add_i_r (2*STACK_ELEMENT_SIZE,REGISTER_A0-c_parameter_n);							
						} else {
							i_move_id_r (a_o,A_STACK_POINTER,REGISTER_A0);
							i_add_i_r (2*STACK_ELEMENT_SIZE,REGISTER_A0);
							i_move_r_pd (REGISTER_A0,B_STACK_POINTER);
							c_offset+=STACK_ELEMENT_SIZE;
						}
						a_o+=STACK_ELEMENT_SIZE;
						break;
					case 'A':
						if (--c_parameter_n<4){
							i_move_id_r (a_o,A_STACK_POINTER,REGISTER_A0-c_parameter_n);
							i_add_i_r (3*STACK_ELEMENT_SIZE,REGISTER_A0-c_parameter_n);
						} else {
							i_move_id_r (a_o,A_STACK_POINTER,REGISTER_A0);
							i_add_i_r (3*STACK_ELEMENT_SIZE,REGISTER_A0);
							i_move_r_pd (REGISTER_A0,B_STACK_POINTER);
							c_offset+=STACK_ELEMENT_SIZE;
						}
						a_o+=STACK_ELEMENT_SIZE;
						break;
					case 'F':
					case 'O':
					case '*':
					case ']':
						/* while (l>=0 && !(s[l]=='F' || s[l]=='O')) bug in watcom c */
						while (l>=0 && (s[l]!='F' && s[l]!='O'))
							--l;
						
						if (l<=last_register_parameter_index){
							int clean_b_reg_n,i;
							
							clean_b_reg_n=REGISTER_D0+n_extra_clean_b_register_parameters+reg_n;

							if (function_address_parameter=='O'){
								i_move_r_pd (clean_b_reg_n,B_STACK_POINTER);
								c_offset+=STACK_ELEMENT_SIZE;
							}
							
							++reg_n;

							function_address_reg=clean_b_reg_n;
							i=l;
							while (i+1<length && (s[i+1]=='*' || s[i+1]=='[')){
								int n;
								
								++i;
								n=0;
								
								if (s[i]=='['){
									++i;
									while (i<length && (unsigned)(s[i]-'0')<(unsigned)10){
										n=n*10+(s[i]-'0');
										++i;
									}
								}
								
								i_move_id_r (n,clean_b_reg_n,clean_b_reg_n);
							}
							break;
						}
					default:
						error_s (ccall_error_string,c_function_name);
				}
			}
		}

#   ifndef THREAD64
		if (save_state_in_global_variables){
			i_move_r_l (-6/*RSI*/,saved_a_stack_p_label);
			i_lea_l_i_r (saved_heap_p_label,0,-6/*RSI*/);
			i_move_r_id (-7/*RDI*/,  0,-6/*RSI*/);
			i_move_r_id (REGISTER_D7,8,-6/*RSI*/);
		}
#   endif

		i_sub_i_r (32,B_STACK_POINTER);
		if (!function_address_parameter)
			i_jsr_l (label,0);
		else
			i_jsr_r (function_address_reg);

		/* i_add_i_r (32,B_STACK_POINTER); */
		
		if (c_offset_before_pushing_arguments-(b_result_offset+a_result_offset)==0)
			i_move_r_r (REGISTER_RBP,B_STACK_POINTER);
		else
			i_lea_id_r (c_offset_before_pushing_arguments-(b_result_offset+a_result_offset),REGISTER_RBP,B_STACK_POINTER);	

#   ifdef THREAD64
		if (!save_state_in_global_variables)
			i_move_id_r (-16,REGISTER_RBP,-4/*R9*/);
		else {
			instruction_l_r (ILDTLSP,tlsp_tls_index_label,-4/*R9*/);

			i_move_id_r (SAVED_A_STACK_P_OFFSET,-4/*R9*/,A_STACK_POINTER);
			i_move_id_r (SAVED_R15_OFFSET,-4/*R9*/,REGISTER_D7);
			i_move_id_r (SAVED_HEAP_P_OFFSET,-4/*R9*/,-7/*RDI*/);
		}
#   else
		if (save_state_in_global_variables){
			i_lea_l_i_r (saved_heap_p_label,0,-7/*RDI*/);
			i_move_l_r (saved_a_stack_p_label,-6/*RSI*/);
			i_move_id_r (8,-7/*RDI*/,REGISTER_D7);
			i_move_id_r (0,-7/*RDI*/,-7/*RDI*/);
		}
#   endif
#  endif
		/* for I486 && G_AI64 */

		if (callee_pops_arguments)
			c_offset=c_offset_before_pushing_arguments;
		
		if (a_offset!=0)
			i_sub_i_r (a_offset,A_STACK_POINTER);
		/*
		if (c_offset-(b_result_offset+a_result_offset)!=0)
			i_add_i_r (c_offset-(b_result_offset+a_result_offset),B_STACK_POINTER);
		*/
		}

		for (l=length-1; l>=first_pointer_result_index; --l){
			switch (s[l]){
				case 'S':
					if (string_to_string_node_label==NULL)
						string_to_string_node_label=enter_label ("string_to_string_node",IMPORT_LABEL);
					i_move_pi_r (B_STACK_POINTER,REGISTER_A0);
					i_jsr_l (string_to_string_node_label,0);
					i_move_r_id (REGISTER_A0,0,A_STACK_POINTER);
					i_add_i_r (STACK_ELEMENT_SIZE,A_STACK_POINTER);
					break;
				case 'i':
					--l;
					if (int_array_to_node_label==NULL)
						int_array_to_node_label=enter_label ("int_array_to_node",IMPORT_LABEL);
					i_move_pi_r (B_STACK_POINTER,REGISTER_A0);
					i_jsr_l (int_array_to_node_label,0);
					i_move_r_id (REGISTER_A0,0,A_STACK_POINTER);
					i_add_i_r (STACK_ELEMENT_SIZE,A_STACK_POINTER);
					break;
				case 'r':
					--l;
					if (real_array_to_node_label==NULL)
						real_array_to_node_label=enter_label ("real_array_to_node",IMPORT_LABEL);
					i_move_pi_r (B_STACK_POINTER,REGISTER_A0);
					i_jsr_l (real_array_to_node_label,0);
					i_move_r_id (REGISTER_A0,0,A_STACK_POINTER);
					i_add_i_r (STACK_ELEMENT_SIZE,A_STACK_POINTER);
					break;
				case 'I':
				case 'p':
				case 'R':
				case 'V':
					break;
				default:
					error_s (ccall_error_string,c_function_name);
			}
		}
		
		b_o=0;
		for (l=first_pointer_result_index; l<length; ++l){
			switch (s[l]){
				case 'I':
					i_loadsqb_id_r (b_o,B_STACK_POINTER,REGISTER_RBP);
					i_move_r_id (REGISTER_RBP,b_o,B_STACK_POINTER);
					b_o+=STACK_ELEMENT_SIZE;
					break;
				case 'p':
					b_o+=STACK_ELEMENT_SIZE;
					break;
				case 'R':
					b_o+=8;
					break;
				case 'S':
				case 'V':
					break;
				case 'A':
					++l;
					break;
				default:
					error_s (ccall_error_string,c_function_name);
			}
		}

		switch (result){
			case 'I':
				i_loadsqb_r_r (REGISTER_D0,REGISTER_D0);
			case 'p':
				begin_new_basic_block();
				init_b_stack (1,i_vector);
				break;
			case 'R':
				begin_new_basic_block();
				init_b_stack (1,r_vector);
				break;
			case 'S':
				if (string_to_string_node_label==NULL)
					string_to_string_node_label=enter_label ("string_to_string_node",IMPORT_LABEL);

				i_move_r_r (REGISTER_D0,REGISTER_A0);
				i_jsr_l (string_to_string_node_label,0);

				begin_new_basic_block();
				init_a_stack (1);
				break;
			case 'A':
				i_move_r_r (REGISTER_D0,REGISTER_A0);
				if (s[min_index+2]=='i'){
					if (int_array_to_node_label==NULL)
						int_array_to_node_label=enter_label ("int_array_to_node",IMPORT_LABEL);
					i_jsr_l (int_array_to_node_label,0);
				} else if (s[min_index+2]=='r'){
					if (real_array_to_node_label==NULL)
						real_array_to_node_label=enter_label ("real_array_to_node",IMPORT_LABEL);
					i_jsr_l (real_array_to_node_label,0);
				}

				begin_new_basic_block();
				init_a_stack (1);
				break;
			case 'V':
				begin_new_basic_block();
				break;
			default:
				error_s (ccall_error_string,c_function_name);
		}
# endif
#endif
}

#define SMALL_VECTOR_SIZE 32
#define LOG_SMALL_VECTOR_SIZE 5
#define MASK_SMALL_VECTOR_SIZE 31

static char centry_error_string[]="Error in c entry of '%s'";

#ifdef G_POWER
extern struct instruction *last_instruction;
extern LABEL *INT_label,*BOOL_label,*CHAR_label,*REAL_label;
extern LABEL *cycle_in_spine_label,*reserve_label;
void code_jsr_from_c_to_clean (char *label_name);

static void load_constant_registers (void)
{
	/*
		lea	a5,__cycle__in__spine
		lea	int_reg,INT2
		lea	char_reg,CHAR2
		lea	real_reg,REAL2
		lea	bool_reg,BOOL2
	*/

	if (INT_label==NULL)
		INT_label=enter_label ("INT",IMPORT_LABEL | DATA_LABEL);
	i_lea_l_i_r (INT_label,2,INT_REGISTER);
	
	if (CHAR_label==NULL)
		CHAR_label=enter_label ("CHAR",IMPORT_LABEL | DATA_LABEL);
	i_lea_l_i_r (CHAR_label,2,CHAR_REGISTER);	

	if (REAL_label==NULL)
		REAL_label=enter_label ("REAL",IMPORT_LABEL | DATA_LABEL);
	i_lea_l_i_r (REAL_label,2,REAL_REGISTER);

	if (BOOL_label==NULL)
		BOOL_label=enter_label ("BOOL",IMPORT_LABEL | DATA_LABEL);
	i_lea_l_i_r (BOOL_label,2,BOOL_REGISTER);
	
	if (!parallel_flag){
		if (cycle_in_spine_label==NULL){
			cycle_in_spine_label=enter_label ("__cycle__in__spine",IMPORT_LABEL | NODE_ENTRY_LABEL);
			cycle_in_spine_label->label_arity=0;
			cycle_in_spine_label->label_descriptor=EMPTY_label;
		}
		i_lea_l_i_r (cycle_in_spine_label,0,REGISTER_A5);
	} else {
		if (reserve_label==NULL){
			reserve_label=enter_label ("__reserve",IMPORT_LABEL | NODE_ENTRY_LABEL);
			reserve_label->label_arity=0;
			reserve_label->label_descriptor=EMPTY_label;
		}
		i_lea_l_i_r (reserve_label,0,REGISTER_A5);
	}
}
#endif

static void save_registers_before_clean_call (void)
{
#if defined (I486)
# ifdef G_AI64
	i_sub_i_r (144,B_STACK_POINTER);

#  if defined (LINUX_ELF) || defined (MACH_O64)
#   ifndef THREAD64
	i_move_r_r (-6/*RSI*/,3/*R11*/);
#   endif
#  else
	i_move_r_id (-6/*RSI*/,136,B_STACK_POINTER);
#  endif
#  ifndef THREAD64
	i_move_l_r (saved_a_stack_p_label,-6/*RSI*/);
#  endif
#  if defined (LINUX_ELF) || defined (MACH_O64)
#   ifndef THREAD64
	i_move_r_r (-7/*RDI*/,2/*R10*/);
#   endif
#  else
	i_move_r_id (-7/*RDI*/,128,B_STACK_POINTER);
#  endif
#  ifndef THREAD64
	i_lea_l_i_r (saved_heap_p_label,0,-7/*RDI*/);
#  endif
	i_move_r_id ( 7/*R15*/,80,B_STACK_POINTER);
#  ifndef THREAD64
	i_move_id_r (8,-7/*RDI*/,REGISTER_D7);
	i_move_id_r (0,-7/*RDI*/,-7/*RDI*/);
#  endif
	i_move_r_id ( 1/*RBX*/,120,B_STACK_POINTER);
	i_move_r_id (-5/*RBP*/,112,B_STACK_POINTER);
	i_move_r_id ( 4/*R12*/,104,B_STACK_POINTER);
	i_move_r_id ( 5/*R13*/,96,B_STACK_POINTER);
	i_move_r_id ( 6/*R14*/,88,B_STACK_POINTER);

#  if ! (defined (LINUX_ELF) || defined (MACH_O64))
	{
		int i;
		/* to do: save all 128 bits, because calling convention has been changed */
		for (i=6; i<16; ++i)
			i_fmove_fr_id (i,(15-i)<<3,B_STACK_POINTER);
	}
#  endif
# else
	i_sub_i_r (20,B_STACK_POINTER);
#  ifndef THREAD32
	i_move_r_id (-4/*ESI*/,16,B_STACK_POINTER);
	i_move_l_r (saved_a_stack_p_label,-4/*ESI*/);

	i_move_r_id (-5/*EDI*/,12,B_STACK_POINTER);
	i_move_l_r (saved_heap_p_label,-5/*EDI*/);
#  else
	if (tlsp_tls_index_label==NULL)
		tlsp_tls_index_label=enter_label (STRING_tlsp_tls_index,IMPORT_LABEL);

	i_move_r_id (-5/*EDI*/,12,B_STACK_POINTER);
	instruction_l_r (ILDTLSP,tlsp_tls_index_label,-5/*EDI*/);

	i_move_r_id (-4/*ESI*/,16,B_STACK_POINTER);
	i_move_id_r (SAVED_A_STACK_P_OFFSET,-5/*EDI*/,-4/*ESI*/);
#  endif
	i_move_r_id (1/*EBX*/,8,B_STACK_POINTER);
	i_move_r_id (-1/*ECX*/,4,B_STACK_POINTER);
	i_move_r_id (-3/*EBP*/,0,B_STACK_POINTER);
# endif
#elif defined (G_POWER)
	{
		int i,offset;
		
		i_sub_i_r (((32-13)<<2)+((32-14)<<3),B_STACK_POINTER);
		
		offset=0;
		for (i=13; i<32; ++i){
			i_move_r_id (i-24,offset,B_STACK_POINTER);
			offset+=4;
		}
		
		for (i=14; i<32; ++i){
			i_fmove_fr_id (i-14,offset,B_STACK_POINTER);
			offset+=8;
		}
	}

	i_lea_l_i_r (saved_a_stack_p_label,0,REGISTER_A3);
	i_move_id_r (0,REGISTER_A3,A_STACK_POINTER);
	i_lea_l_i_r (saved_heap_p_label,0,REGISTER_A3);
	i_move_id_r (0,REGISTER_A3,HEAP_POINTER);
	i_move_id_r (4,REGISTER_A3,REGISTER_D7);
#endif
}

static void restore_registers_after_clean_call (void)
{
#if defined (I486)
# ifdef G_AI64

#  ifdef THREAD64
	if (tlsp_tls_index_label==NULL)
		tlsp_tls_index_label=enter_label (STRING_tlsp_tls_index,IMPORT_LABEL);

	i_move_r_id (-6/*RSI*/,SAVED_A_STACK_P_OFFSET,-4/*R9*/);
	i_move_r_id (-7/*RDI*/,SAVED_HEAP_P_OFFSET,-4/*R9*/);
	i_move_r_id (REGISTER_D7,SAVED_R15_OFFSET,-4/*R9*/);
#  else
	i_move_r_l (-6/*RSI*/,saved_a_stack_p_label);
	i_lea_l_i_r (saved_heap_p_label,0,-6/*RSI*/);
	i_move_r_id (-7/*RDI*/,  0,-6/*RSI*/);
	i_move_r_id (REGISTER_D7,8,-6/*RSI*/);
#  endif

#  if ! (defined (LINUX_ELF) || defined (MACH_O64))
	i_move_id_r (136,B_STACK_POINTER,-6/*RSI*/);
	i_move_id_r (128,B_STACK_POINTER,-7/*RDI*/);
#  endif
	i_move_id_r ( 80,B_STACK_POINTER, 7/*R15*/);

	i_move_id_r (120,B_STACK_POINTER, 1/*RBX*/);
	i_move_id_r (112,B_STACK_POINTER,-5/*RBP*/);
	i_move_id_r (104,B_STACK_POINTER, 4/*R12*/);
	i_move_id_r ( 96,B_STACK_POINTER, 5/*R13*/);
	i_move_id_r ( 88,B_STACK_POINTER, 6/*R14*/);
#  if ! (defined (LINUX_ELF) || defined (MACH_O64))
	{
		int i;
		/* to do: save all 128 bits, because calling convention has been changed */		
		for (i=6; i<16; ++i)
			i_fmove_id_fr ((15-i)<<3,B_STACK_POINTER,i);
	}
#  endif
	i_add_i_r (144,B_STACK_POINTER);
# else
#  ifndef THREAD32
	i_move_r_l (-4/*ESI*/,saved_a_stack_p_label);
	i_move_id_r (16,B_STACK_POINTER,-4/*ESI*/);

	i_move_r_l (-5/*EDI*/,saved_heap_p_label);
	i_move_id_r (12,B_STACK_POINTER,-5/*EDI*/);	
#  else
	i_move_r_id (-4/*ESI*/,SAVED_A_STACK_P_OFFSET,-5/*EDI*/);
	i_move_id_r (16,B_STACK_POINTER,-4/*ESI*/);
	i_move_id_r (12,B_STACK_POINTER,-5/*EDI*/);		
#  endif
	i_move_id_r (8,B_STACK_POINTER,1/*EBX*/);
	i_move_id_r (4,B_STACK_POINTER,-1/*ECX*/);
	i_move_id_r (0,B_STACK_POINTER,-3/*EBP*/);
	i_add_i_r (20,B_STACK_POINTER);
# endif
#elif defined (G_POWER)
	i_lea_l_i_r (saved_a_stack_p_label,0,REGISTER_A3);
	i_move_r_id (A_STACK_POINTER,0,REGISTER_A3);
	i_lea_l_i_r (saved_heap_p_label,0,REGISTER_A3);
	i_move_r_id (HEAP_POINTER,0,REGISTER_A3);
	i_move_r_id (REGISTER_D7,4,REGISTER_A3);

	i_move_r_r (REGISTER_D0,C_PARAMETER_REGISTER_0);

	{
		int i,offset;
		
		offset=0;
		for (i=13; i<32; ++i){
			i_move_id_r (offset,B_STACK_POINTER,i-24);
			offset+=4;
		}
		
		for (i=14; i<32; ++i){
			i_fmove_id_fr (offset,B_STACK_POINTER,i-14);
			offset+=8;
		}

		i_add_i_r (offset,B_STACK_POINTER);
	}
#endif
}

#ifdef THREAD64
static void insert_loads_of_r9_rsi_rdi_and_r15_before_call (struct basic_block *block_with_call)
{
	/* hack to load r9, rsi, rdi and r15 before jmp or call */
# ifndef MACH_O64
	struct instruction *instruction1;
# endif
	struct instruction *instruction2,*instruction3,*instruction4,*jmp_or_call_instruction,*old_second_last_instruction;

# if !(defined (LINUX_ELF) || defined (MACH_O64))
	/* LDTLSP tlsp_tls_index_label,r9 */

	instruction1=(struct instruction*)fast_memory_allocate (sizeof (struct instruction)+2*sizeof (struct parameter));
	instruction1->instruction_icode=ILDTLSP;
	instruction1->instruction_arity=2;
	instruction1->instruction_parameters[0].parameter_type=P_LABEL;
	instruction1->instruction_parameters[0].parameter_data.l=tlsp_tls_index_label;
	instruction1->instruction_parameters[1].parameter_type=P_REGISTER;
	instruction1->instruction_parameters[1].parameter_data.i=-4/*R9*/;

	jmp_or_call_instruction=block_with_call->block_last_instruction;
	old_second_last_instruction=jmp_or_call_instruction->instruction_prev;

	if (old_second_last_instruction==NULL)
		block_with_call->block_instructions=instruction1;
	else
		old_second_last_instruction->instruction_next=instruction1;
	instruction1->instruction_prev=old_second_last_instruction;
# endif

	/* i_move_id_r (SAVED_A_STACK_P_OFFSET,R9,-6 */ /*RSI*/ /*); */

	instruction2=(struct instruction*)fast_memory_allocate (sizeof (struct instruction)+2*sizeof (struct parameter));
	instruction2->instruction_icode=IMOVE;
	instruction2->instruction_arity=2;
	instruction2->instruction_parameters[0].parameter_type=P_INDIRECT;
	instruction2->instruction_parameters[0].parameter_offset=SAVED_A_STACK_P_OFFSET;
	instruction2->instruction_parameters[0].parameter_data.i=-4/*R9*/;
	instruction2->instruction_parameters[1].parameter_type=P_REGISTER;
	instruction2->instruction_parameters[1].parameter_data.i=-6/*RSI*/;

# if !(defined (LINUX_ELF) || defined (MACH_O64))
	instruction1->instruction_next=instruction2;
	instruction2->instruction_prev=instruction1;
# else
	jmp_or_call_instruction=block_with_call->block_last_instruction;
	old_second_last_instruction=jmp_or_call_instruction->instruction_prev;

	if (old_second_last_instruction==NULL)
		block_with_call->block_instructions=instruction2;
	else
		old_second_last_instruction->instruction_next=instruction2;
	instruction2->instruction_prev=old_second_last_instruction;
# endif

	/* i_move_id_r (SAVED_R15_OFFSET,R9,REGISTER_D7); */

	instruction3=(struct instruction*)fast_memory_allocate (sizeof (struct instruction)+2*sizeof (struct parameter));
	instruction3->instruction_icode=IMOVE;
	instruction3->instruction_arity=2;
	instruction3->instruction_parameters[0].parameter_type=P_INDIRECT;
	instruction3->instruction_parameters[0].parameter_offset=SAVED_R15_OFFSET;
	instruction3->instruction_parameters[0].parameter_data.i=-4/*R9*/;
	instruction3->instruction_parameters[1].parameter_type=P_REGISTER;
	instruction3->instruction_parameters[1].parameter_data.i=REGISTER_D7;

	instruction2->instruction_next=instruction3;
	instruction3->instruction_prev=instruction2;

	/* i_move_id_r (SAVED_HEAP_P_OFFSET,R9,-7 */ /*RDI*/ /*); */

	instruction4=(struct instruction*)fast_memory_allocate (sizeof (struct instruction)+2*sizeof (struct parameter));
	instruction4->instruction_icode=IMOVE;
	instruction4->instruction_arity=2;
	instruction4->instruction_parameters[0].parameter_type=P_INDIRECT;
	instruction4->instruction_parameters[0].parameter_offset=SAVED_HEAP_P_OFFSET;
	instruction4->instruction_parameters[0].parameter_data.i=-4/*R9*/;
	instruction4->instruction_parameters[1].parameter_type=P_REGISTER;
	instruction4->instruction_parameters[1].parameter_data.i=-7 /*RDI*/;

	instruction3->instruction_next=instruction4;
	instruction4->instruction_prev=instruction3;

	instruction4->instruction_next=jmp_or_call_instruction;
	jmp_or_call_instruction->instruction_prev=instruction4;
}
#endif

#if defined (THREAD64) && (defined (LINUX_ELF) || defined (MACH_O64))
static void call_pthread_getspecific (int n_integer_parameters,int n_float_parameters)
{
	int float_parameter_n;

	if (tlsp_tls_index_label==NULL)
		tlsp_tls_index_label=enter_label (STRING_tlsp_tls_index,IMPORT_LABEL);
	if (pthread_getspecific_label==NULL)
		pthread_getspecific_label=enter_label (STRING_pthread_getspecific,IMPORT_LABEL);

	if (n_float_parameters>8)
		n_float_parameters=8;

	switch (n_integer_parameters){
		default: /* >=6 */
			i_move_r_r (-4/*R9 */, 4/*R12*/);
		case 5:
			i_move_r_r (-3/*R8 */, 7/*R15*/);
		case 4:
			i_move_r_r (-1/*RCX*/, 6/*R14*/);
		case 3:
			i_move_r_r (-2/*RDX*/, 5/*R13*/);
		case 2:
			i_move_r_r (-6/*RSI*/,-5/*RBP*/);
		case 1:
			i_move_r_r (-7/*RDI*/, 1/*RBX*/);
		case 0:
			break;
	}

	i_sub_i_r (8+(n_float_parameters<<3),B_STACK_POINTER);

	for (float_parameter_n=0; float_parameter_n<n_float_parameters; ++float_parameter_n)
		i_fmove_fr_id (float_parameter_n,float_parameter_n<<3,B_STACK_POINTER);

	i_move_l_r (tlsp_tls_index_label,-7/*RDI*/);
	i_jsr_l (pthread_getspecific_label,0);

	for (float_parameter_n=0; float_parameter_n<n_float_parameters; ++float_parameter_n)
		i_fmove_id_fr (float_parameter_n<<3,B_STACK_POINTER,float_parameter_n);

	i_move_r_r (REGISTER_D0,-4/*R9*/);

	i_add_i_r (8+(n_float_parameters<<3),B_STACK_POINTER);

	switch (n_integer_parameters){
		default: /* >=6 */
		case 5:
			i_move_r_r ( 7/*R15*/,-3/*R8 */);
		case 4:
			i_move_r_r ( 6/*R14*/,-1/*RCX*/);
		case 3:
			i_move_r_r ( 5/*R13*/,-2/*RDX*/);
		case 2:
			i_move_r_r (-5/*RBP*/, 3/*R11*/);
		case 1:
			i_move_r_r ( 1/*RBX*/, 2/*R10*/);
		case 0:
			break;
	}
}
#endif

#ifdef I486
# ifdef G_AI64
#  define REGISTER_EBP_OR_RBP (-5)
# else
#  define REGISTER_EBP_OR_RBP (-3)
# endif
#endif

void code_centry (char *c_function_name,char *clean_function_label,char *s,int length)
{
#if defined (I486) || defined (G_POWER)
	struct block_label *new_label;
	LABEL *label;
	int i,n,callee_pops_arguments,n_integer_and_float_parameters;
	int first_parameter_index,colon_index,first_result_index;
	int n_integer_parameters,n_integer_results,integer_c_function_result;
	int n_float_parameters,n_float_results,float_c_function_result;
	int n_string_or_array_parameters,n_string_or_array_results;
	int string_c_function_result,array_c_function_result,string_or_array_c_function_result;
	int float_parameter_or_result;
# ifdef THREAD64
	struct basic_block *block_with_call;
# endif

#if !defined (THREAD64)
	if (saved_heap_p_label==NULL)
		saved_heap_p_label=enter_label ("saved_heap_p",IMPORT_LABEL);
	if (saved_a_stack_p_label==NULL)
		saved_a_stack_p_label=enter_label ("saved_a_stack_p",IMPORT_LABEL);
#endif

	n_integer_parameters=0;
	n_float_parameters=0;
	n_string_or_array_parameters=0;
	n_integer_results=0;
	n_float_results=0;
	float_parameter_or_result=0;
	n_string_or_array_results=0;

	i=0;
	callee_pops_arguments=0;
	if (length>0 && s[0]=='P'){
		i=1;
		callee_pops_arguments=1;
	}

	integer_c_function_result=0;
	float_c_function_result=0;
	string_c_function_result=0;
	array_c_function_result=0;

	first_parameter_index=i;

	while (i<length){
		char c;
		
		c=s[i];
		if (c=='I')
			++n_integer_parameters;
#if defined (I486)
		else if (c=='R'){
			++n_float_parameters;
			float_parameter_or_result=1;
		} else if (c=='S')
			++n_string_or_array_parameters;
		else if (c=='A' && i+1<length){
			c=s[++i];
			if (c=='i')
				++n_string_or_array_parameters;				
			else if (c=='r'){
				++n_string_or_array_parameters;
				float_parameter_or_result=1;
			} else
				error_s (centry_error_string,c_function_name);				
		}
#endif
		else if (c==':'){
			colon_index=i;
			++i;

			if (i<length){
				c=s[i];
				if (c=='V')
					;
				else if (c=='I'){
					integer_c_function_result=1;
					++n_integer_results;
#if defined (I486)
				} else if (c=='R'){
					float_c_function_result=1;
					++n_float_results;
					float_parameter_or_result=1;
				} else if (c=='S'){
					string_c_function_result=1;
					++n_string_or_array_results;
				} else if (c=='A' && i+1<length){
					c=s[++i];
					++n_string_or_array_results;
					if (c=='i'){
						array_c_function_result=1;
					} else if (c=='r'){
						array_c_function_result=1;
						float_parameter_or_result=1;
					} else
						error_s (centry_error_string,c_function_name);
#endif
				} else
					error_s (centry_error_string,c_function_name);
				++i;
			}

			first_result_index=i;
			while (i<length){
				c=s[i];
				if (c=='I')
					++n_integer_results;
#if defined (I486)
				else if (c=='R'){
					++n_float_results;
					float_parameter_or_result=1;
				} else if (c=='S')
					++n_string_or_array_results;
				else if (c=='A' && i+1<length){
					c=s[++i];
					if (c=='i'){
						++n_string_or_array_results;						
					} else if (c=='r'){
						++n_string_or_array_results;
						float_parameter_or_result=1;
					} else
						error_s (centry_error_string,c_function_name);
				}
#endif
				else
					error_s (centry_error_string,c_function_name);
				++i;
			}
			break;
		} else
			error_s (centry_error_string,c_function_name);
		
		++i;
	}

	string_or_array_c_function_result=string_c_function_result+array_c_function_result;

#ifdef I486
	if (n_integer_results==0 && n_float_results==0 && n_string_or_array_results==0)
#else
	if (n_integer_results!=1)
#endif
		error_s (centry_error_string,c_function_name);

#ifndef G_A64
	n_integer_and_float_parameters=n_integer_parameters+(n_float_parameters<<1);
#else
	n_integer_and_float_parameters=n_integer_parameters+n_float_parameters;
#endif

# if (defined (sparc) && !defined (SOLARIS)) || (defined (I486) && !defined (LINUX_ELF) && !defined (G_AI64)) || (defined (G_POWER) && !defined (LINUX_ELF)) || defined (MACH_O) || defined (MACH_O64)
	{
		char label_name [202];

#  if defined (G_POWER) && !defined (MACH_O)
		label_name[0]='.';
#  else
		label_name[0]='_';
#  endif
		strcpy (&label_name[1],c_function_name);
		
		label=enter_label (label_name,EXPORT_LABEL);

# if defined (G_POWER) && defined (MACH_O)
		if (dyld_stub_binding_helper_p_label==NULL)
			dyld_stub_binding_helper_p_label=enter_label ("dyld_stub_binding_helper",IMPORT_LABEL);
# endif
	}
# else
	label=enter_label (c_function_name,EXPORT_LABEL);
# endif
	
	new_label=fast_memory_allocate_type (struct block_label);
	new_label->block_label_label=label;
	new_label->block_label_next=NULL;

	label->label_a_stack_size=0;
	label->label_b_stack_size=0;
	label->label_vector=e_vector;
	label->label_flags |= REGISTERS_ALLOCATED;

	generate_code_for_previous_blocks (0);

	if (last_block->block_instructions!=NULL){
		begin_new_basic_block();
		
		last_block->block_begin_module=1;
		last_block->block_link_module=0;
	} else {
		release_a_stack();
		release_b_stack();
		
		if (!last_block->block_begin_module){
			last_block->block_begin_module=1;
			last_block->block_link_module=0;
		}
	}

	save_registers_before_clean_call();

#if defined (THREAD64) && (defined (LINUX_ELF) || defined (MACH_O64))
	call_pthread_getspecific (n_integer_parameters+n_string_or_array_parameters,n_float_parameters);
#endif

#if defined (G_AI64)
	if (n_string_or_array_parameters!=0){
		int register_n;

		for (i=first_parameter_index,register_n=0; i<colon_index && register_n<4; ++i,++register_n){
			char c;

			c=s[i];
			if (c!='R'){
				i_move_r_id (REGISTER_A0-register_n,(18+1+register_n)<<STACK_ELEMENT_LOG_SIZE,B_STACK_POINTER);
				if (c=='A')
					++i;
			} else
				i_fmove_fr_id (register_n,(18+1+register_n)<<STACK_ELEMENT_LOG_SIZE,B_STACK_POINTER);
		}
	}

	{
		int first_result_pointer_n,n_result_pointers;

		first_result_pointer_n = n_integer_and_float_parameters+n_string_or_array_parameters;
		if (first_result_pointer_n<4){
			int register_n;
			
			n_result_pointers = n_integer_results-integer_c_function_result+
								n_float_results-float_c_function_result+
								n_string_or_array_results-string_or_array_c_function_result;

			for (register_n=first_result_pointer_n; register_n<4 && register_n<first_result_pointer_n+n_result_pointers; ++register_n)
				i_move_r_id (REGISTER_A0-register_n,(18+1+register_n)<<STACK_ELEMENT_LOG_SIZE,B_STACK_POINTER);				
		}
	}
#endif

#if defined (I486)
	if (n_string_or_array_parameters!=0){
		int i,offset;

# ifdef THREAD64
#  if !(defined (LINUX_ELF) || defined (MACH_O64))
		instruction_l_r (ILDTLSP,tlsp_tls_index_label,-4/*R9*/);
#  endif
		i_move_id_r (SAVED_A_STACK_P_OFFSET,-4/*R9*/,A_STACK_POINTER);
		i_move_id_r (SAVED_R15_OFFSET,-4/*R9*/,REGISTER_D7);
		i_move_id_r (SAVED_HEAP_P_OFFSET,-4/*R9*/,-7/*RDI*/);
# endif

# if defined (G_A64)
		offset=((18+1+n_integer_parameters+n_string_or_array_parameters)<<STACK_ELEMENT_LOG_SIZE)+(n_float_parameters<<3);
# else
		offset=24+((n_integer_parameters+n_string_or_array_parameters)<<STACK_ELEMENT_LOG_SIZE)+(n_float_parameters<<3);
# endif
		
		for (i=colon_index-1; i>=first_parameter_index; --i){
			char c;

			c=s[i];
			if (c=='I')
				offset-=STACK_ELEMENT_SIZE;
			else if (c=='R')
				offset-=8;
			else if (c=='S'){
				if (string_to_string_node_label==NULL)
					string_to_string_node_label=enter_label ("string_to_string_node",IMPORT_LABEL);
				offset-=STACK_ELEMENT_SIZE;
				i_move_id_r (offset,B_STACK_POINTER,REGISTER_A0);
				i_jsr_l (string_to_string_node_label,0);
				i_move_r_id (REGISTER_A0,0,A_STACK_POINTER);
				i_add_i_r (STACK_ELEMENT_SIZE,A_STACK_POINTER);
			} else if (c=='i'){
				--i;
				if (int_array_to_node_label==NULL)
					int_array_to_node_label=enter_label ("int_array_to_node",IMPORT_LABEL);
				offset-=STACK_ELEMENT_SIZE;
				i_move_id_r (offset,B_STACK_POINTER,REGISTER_A0);
				i_jsr_l (int_array_to_node_label,0);
				i_move_r_id (REGISTER_A0,0,A_STACK_POINTER);
				i_add_i_r (STACK_ELEMENT_SIZE,A_STACK_POINTER);
			} else if (c=='r'){
				--i;
				if (real_array_to_node_label==NULL)
					real_array_to_node_label=enter_label ("real_array_to_node",IMPORT_LABEL);
				offset-=STACK_ELEMENT_SIZE;
				i_move_id_r (offset,B_STACK_POINTER,REGISTER_A0);
				i_jsr_l (real_array_to_node_label,0);
				i_move_r_id (REGISTER_A0,0,A_STACK_POINTER);
				i_add_i_r (STACK_ELEMENT_SIZE,A_STACK_POINTER);
			} else
				break;
		}
	}
#endif

	if (last_block->block_labels==NULL)
		last_block->block_labels=new_label;
	else
		last_block_label->block_label_next=new_label;
	last_block_label=new_label;

	begin_new_basic_block();

	last_block->block_begin_module=0;
	last_block->block_link_module=1;

	reachable=1;
	
	init_a_stack (0);
	init_b_stack (0,e_vector);

#if defined (I486)
	if (n_string_or_array_parameters!=0){
		int i,offset;

# if defined (G_A64)
		offset=18+1+(n_integer_and_float_parameters+n_string_or_array_parameters-1);
# else
		offset=5+1+(n_integer_and_float_parameters+n_string_or_array_parameters-1);
# endif

		for (i=colon_index-1; i>=first_parameter_index; --i){
			char c;

			c=s[i];
			if (c=='I')
				s_push_b (s_get_b (offset));
			else if (c=='R'){
				s_push_b (s_get_b (offset));
# if !defined (G_A64)
				s_push_b (s_get_b (offset));
# endif
			} else if (c=='S'){
				--offset;
			} else if (c=='i' || c=='r'){
				--i;
				--offset;
			} else
				error ("error in centry");
		}
	} else
#endif
		for (n=0; n<n_integer_and_float_parameters; ++n)
#ifdef G_POWER
			s_push_b (g_g_register (C_PARAMETER_REGISTER_0+((n_integer_parameters-1)-n)));
#else
# ifdef G_AI64
			if (n>=n_integer_and_float_parameters-4){
				int register_n;

				register_n = (n_integer_and_float_parameters-1)-n;
				if (s[first_parameter_index+register_n]!='R')
#  if defined (LINUX_ELF) || defined (MACH_O64)
				{
					switch (register_n){
						case 0: register_n= 2/*R10 was RDI*/; break;
						case 1: register_n= 3/*R11 was RSI*/; break;
						case 2: register_n=-2/*RDX*/; break;
						case 3: register_n=-1/*RCX*/; break;
						case 4: register_n=-3/*R8*/; break;
						case 5:
#   ifndef THREAD64
								register_n=-4/*R9*/;
#   else
								register_n= 4/*R12*/;
#   endif
								break;
						default: error ("error in centry");
					}
					s_push_b (g_g_register (register_n));
				}
#  else
					s_push_b (g_g_register (REGISTER_A0-register_n));
#  endif
				else
					s_push_b (g_fromf (g_fregister (register_n)));
			} else
				s_push_b (s_get_b (18+1+4+(n_integer_and_float_parameters-4-1)));
# else
			s_push_b (s_get_b (5+1+(n_integer_and_float_parameters-1)));
# endif
#endif

	{
	ULONG *vector_p;
	static ULONG small_vector;
	
	if (n_integer_and_float_parameters+1<=SMALL_VECTOR_SIZE){
		small_vector=0;
		vector_p=&small_vector;
	} else {
		int n_ulongs;
		
		n_ulongs=(n_integer_and_float_parameters+1+SMALL_VECTOR_SIZE-1)>>LOG_SMALL_VECTOR_SIZE;
		vector_p=(ULONG*)fast_memory_allocate (n_ulongs * sizeof (ULONG));
		
		for (i=0; i<n_ulongs; ++i)
			vector_p[i]=0;
	}

	if (n_float_parameters!=0){
		int i,offset;

		i=first_parameter_index;
		offset=0;

		while (i<length){
			char c;
			
			c=s[i];
			if (c=='I')
				++offset;
			else if (c=='R'){
				vector_p[offset>>LOG_SMALL_VECTOR_SIZE] |= (1<< (offset & MASK_SMALL_VECTOR_SIZE));
				++offset;
#ifndef G_A64
				vector_p[offset>>LOG_SMALL_VECTOR_SIZE] |= (1<< (offset & MASK_SMALL_VECTOR_SIZE));
				++offset;
#endif
			} else if (c=='S')
				;
			else if (c=='A')
				++i;
			else
				break;
			++i;
		}
	}

#ifdef THREAD64
	block_with_call=last_block;
#endif

	code_d (n_string_or_array_parameters,n_integer_and_float_parameters,vector_p);

#ifdef G_POWER
	load_constant_registers();
	code_jsr_from_c_to_clean (clean_function_label);
#else
	code_jsr (clean_function_label);
#endif

	{
		int result_pointer_parameter_offset,n_data_results_registers,n_float_results_registers,n_string_or_array_results_registers;

#ifdef G_AI64
		result_pointer_parameter_offset=((18+1+4+n_integer_and_float_parameters+n_string_or_array_parameters-4)<<STACK_ELEMENT_LOG_SIZE);
#else
		result_pointer_parameter_offset=20+4+((n_integer_and_float_parameters+n_string_or_array_parameters)<<STACK_ELEMENT_LOG_SIZE);
#endif
		if (n_integer_results-integer_c_function_result>N_DATA_PARAMETER_REGISTERS)
			result_pointer_parameter_offset+=(n_integer_results-integer_c_function_result-N_DATA_PARAMETER_REGISTERS)<<STACK_ELEMENT_LOG_SIZE;
		if (n_float_results-float_c_function_result>N_FLOAT_PARAMETER_REGISTERS)
			result_pointer_parameter_offset+=(n_float_results-float_c_function_result-N_FLOAT_PARAMETER_REGISTERS)<<3;

		n_data_results_registers=n_integer_results;
		if (n_data_results_registers>N_DATA_PARAMETER_REGISTERS)
			n_data_results_registers=N_DATA_PARAMETER_REGISTERS;

		n_float_results_registers=n_float_results;
		if (n_float_results_registers>N_FLOAT_PARAMETER_REGISTERS)
			n_float_results_registers=N_FLOAT_PARAMETER_REGISTERS;

		n_string_or_array_results_registers=n_string_or_array_results;
		if (n_string_or_array_results_registers>N_ADDRESS_PARAMETER_REGISTERS)
			n_string_or_array_results_registers=N_ADDRESS_PARAMETER_REGISTERS;
		
		{
			int i,data_result_n,float_result_n,result_offset,string_or_array_result_n;

			float_result_n=float_c_function_result;
			data_result_n=integer_c_function_result;
			string_or_array_result_n=string_or_array_c_function_result;

			i=first_result_index;
			result_offset=0;

			while (i<length){
				int c;
				
				i_move_id_r (result_pointer_parameter_offset,B_STACK_POINTER,REGISTER_EBP_OR_RBP);
				result_pointer_parameter_offset+=STACK_ELEMENT_SIZE;

				c=s[i];
				if (c=='I'){
					if (data_result_n<n_data_results_registers)
						i_move_r_id (n_data_results_registers-1-data_result_n,0,REGISTER_EBP_OR_RBP);
					else {
						i_move_id_r (result_offset,B_STACK_POINTER,REGISTER_D0+integer_c_function_result);
						i_move_r_id (REGISTER_D0+integer_c_function_result,0,REGISTER_EBP_OR_RBP);
						result_offset+=STACK_ELEMENT_SIZE;
					}
					++data_result_n;
				} else if (c=='R'){
					if (float_result_n<n_float_results_registers)
						i_fmove_fr_id (n_float_results_registers-1-float_result_n,0,REGISTER_EBP_OR_RBP);
					else {
						i_fmove_id_fr (result_offset,B_STACK_POINTER,float_c_function_result);
						i_fmove_fr_id (float_c_function_result,0,REGISTER_EBP_OR_RBP);
						result_offset+=8;
					}
					++float_result_n;
				} else if (c=='S'){
					int reg_n;
					
					if (string_or_array_result_n<n_string_or_array_results_registers)
						reg_n=REGISTER_A0-(n_string_or_array_results_registers-1-string_or_array_result_n);
					else {
						reg_n=REGISTER_A0-string_or_array_c_function_result;
						i_sub_i_r (4,A_STACK_POINTER);
						i_move_id_r (0,A_STACK_POINTER,reg_n);
					}
					i_add_i_r (STACK_ELEMENT_SIZE,reg_n);
					i_move_r_id (reg_n,0,REGISTER_EBP_OR_RBP);
					++string_or_array_result_n;
				} else if (c=='A'){
					int reg_n;
					
					++i;
					if (string_or_array_result_n<n_string_or_array_results_registers)
						reg_n=REGISTER_A0-(n_string_or_array_results_registers-1-string_or_array_result_n);
					else {
						reg_n=REGISTER_A0-string_or_array_c_function_result;
						i_sub_i_r (4,A_STACK_POINTER);
						i_move_id_r (0,A_STACK_POINTER,reg_n);
					}
					i_add_i_r (STACK_ELEMENT_SIZE*3,reg_n);
					i_move_r_id (reg_n,0,REGISTER_EBP_OR_RBP);
					++string_or_array_result_n;
				} else
					error ("error in centry");
				++i;
			}
		}

# if defined (I486) && !defined (G_AI64)
		if (float_parameter_or_result){
			int freg_n;

			for (freg_n=float_c_function_result; freg_n<8; ++freg_n){
		 		i_word_i (0xdd);
				i_word_i (0xc0+freg_n); /* ffree */
			}
		}
# endif
		
		if (n_integer_results>N_DATA_PARAMETER_REGISTERS || n_float_results>N_FLOAT_PARAMETER_REGISTERS){
			int offset;

			if (n_integer_results>N_DATA_PARAMETER_REGISTERS)
				offset=(n_integer_results-N_DATA_PARAMETER_REGISTERS)<<STACK_ELEMENT_LOG_SIZE;
			else
				offset=0;
			if (n_float_results>N_FLOAT_PARAMETER_REGISTERS)
				offset+=(n_float_results-N_FLOAT_PARAMETER_REGISTERS)<<3;
			i_add_i_r (offset,B_STACK_POINTER);
		}

		if (integer_c_function_result){
			if (n_data_results_registers>1)
				i_move_r_r (n_data_results_registers-1,0);
		} else if (string_c_function_result)
			i_lea_id_r (STACK_ELEMENT_SIZE,REGISTER_A0,REGISTER_D0);
		else if (array_c_function_result)
			i_lea_id_r (STACK_ELEMENT_SIZE*3,REGISTER_A0,REGISTER_D0);
	}

	if (!float_c_function_result)
		code_o (0,integer_c_function_result+string_or_array_c_function_result,i_vector);
	else
#ifdef G_A64
		code_o (0,float_c_function_result,r_vector);
#else
		code_o (0,float_c_function_result<<1,r_vector);
#endif

	restore_registers_after_clean_call();

	{
		int b_offset,a_stack_size,b_stack_size;
		
		a_stack_size=0;
		b_stack_size=string_or_array_c_function_result+integer_c_function_result;
#ifdef G_A64
		b_stack_size+=float_c_function_result;
#else
		b_stack_size+=float_c_function_result<<1;
#endif

#if ! (defined (sparc))
		b_offset=0;
#else
		b_offset=4;
#endif
		b_offset+=end_basic_block_with_registers_and_return_b_stack_offset (a_stack_size,b_stack_size,
							float_c_function_result ? r_vector : i_vector,N_ADDRESS_PARAMETER_REGISTERS);

# ifdef THREAD64
		if (n_string_or_array_parameters==0)
			insert_loads_of_r9_rsi_rdi_and_r15_before_call (block_with_call);
# endif

#if ! (defined (sparc) || defined (G_POWER))
		if (b_offset!=0)
			if (b_offset>0)
				i_add_i_r (b_offset,B_STACK_POINTER);
			else
				i_sub_i_r (-b_offset,B_STACK_POINTER);
# ifdef I486
		if (callee_pops_arguments && n_integer_and_float_parameters+n_string_or_array_parameters>0)
			i_rts_i ((n_integer_and_float_parameters+n_string_or_array_parameters)<<2);
		else
# endif
		i_rts();
#else
# ifdef G_POWER
		if (b_offset!=0)
			if (b_offset>0)
				i_add_i_r (b_offset,B_STACK_POINTER);
			else
				i_sub_i_r (-b_offset,B_STACK_POINTER);
		i_rts_c();
# else
		i_rts (b_offset-4,b_offset);
# endif
#endif
		reachable=0;
		
		begin_new_basic_block();
	}

	}
#endif
}

void code_load_i (CleanInt offset)
{
	INSTRUCTION_GRAPH graph_1,graph_2;
	
	graph_1=s_pop_b ();
	graph_2=g_load_id (offset,graph_1);
	
	s_push_b (graph_2);
}

void code_load_si16 (CleanInt offset)
{
	INSTRUCTION_GRAPH graph_1,graph_2;
	
	graph_1=s_pop_b ();
	graph_2=g_load_des_id (offset,graph_1);

	s_push_b (graph_2);
}

#ifdef G_AI64
void code_load_si32 (CleanInt offset)
{
	INSTRUCTION_GRAPH graph_1,graph_2;
	
	graph_1=s_pop_b ();
	graph_2=g_load_sqb_id (offset,graph_1);

	s_push_b (graph_2);
}
#endif

void code_load_ui8 (CleanInt offset)
{
	INSTRUCTION_GRAPH graph_1,graph_2;
	
	graph_1=s_pop_b ();
	graph_2=g_load_b_id (offset,graph_1);

	s_push_b (graph_2);
}

void code_new_int_reducer (char label_name[],int a_offset)
{
	LABEL *reducer_label;
	INSTRUCTION_GRAPH graph_1,graph_2;

#ifdef RESERVE_NEW_REDUCER
	INSTRUCTION_GRAPH graph_3;
	LABEL *node_entry_label;
#endif
	
	if (new_int_reducer_label==NULL)
		new_int_reducer_label=enter_label ("new_int_reducer",IMPORT_LABEL);
	
	reducer_label=enter_label (label_name,0);

	graph_1=s_get_a (a_offset);
	graph_2=g_lea (reducer_label);

#ifdef RESERVE_NEW_REDUCER
	if (EMPTY_label==NULL)
		EMPTY_label=enter_label ("EMPTY",IMPORT_LABEL | DATA_LABEL);
	
	switch (graph_1->instruction_code){
		case GFILL:
			graph_3=graph_1->instruction_parameters[1].p;
			if (graph_3->instruction_code==GLEA){
				node_entry_label=graph_3->instruction_parameters[0].l;
				if (node_entry_label->label_flags & NODE_ENTRY_LABEL){
					char cycle_in_spine_label_n [64];
					LABEL *cycle_label_n;
					int n_arguments;
					
					n_arguments=node_entry_label->label_arity;
					
					sprintf (cycle_in_spine_label_n,"_c%d",n_arguments);
					cycle_label_n=enter_label (cycle_in_spine_label_n,NODE_ENTRY_LABEL | IMPORT_LABEL);
					cycle_label_n->label_arity=n_arguments;
					cycle_label_n->label_descriptor=EMPTY_label;

					graph_1->instruction_parameters[1].p=g_lea (cycle_label_n);
					break;
				}
			}
			graph_3=NULL;
			break;
		case GCREATE:
			graph_3=graph_1->instruction_parameters[0].p;
			if (graph_3->instruction_code==GLEA){
				node_entry_label=graph_3->instruction_parameters[0].l;
				if (node_entry_label->label_flags & NODE_ENTRY_LABEL){
					char cycle_in_spine_label_n [64];
					LABEL *cycle_label_n;
					int n_arguments;
					
					n_arguments=node_entry_label->label_arity;
					
					sprintf (cycle_in_spine_label_n,"_c%d",n_arguments);
					cycle_label_n=enter_label (cycle_in_spine_label_n,NODE_ENTRY_LABEL | IMPORT_LABEL);
					cycle_label_n->label_arity=n_arguments;
					cycle_label_n->label_descriptor=EMPTY_label;

					graph_1->instruction_parameters[0].p=g_lea (cycle_label_n);
					break;
				}
			}
		default:
			graph_3=NULL;
	}

	if (graph_3==NULL)
		error ("error: argument of new_int_reducer is not a closure");
#endif
	
	s_push_a (graph_1);

	s_push_b (NULL);
	s_push_b (graph_2);

#ifdef RESERVE_NEW_REDUCER
	s_push_b (graph_3);
	insert_basic_block (JSR_BLOCK,1,2+1,i_i_i_vector,new_int_reducer_label);
#else
	insert_basic_block (JSR_BLOCK,1,1+1,i_i_vector,new_int_reducer_label);
#endif
}

void code_set_defer (int a_offset)
{
	INSTRUCTION_GRAPH graph_1,graph_2;
	LABEL *node_entry_label;

	if (EMPTY_label==NULL)
		EMPTY_label=enter_label ("EMPTY",IMPORT_LABEL | DATA_LABEL);

	graph_1=s_get_a (a_offset);
	
	switch (graph_1->instruction_code){
		case GFILL:
			graph_2=graph_1->instruction_parameters[1].p;
			if (graph_2->instruction_code==GLEA){
				node_entry_label=graph_2->instruction_parameters[0].l;
				if (node_entry_label->label_flags & NODE_ENTRY_LABEL){
					LABEL *label;
#ifdef RESERVE_NEW_REDUCER
					label=new_local_label (DEFERED_LABEL | NODE_ENTRY_LABEL);
#else
					label=new_local_label (DEFERED_LABEL);
#endif
					label->label_arity=node_entry_label->label_arity;
					label->label_descriptor=node_entry_label;

					graph_1->instruction_parameters[1].p=g_lea (label);
					return;
				}
			}
			break;
		case GCREATE:
			graph_2=graph_1->instruction_parameters[0].p;
			if (graph_2->instruction_code==GLEA){
				node_entry_label=graph_2->instruction_parameters[0].l;
				if (node_entry_label->label_flags & NODE_ENTRY_LABEL){
					LABEL *label;
					
#ifdef RESERVE_NEW_REDUCER
					label=new_local_label (DEFERED_LABEL | NODE_ENTRY_LABEL);
#else
					label=new_local_label (DEFERED_LABEL);
#endif
					label->label_arity=node_entry_label->label_arity;
					label->label_descriptor=node_entry_label;
					
					graph_1->instruction_parameters[0].p=g_lea (label);
					return;
				}
			}
	}

	error ("error: argument of set_defer is not a closure");
}

void code_channelP (int a_offset)
{
	INSTRUCTION_GRAPH graph_1;
		
	if (channelP_label==NULL)
		channelP_label=enter_label ("channelP",IMPORT_LABEL);

	graph_1=s_get_a (a_offset);
	
	s_push_a (graph_1);
	s_push_b (NULL);
	insert_basic_block (JSR_BLOCK,1,0+1,i_vector,channelP_label);
		
	init_b_stack (1,i_vector);
}

void code_stop_reducer (VOID)
{
	if (stop_reducer_label==NULL)
		stop_reducer_label=enter_label ("stop_reducer",IMPORT_LABEL);

	end_basic_block_with_registers (0,0,e_vector);

	i_jmp_l (stop_reducer_label,0);

	reachable=0;

	begin_new_basic_block();	
}

void code_send_graph (char descriptor_name[],int a_offset_1,int a_offset_2)
{
	INSTRUCTION_GRAPH graph_1,graph_2,graph_3;
	LABEL *descriptor_label;

	if (send_graph_label==NULL)
		send_graph_label=enter_label ("send_graph",IMPORT_LABEL);

	descriptor_label=enter_label (descriptor_name,0);

	graph_1=g_lea (descriptor_label);
	graph_2=s_get_a (a_offset_1);
	graph_3=s_get_a (a_offset_2);

	s_push_a (graph_2);
	s_push_a (graph_3);

	s_push_b (NULL);
	s_push_b (graph_1);
	insert_basic_block (JSR_BLOCK,2,1+1,i_i_vector,send_graph_label);
}

void code_send_request (int a_offset)
{
	INSTRUCTION_GRAPH graph_1;
	
	if (send_request_label==NULL)
		send_request_label=enter_label ("send_request",IMPORT_LABEL);
	
	graph_1=s_get_a (a_offset);
	
	s_push_a (graph_1);
	
	s_push_b (NULL);
	insert_basic_block (JSR_BLOCK,1,0+1,e_vector,send_request_label);
}

void code_set_continue (int a_offset)
{
	LABEL *reducer_label;
	INSTRUCTION_GRAPH graph_1,graph_2;
	
	if (new_int_reducer_label==NULL)
		new_int_reducer_label=enter_label ("new_int_reducer",IMPORT_LABEL);
	
	reducer_label=enter_label ("__nf__reducer",0);
	
	graph_1=s_get_a (a_offset);
	graph_2=g_lea (reducer_label);
	
	s_push_a (graph_1);
	
	s_push_b (NULL);
	s_push_b (graph_2);
	
	insert_basic_block (JSR_BLOCK,1,1+1,i_i_vector,new_int_reducer_label);
}

void code_copy_graph (int a_offset)
{
	INSTRUCTION_GRAPH graph_1;
	
	if (copy_graph_label==NULL)
		copy_graph_label=enter_label ("copy_graph",IMPORT_LABEL);
	
	graph_1=s_get_a (a_offset);
	s_push_a (graph_1);

	s_push_b (NULL);
	insert_basic_block (JSR_BLOCK,1,0+1,e_vector,copy_graph_label);
	
	init_a_stack (1);
}

void code_create_channel (char *label_name)
{
	INSTRUCTION_GRAPH graph_1,graph_2;
	LABEL *label;
	
	if (CHANNEL_label==NULL)
		CHANNEL_label=enter_label ("CHANNEL",DATA_LABEL);
	if (create_channel_label==NULL)
		create_channel_label=enter_label ("create_channel",IMPORT_LABEL);
	
	label=enter_label (label_name,NODE_ENTRY_LABEL);
	label->label_arity=1;
	label->label_descriptor=CHANNEL_label;
	
	graph_1=s_pop_b();
	graph_2=g_lea (label);

	s_push_b (NULL);
	s_push_b (graph_1);
	s_push_b (graph_2);
	
	insert_basic_block (JSR_BLOCK,0,2+1,i_i_i_vector,create_channel_label);
	
	init_a_stack (1);
}

void code_currentP (void)
{
	if (currentP_label==NULL)
		currentP_label=enter_label ("currentP",IMPORT_LABEL);

	s_push_b (NULL);
	insert_basic_block (JSR_BLOCK,0,0+1,i_vector,currentP_label);
		
	init_b_stack (1,i_vector);
}

void code_new_ext_reducer (char descriptor_name[],int a_offset)
{
#pragma unused (descriptor_name,a_offset)
/*
	LABEL *descriptor_label;
	INSTRUCTION_GRAPH graph_1,graph_2;
	
	if (new_ext_reducer_label==NULL)
		new_ext_reducer_label=enter_label ("new_ext_reducer",IMPORT_LABEL);
	
	descriptor_label=enter_label (descriptor_name,0);
	
	graph_1=s_get_a (a_offset);
	graph_2=g_lea (descriptor_label);

	s_push_a (graph_1);
	
	s_push_b (NULL);
	s_push_b (graph_2);
		
	insert_basic_block (JSR_BLOCK,1,1+1,i_i_vector,new_ext_reducer_label);
*/
}

void code_newP (void)
{
	if (newP_label==NULL)
		newP_label=enter_label ("newP",IMPORT_LABEL);

	s_push_b (NULL);
	insert_basic_block (JSR_BLOCK,0,0+1,i_vector,newP_label);
		
	init_b_stack (1,i_vector);
}

void code_parallel (VOID)
{
}

void code_pause (VOID)
{
	error ("ABC instruction 'pause' not implemented");
}

void code_randomP (void)
{
	if (randomP_label==NULL)
		randomP_label=enter_label ("randomP",IMPORT_LABEL);

	s_push_b (NULL);
	insert_basic_block (JSR_BLOCK,0,0+1,i_vector,randomP_label);
		
	init_b_stack (1,i_vector);
}

void code_suspend (VOID)
{
	if (suspend_label==NULL)
		suspend_label=enter_label ("suspend",IMPORT_LABEL);

	s_push_b (NULL);
	insert_basic_block (JSR_BLOCK,0,0+1,i_vector,suspend_label);
}

void code_add_args (int source_offset,int n_arguments,int destination_offset)
{
#	pragma unused (source_offset,n_arguments,destination_offset)

	error ("ABC instruction 'add_args' not implemented");
}

void code_dummy (VOID)
{
}

extern LABEL *cat_string_label;

void code_catS (int source_offset_1,int source_offset_2,int destination_offset)
{
	INSTRUCTION_GRAPH graph_1,graph_2,graph_3;
	
	if (cat_string_label==NULL)
		cat_string_label=enter_label ("cat_string",IMPORT_LABEL);
	
	graph_1=s_get_a (source_offset_1);
	graph_2=s_get_a (source_offset_2);
	graph_3=s_get_a (destination_offset);
	
	s_push_a (graph_3);
	s_push_a (graph_2);
	s_push_a (graph_1);

	s_push_b (NULL);

	insert_basic_block (JSR_BLOCK,3,0+1,e_vector,cat_string_label);
}

void init_cginstructions (void)
{
	if (check_stack){
		if (parallel_flag){
			realloc_0_label=enter_label ("realloc_0",IMPORT_LABEL);
			realloc_1_label=enter_label ("realloc_1",IMPORT_LABEL);
			realloc_2_label=enter_label ("realloc_2",IMPORT_LABEL);
			realloc_3_label=enter_label ("realloc_3",IMPORT_LABEL);
		} else {
			stack_overflow_label=enter_label ("stack_overflow",IMPORT_LABEL);
			stack_overflow_label->label_id=next_label_id++;
		}
#ifdef SEPARATE_A_AND_B_STACK_OVERFLOW_CHECKS
			end_a_stack_label=enter_label ("end_a_stack",IMPORT_LABEL);
			end_a_stack_label->label_id=next_label_id++;
			end_b_stack_label=enter_label ("end_b_stack",IMPORT_LABEL);
			end_b_stack_label->label_id=next_label_id++;
#endif
	}

	if (parallel_flag){
		schedule_0_label=enter_label ("schedule_0",IMPORT_LABEL);
		schedule_1_label=enter_label ("schedule_1",IMPORT_LABEL);
		schedule_2_label=enter_label ("schedule_2",IMPORT_LABEL);
		schedule_3_label=enter_label ("schedule_3",IMPORT_LABEL);
		schedule_eval_label=enter_label ("schedule_eval",IMPORT_LABEL);
	}

	profile_function_label=NULL;
	profile_flag=PROFILE_NORMAL;

#if defined (G_POWER) || defined (I486)
	profile_l_label=NULL;
	profile_l2_label=NULL;
	profile_n_label=NULL;
	profile_n2_label=NULL;
	profile_s_label=NULL;
	profile_s2_label=NULL;
	profile_r_label=NULL;
	profile_t_label=NULL;
# ifdef G_POWER
	profile_ti_label=NULL;
# endif
#endif
#if (defined (I486) && !defined (THREAD64)) || defined (G_POWER)
	saved_heap_p_label=NULL;
	saved_a_stack_p_label=NULL;
#endif
#ifdef MACH_O
	dyld_stub_binding_helper_p_label=NULL;
#endif
}