#ifdef ANDROID
# define SOFT_FP_CC
#endif
#define NO_REG_OR_PAD 128
#define PAD_4_AFTER 129
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 c_offset,c_register_parameter_n,c_register_pair_parameter_n,c_parameter_offset;
#ifndef SOFT_FP_CC
int c_fp_register_parameter_n;
#endif
int c_parameter_padding;
int previous_word_l;
unsigned char reg_or_pad[100]; /* 128 = no_reg_or_pad, <128 = reg number, 129 = pad 4 bytes after */
function_address_parameter=0;
if (length>100)
error_s (ccall_error_string,c_function_name);
for (l=0; l<length; ++l)
reg_or_pad[l] = NO_REG_OR_PAD;
if (*s=='G'){
++s;
--length;
save_state_in_global_variables=1;
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);
} else
save_state_in_global_variables=0;
if (*s=='P'){
++s;
--length;
callee_pops_arguments=1;
} else
callee_pops_arguments=0;
float_parameters=0;
a_offset=0;
b_offset=0;
n_clean_b_register_parameters=0;
c_register_parameter_n=0;
c_register_pair_parameter_n=0;
c_parameter_offset = 0;
c_parameter_padding = 0;
#ifndef SOFT_FP_CC
c_fp_register_parameter_n=0;
#endif
previous_word_l = -1;
for (l=0; l<length; ++l){
switch (s[l]){
case '-':
case ':':
min_index=l;
break;
case 'I':
case 'p':
if (c_register_parameter_n<4){
reg_or_pad[l] = c_register_parameter_n;
if (c_register_parameter_n>=c_register_pair_parameter_n)
++c_register_parameter_n;
else
c_register_parameter_n=c_register_pair_parameter_n+2;
} else {
previous_word_l = l;
c_parameter_offset+=STACK_ELEMENT_SIZE;
}
b_offset+=STACK_ELEMENT_SIZE;
if (!float_parameters)
++n_clean_b_register_parameters;
continue;
case 'r':
if (c_register_parameter_n<4){
reg_or_pad[l] = c_register_parameter_n;
if (c_register_parameter_n>=c_register_pair_parameter_n)
++c_register_parameter_n;
else
c_register_parameter_n=c_register_pair_parameter_n;
} else {
previous_word_l = l;
c_parameter_offset+=STACK_ELEMENT_SIZE;
}
float_parameters=1;
b_offset+=8;
continue;
case 'R':
float_parameters=1;
b_offset+=8;
#ifdef SOFT_FP_CC
if (c_register_parameter_n<4){
if ((c_register_parameter_n & 1)==0){
reg_or_pad[l] = c_register_parameter_n;
c_register_parameter_n+=2;
c_register_pair_parameter_n = c_register_parameter_n;
previous_word_l = -1;
continue;
} else {
if (c_register_pair_parameter_n<=c_register_parameter_n)
c_register_pair_parameter_n = c_register_parameter_n+1;
if (c_register_pair_parameter_n<4){
reg_or_pad[l] = c_register_pair_parameter_n;
c_register_pair_parameter_n+=2;
previous_word_l = -1;
continue;
} else
c_register_parameter_n=4;
}
}
#else
if (c_fp_register_parameter_n<8){
reg_or_pad[l] = c_fp_register_parameter_n++;
continue;
}
#endif
if (c_parameter_offset & 4){
if (previous_word_l<0 || reg_or_pad[previous_word_l]!=NO_REG_OR_PAD)
internal_error_in_function ("code_ccall");
reg_or_pad[previous_word_l]=PAD_4_AFTER;
c_parameter_padding+=4;
c_parameter_offset+=4;
}
c_parameter_offset+=8;
previous_word_l = -1;
continue;
case 'S':
case 's':
case 'A':
if (c_register_parameter_n<4){
reg_or_pad[l] = c_register_parameter_n;
if (c_register_parameter_n>=c_register_pair_parameter_n)
++c_register_parameter_n;
else
c_register_parameter_n=c_register_pair_parameter_n+2;
} else {
previous_word_l = l;
c_parameter_offset+=STACK_ELEMENT_SIZE;
}
a_offset+=STACK_ELEMENT_SIZE;
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);
n_extra_clean_b_register_parameters=0;
for (++l; l<length; ++l){
switch (s[l]){
case 'I':
case 'p':
continue;
case 'R':
float_parameters=1;
continue;
case 'S':
continue;
case 'A':
++l;
if (l<length && (s[l]=='i' || s[l]=='r')){
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)
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);
c_offset=b_offset;
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':
case 'R':
case 'S':
break;
case 'A':
++first_pointer_result_index;
}
}
a_result_offset=0;
b_result_offset=0;
for (l=first_pointer_result_index; l<length; ++l){
switch (s[l]){
case 'I':
case 'p':
if (c_register_parameter_n<4){
reg_or_pad[l] = c_register_parameter_n;
if (c_register_parameter_n>=c_register_pair_parameter_n)
++c_register_parameter_n;
else
c_register_parameter_n=c_register_pair_parameter_n+2;
} else
c_parameter_offset+=STACK_ELEMENT_SIZE;
b_result_offset+=STACK_ELEMENT_SIZE;
continue;
case 'R':
if (c_register_parameter_n<4){
reg_or_pad[l] = c_register_parameter_n;
if (c_register_parameter_n>=c_register_pair_parameter_n)
++c_register_parameter_n;
else
c_register_parameter_n=c_register_pair_parameter_n+2;
} else
c_parameter_offset+=STACK_ELEMENT_SIZE;
b_result_offset+=8;
continue;
case 'S':
if (c_register_parameter_n<4){
reg_or_pad[l] = c_register_parameter_n;
if (c_register_parameter_n>=c_register_pair_parameter_n)
++c_register_parameter_n;
else
c_register_parameter_n=c_register_pair_parameter_n+2;
} else
c_parameter_offset+=STACK_ELEMENT_SIZE;
a_result_offset+=STACK_ELEMENT_SIZE;
continue;
case 'A':
if (c_register_parameter_n<4){
reg_or_pad[l] = c_register_parameter_n;
if (c_register_parameter_n>=c_register_pair_parameter_n)
++c_register_parameter_n;
else
c_register_parameter_n=c_register_pair_parameter_n+2;
} else
c_parameter_offset+=STACK_ELEMENT_SIZE;
++l;
a_result_offset+=STACK_ELEMENT_SIZE;
continue;
}
}
if (!function_address_parameter)
label = enter_c_function_name_label (c_function_name);
{
int c_offset_before_pushing_arguments,function_address_reg,function_address_s_index;
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;
}
c_offset_before_pushing_arguments=c_offset;
i_move_r_r (B_STACK_POINTER,REGISTER_A2);
if (c_parameter_offset & 4){
i_sub_i_r (4,B_STACK_POINTER);
i_or_i_r (4,B_STACK_POINTER);
} else {
i_and_i_r (-8,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 (reg_or_pad[l]<NO_REG_OR_PAD)
i_lea_id_r (b_o+c_offset_before_pushing_arguments,REGISTER_A2,REGISTER_D4-reg_or_pad[l]);
else {
i_lea_id_r (b_o+c_offset_before_pushing_arguments,REGISTER_A2,REGISTER_A3);
i_move_r_pd (REGISTER_A3,B_STACK_POINTER);
c_offset+=STACK_ELEMENT_SIZE;
}
break;
case 'i':
case 'r':
--l;
case 'S':
if (reg_or_pad[l]<NO_REG_OR_PAD)
i_lea_id_r (a_o+c_offset_before_pushing_arguments,REGISTER_A2,REGISTER_D4-reg_or_pad[l]);
else {
i_lea_id_r (a_o+c_offset_before_pushing_arguments,REGISTER_A2,REGISTER_A3);
i_move_r_pd (REGISTER_A3,B_STACK_POINTER);
c_offset+=STACK_ELEMENT_SIZE;
}
a_o+=STACK_ELEMENT_SIZE;
break;
case 'R':
b_o-=8;
if (reg_or_pad[l]<NO_REG_OR_PAD)
i_lea_id_r (b_o+c_offset_before_pushing_arguments,REGISTER_A2,REGISTER_D4-reg_or_pad[l]);
else {
i_lea_id_r (b_o+c_offset_before_pushing_arguments,REGISTER_A2,REGISTER_A3);
i_move_r_pd (REGISTER_A3,B_STACK_POINTER);
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,c_offset_1;
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;
}
c_offset_1=0;
for (l=min_index-1; l>=0; --l){
switch (s[l]){
case 'I':
case 'p':
case 'S':
case 's':
case 'A':
if (reg_or_pad[l]>=NO_REG_OR_PAD){
if (reg_or_pad[l]==PAD_4_AFTER)
c_offset_1+=4;
c_offset_1+=STACK_ELEMENT_SIZE;
}
break;
case 'R':
if (reg_or_pad[l]>=NO_REG_OR_PAD)
c_offset_1+=8;
break;
case 'O':
case 'F':
case '*':
case ']':
while (l>=0 && (s[l]!='F' && s[l]!='O'))
--l;
if (reg_or_pad[l]>=NO_REG_OR_PAD)
c_offset_1+=STACK_ELEMENT_SIZE;
break;
}
}
if (c_offset_1!=0){
i_sub_i_r (c_offset_1,B_STACK_POINTER);
c_offset += c_offset_1;
}
{
int l,c_offset_2,not_finished,new_reg[5];
new_reg[0]=new_reg[1]=new_reg[2]=new_reg[3]=new_reg[4]=-1; /* [0] not used */
c_offset_2 = c_offset_1;
reg_n=0;
for (l=min_index-1; l>=0; --l){
switch (s[l]){
case 'I':
case 'p':
if (reg_or_pad[l]<NO_REG_OR_PAD){
if (l<=last_register_parameter_index){
new_reg [4-reg_or_pad[l]] = n_extra_clean_b_register_parameters+reg_n;
++reg_n;
}
} else {
if (reg_or_pad[l]==PAD_4_AFTER)
c_offset_2-=4;
c_offset_2-=STACK_ELEMENT_SIZE;
if (l<=last_register_parameter_index){
i_move_r_id (REGISTER_D0+n_extra_clean_b_register_parameters+reg_n,c_offset_2,B_STACK_POINTER);
++reg_n;
}
}
break;
case 'S':
case 's':
case 'A':
if (reg_or_pad[l]>=NO_REG_OR_PAD){
if (reg_or_pad[l]==PAD_4_AFTER)
c_offset_2-=4;
c_offset_2-=STACK_ELEMENT_SIZE;
}
break;
case 'R':
if (reg_or_pad[l]>=NO_REG_OR_PAD)
c_offset_2-=8;
break;
case 'O':
case 'F':
case '*':
case ']':
while (l>=0 && (s[l]!='F' && s[l]!='O'))
--l;
if (reg_or_pad[l]<NO_REG_OR_PAD){
if (l<=last_register_parameter_index){
new_reg [4-reg_or_pad[l]] = n_extra_clean_b_register_parameters+reg_n;
++reg_n;
}
}
break;
}
}
do {
not_finished=0;
for (reg_n=1; reg_n<=4; ++reg_n){
int n;
n=new_reg[reg_n];
if (n>=0 && n!=reg_n){
if (new_reg[1]!=reg_n && new_reg[2]!=reg_n && new_reg[3]!=reg_n && new_reg[4]!=reg_n){
i_move_r_r (REGISTER_D0+n,REGISTER_D0+reg_n);
new_reg[reg_n]=-1;
} else
not_finished=1;
}
}
} while (not_finished); /* infinite loop in case of cycle */
}
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 (reg_or_pad[l]<NO_REG_OR_PAD){
if (l<=last_register_parameter_index){
/* i_move_r_r (REGISTER_D0+n_extra_clean_b_register_parameters+reg_n,REGISTER_D4-reg_or_pad[l]); */
++reg_n;
} else {
b_o-=STACK_ELEMENT_SIZE;
i_move_id_r (b_o+c_offset_before_pushing_arguments,REGISTER_A2,REGISTER_D4-reg_or_pad[l]);
}
} else {
if (reg_or_pad[l]==PAD_4_AFTER)
c_offset_1-=4;
c_offset_1-=STACK_ELEMENT_SIZE;
if (l<=last_register_parameter_index){
/* i_move_r_id (REGISTER_D0+n_extra_clean_b_register_parameters+reg_n,c_offset_1,B_STACK_POINTER); */
++reg_n;
} else {
b_o-=STACK_ELEMENT_SIZE;
i_move_id_r (b_o+c_offset_before_pushing_arguments,REGISTER_A2,6/*r12*/);
i_move_r_id (6/*r12*/,c_offset_1,B_STACK_POINTER);
}
}
break;
case 'S':
if (reg_or_pad[l]<NO_REG_OR_PAD){
i_move_id_r (a_o,A_STACK_POINTER,REGISTER_D4-reg_or_pad[l]);
i_add_i_r (STACK_ELEMENT_SIZE,REGISTER_D4-reg_or_pad[l]);
} else {
if (reg_or_pad[l]==PAD_4_AFTER)
c_offset_1-=4;
c_offset_1-=STACK_ELEMENT_SIZE;
i_move_id_r (a_o,A_STACK_POINTER,REGISTER_A0);
i_add_i_r (STACK_ELEMENT_SIZE,REGISTER_A0);
i_move_r_id (REGISTER_A0,c_offset_1,B_STACK_POINTER);
}
a_o+=STACK_ELEMENT_SIZE;
break;
case 'R':
if (reg_or_pad[l]<NO_REG_OR_PAD){
b_o-=8;
#ifdef SOFT_FP_CC
i_move_id_r (b_o+c_offset_before_pushing_arguments,REGISTER_A2,REGISTER_D4-reg_or_pad[l]);
i_move_id_r (b_o+c_offset_before_pushing_arguments+4,REGISTER_A2,REGISTER_D4-(reg_or_pad[l]+1));
#else
i_fmove_id_fr (b_o+c_offset_before_pushing_arguments,REGISTER_A2,reg_or_pad[l]);
#endif
} else {
c_offset_1-=8;
b_o-=8;
i_move_id_r (b_o+c_offset_before_pushing_arguments,REGISTER_A2,6/*r12*/);
i_move_r_id (6/*r12*/,c_offset_1,B_STACK_POINTER);
i_move_id_r (b_o+c_offset_before_pushing_arguments+4,REGISTER_A2,6/*r12*/);
i_move_r_id (6/*r12*/,c_offset_1+4,B_STACK_POINTER);
}
break;
case 's':
if (reg_or_pad[l]<NO_REG_OR_PAD){
i_move_id_r (a_o,A_STACK_POINTER,REGISTER_D4-reg_or_pad[l]);
i_add_i_r (2*STACK_ELEMENT_SIZE,REGISTER_D4-reg_or_pad[l]);
} else {
if (reg_or_pad[l]==PAD_4_AFTER)
c_offset_1-=4;
c_offset_1-=STACK_ELEMENT_SIZE;
i_move_id_r (a_o,A_STACK_POINTER,REGISTER_A0);
i_add_i_r (2*STACK_ELEMENT_SIZE,REGISTER_A0);
i_move_r_id (REGISTER_A0,c_offset_1,B_STACK_POINTER);
}
a_o+=STACK_ELEMENT_SIZE;
break;
case 'A':
if (reg_or_pad[l]<NO_REG_OR_PAD){
i_move_id_r (a_o,A_STACK_POINTER,REGISTER_D4-reg_or_pad[l]);
i_add_i_r (3*STACK_ELEMENT_SIZE,REGISTER_D4-reg_or_pad[l]);
} else {
if (reg_or_pad[l]==PAD_4_AFTER)
c_offset_1-=4;
c_offset_1-=STACK_ELEMENT_SIZE;
i_move_id_r (a_o,A_STACK_POINTER,REGISTER_A0);
i_add_i_r (3*STACK_ELEMENT_SIZE,REGISTER_A0);
i_move_r_id (REGISTER_A0,c_offset_1,B_STACK_POINTER);
}
a_o+=STACK_ELEMENT_SIZE;
break;
case 'O':
case 'F':
case '*':
case ']':
while (l>=0 && (s[l]!='F' && s[l]!='O'))
--l;
if (reg_or_pad[l]<NO_REG_OR_PAD){
if (l<=last_register_parameter_index){
/* i_move_r_r (REGISTER_D0+n_extra_clean_b_register_parameters+reg_n,REGISTER_D4-reg_or_pad[l]); */
++reg_n;
} else {
b_o-=STACK_ELEMENT_SIZE;
i_move_id_r (b_o+c_offset_before_pushing_arguments,REGISTER_A2,REGISTER_D4-reg_or_pad[l]);
}
function_address_reg = REGISTER_D4-reg_or_pad[l];
function_address_s_index = l+1;
break;
}
default:
error_s (ccall_error_string,c_function_name);
}
}
}
if (save_state_in_global_variables){
i_lea_l_i_r (saved_a_stack_p_label,0,REGISTER_D6);
i_move_r_id (A_STACK_POINTER,0,REGISTER_D6);
i_lea_l_i_r (saved_heap_p_label,0,REGISTER_D6);
i_move_r_id (HEAP_POINTER,0,REGISTER_D6);
i_move_r_id (REGISTER_D5,4,REGISTER_D6);
}
if (!function_address_parameter)
i_call_l (label);
else {
int l;
for (l=function_address_s_index; l<length && (s[l]=='*' || s[l]=='['); ++l){
int n;
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,function_address_reg,REGISTER_D6);
function_address_reg = REGISTER_D6;
}
i_call_r (function_address_reg);
}
if (save_state_in_global_variables){
i_lea_l_i_r (saved_a_stack_p_label,0,REGISTER_D6);
i_move_id_r (0,REGISTER_D6,A_STACK_POINTER);
i_lea_l_i_r (saved_heap_p_label,0,REGISTER_D6);
i_move_id_r (0,REGISTER_D6,HEAP_POINTER);
i_move_id_r (4,REGISTER_D6,REGISTER_D5);
}
if (c_offset_before_pushing_arguments-(b_result_offset+a_result_offset)==0)
i_move_r_r (REGISTER_A2,B_STACK_POINTER);
else
i_lea_id_r (c_offset_before_pushing_arguments-(b_result_offset+a_result_offset),REGISTER_A2,B_STACK_POINTER);
}
if (a_offset!=0)
i_sub_i_r (a_offset,A_STACK_POINTER);
for (l=length-1; l>=first_pointer_result_index; --l){
switch (s[l]){
case 'I':
case 'p':
case 'R':
case 'V':
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_idu (string_to_string_node_label,-4);
i_move_r_id (REGISTER_A0,0,A_STACK_POINTER);
i_add_i_r (STACK_ELEMENT_SIZE,A_STACK_POINTER);
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':
case 'p':
b_o+=STACK_ELEMENT_SIZE;
break;
case 'S':
case 'V':
break;
case 'R':
b_o+=8;
break;
default:
error_s (ccall_error_string,c_function_name);
}
}
switch (result){
case 'I':
case 'p':
begin_new_basic_block();
init_b_stack (5,i_i_i_i_i_vector);
s_put_b (4,s_get_b (0));
s_remove_b();
s_remove_b();
s_remove_b();
s_remove_b();
break;
case 'V':
begin_new_basic_block();
break;
case 'R':
begin_new_basic_block();
#ifdef SOFT_FP_CC
init_b_stack (5,i_i_i_i_i_vector);
s_put_b (3,s_get_b (0));
s_put_b (4,s_get_b (1));
s_remove_b();
s_remove_b();
s_remove_b();
#else
init_b_stack (2,r_vector);
#endif
break;
default:
error_s (ccall_error_string,c_function_name);
}
}