diff options
-rw-r--r-- | .gitignore | 2 | ||||
-rw-r--r-- | Makefile.linux_thumb2 | 12 | ||||
-rw-r--r-- | cgthumb2as.c | 5100 | ||||
-rw-r--r-- | cgthumb2as.h | 34 | ||||
-rw-r--r-- | cgthumb2c.c | 753 | ||||
-rw-r--r-- | cgthumb2was.c | 2908 | ||||
-rw-r--r-- | cgthumb2was.h | 25 |
7 files changed, 8834 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..25757a0 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +*.o +cg diff --git a/Makefile.linux_thumb2 b/Makefile.linux_thumb2 new file mode 100644 index 0000000..4f2eaa1 --- /dev/null +++ b/Makefile.linux_thumb2 @@ -0,0 +1,12 @@ +CFLAGS=-DGNU_C -DLINUX -DLINUX_ELF -DARM -DTHUMB2 -O -fomit-frame-pointer
+
+OBJECTS = cg.o cgcalc.o cgcode.o cginput.o cginstructions.o \
+ cglin.o cgopt.o cgthumb2as.o cgthumb2was.o cgstack.o
+
+cg: $(OBJECTS)
+ $(CC) -o $@ -s $(OBJECTS)
+
+cginstructions.o: cgthumb2c.c
+
+clean:
+ $(RM) $(OBJECTS)
diff --git a/cgthumb2as.c b/cgthumb2as.c new file mode 100644 index 0000000..813196f --- /dev/null +++ b/cgthumb2as.c @@ -0,0 +1,5100 @@ +/* + File: cgthumb2as.c + Original file: cgarmas.c + Author: John van Groningen, adapted by Camil Staps for Thumb-2 + Machine: ARM, Thumb-2 encoding +*/ + +#define RELOCATIONS_RELATIVE_TO_EXPORTED_DATA_LABEL + +#include <stdio.h> +#include <string.h> +#include <stdlib.h> + +#ifdef LINUX_ELF +# define ELF +#endif + +#if defined (_WINDOWS_) || defined (ELF) +# define FUNCTION_LEVEL_LINKING +#endif + +#include "cgport.h" + +#include "cgrconst.h" +#include "cgtypes.h" +#include "cg.h" +#include "cgiconst.h" +#include "cgcode.h" +#include "cgarmas.h" +#include "cginstructions.h" + +#define FP_REVERSE_SUB_DIV_OPERANDS 1 + +#ifdef ELF +# include <elf.h> +# ifdef ANDROID +# include <asm/elf.h> +# ifndef EF_ARM_EABI_VER5 +# define EF_ARM_EABI_VER5 0x05000000 +# endif +# endif +# ifndef ELF32_ST_INFO +# define ELF32_ST_INFO(b,t) (((b)<<4)+((t)&0xf)) +# endif +# ifndef ELF32_R_INFO +# define ELF32_R_INFO(s,t) (((s)<<8)+(unsigned char)(t)) +# endif +# ifndef R_ARM_LDR_PC_G0 +/* R_ARM_PC13 */ +# define R_ARM_LDR_PC_G0 4 +# endif +# ifndef R_ARM_CALL +# define R_ARM_CALL 28 +# endif +# ifndef R_ARM_JUMP24 +# define R_ARM_JUMP24 29 +# endif +# ifndef R_ARM_LDC_PC_G0 +# define R_ARM_LDC_PC_G0 67 +# endif +#endif + +#define for_l(v,l,n) for(v=(l);v!=NULL;v=v->n) + +#define U4(s,v1,v2,v3,v4) s->v1;s->v2;s->v3;s->v4 +#define U5(s,v1,v2,v3,v4,v5) s->v1;s->v2;s->v3;s->v4;s->v5 + +#ifdef FUNCTION_LEVEL_LINKING +# define TEXT_LABEL_ID (-2) +# define DATA_LABEL_ID (-3) +#else +# ifdef ELF +# define TEXT_LABEL_ID 1 +# define DATA_LABEL_ID 2 +# else +# define TEXT_LABEL_ID 0 +# define DATA_LABEL_ID 2 +# endif +#endif + +#define IO_BUFFER_SIZE 8192 +#define BUFFER_SIZE 4096 + +#define CODE_CONTROL_SECTION 0 +#define DATA_CONTROL_SECTION 1 +#define IMPORTED_LABEL 2 +#define EXPORTED_CODE_LABEL 3 +#define EXPORTED_DATA_LABEL 4 + +struct object_label { + struct object_label * next; + union { + unsigned long offset; /* CODE_CONTROL_SECTION,DATA_CONTROL_SECTION */ + struct label * label; /* IMPORTED_LABEL,EXPORTED_CODE_LABEL */ + } object_label_u1; + union { + unsigned long length; /* CODE_CONTROL_SECTION,DATA_CONTROL_SECTION */ + unsigned long string_offset; /* IMPORTED_LABEL,EXPORTED_CODE_LABEL */ + } object_label_u2; + int object_label_number; +#ifdef FUNCTION_LEVEL_LINKING + int object_label_n_relocations; /* CODE_CONTROL_SECTION,DATA_CONTROL_SECTION */ + short object_label_section_n; /* CODE_CONTROL_SECTION,DATA_CONTROL_SECTION */ +#endif + unsigned char object_label_kind; + unsigned char object_section_align8; +}; + +#define object_label_offset object_label_u1.offset +#define object_label_label object_label_u1.label + +#define object_label_length object_label_u2.length +#define object_label_string_offset object_label_u2.string_offset + +static struct object_label *first_object_label,**last_object_label_l; + +struct object_buffer { + struct object_buffer *next; + int size; + unsigned char data [BUFFER_SIZE]; +}; + +static struct object_buffer *first_code_buffer,*current_code_buffer; +static int code_buffer_free,code_buffer_offset; +static unsigned char *code_buffer_p; + +static struct object_buffer *first_data_buffer,*current_data_buffer; +static int data_buffer_free,data_buffer_offset; +static unsigned char *data_buffer_p; + +static void initialize_buffers (void) +{ + struct object_buffer *new_code_buffer,*new_data_buffer; + + new_code_buffer=memory_allocate (sizeof (struct object_buffer)); + + new_code_buffer->size=0; + new_code_buffer->next=NULL; + + first_code_buffer=new_code_buffer; + current_code_buffer=new_code_buffer; + code_buffer_offset=0; + + code_buffer_free=BUFFER_SIZE; + code_buffer_p=(void*)new_code_buffer->data; + + new_data_buffer=memory_allocate (sizeof (struct object_buffer)); + + new_data_buffer->size=0; + new_data_buffer->next=NULL; + + first_data_buffer=new_data_buffer; + current_data_buffer=new_data_buffer; + data_buffer_offset=0; + + data_buffer_free=BUFFER_SIZE; + data_buffer_p=new_data_buffer->data; +} + +static FILE *output_file; + +static void write_c (int c) +{ + fputc (c,output_file); +} + +static void write_w (int c) +{ + fputc (c,output_file); + fputc (c>>8,output_file); +} + +static void write_l (int c) +{ + fputc (c,output_file); + fputc (c>>8,output_file); + fputc (c>>16,output_file); + fputc (c>>24,output_file); +} + +#define LONG_WORD_RELOCATION 0 +#define CALL_RELOCATION 1 +#define BRANCH_RELOCATION 2 +#define JUMP_RELOCATION 3 +#define DUMMY_BRANCH_RELOCATION 4 +#define LDR_OFFSET_RELOCATION 5 /* R_ARM_LDR_PC_G0 */ +#define VLDR_OFFSET_RELOCATION 6 /* R_ARM_LDC_PC_G0 */ +#define RELATIVE_LONG_WORD_RELOCATION 7 + +struct relocation { + struct relocation * next; + unsigned long relocation_offset; + union { + struct { + WORD s_align1; + WORD s_align2; + } u_s; + struct label * u_label; + } relocation_u; +#ifdef FUNCTION_LEVEL_LINKING + struct object_label * relocation_object_label; +#endif + short relocation_kind; +}; + +#define relocation_label relocation_u.u_label +#define relocation_align1 relocation_u.u_s.s_align1 +#define relocation_align2 relocation_u.u_s.s_align2 + +static void write_buffers_and_release_memory (struct object_buffer **first_buffer_l) +{ + struct object_buffer *buffer,*next_buffer; + + for (buffer=*first_buffer_l; buffer!=NULL; buffer=next_buffer){ + int size; + + size=buffer->size; + + if (fwrite (buffer->data,1,size,output_file)!=size) + error ("Write error"); + + next_buffer=buffer->next; + + memory_free (buffer); + } + + *first_buffer_l=NULL; +} + +static struct relocation *first_code_relocation,**last_code_relocation_l; +static struct relocation *first_data_relocation,**last_data_relocation_l; +static int n_code_relocations,n_data_relocations; + +static int n_object_labels; + +static unsigned long string_table_offset; + +static struct object_label *code_object_label,*data_object_label; +#ifdef FUNCTION_LEVEL_LINKING +static int n_code_sections,n_data_sections; +#endif + +struct call_and_jump { + struct call_and_jump *cj_next; + struct label *cj_call_label; + struct label cj_label; + struct label cj_jump; +}; + +static struct call_and_jump *first_call_and_jump,*last_call_and_jump; + +struct mapping_symbol { + struct mapping_symbol *ms_next; + unsigned long ms_data_offset; + unsigned long ms_code_offset; +}; + +static struct mapping_symbol *first_mapping_symbol,*last_mapping_symbol; +int n_mapping_symbols; /* not length of struct mapping_symbol list */ +unsigned long end_code_offset; + +void initialize_assembler (FILE *output_file_d) +{ + output_file=output_file_d; +#ifdef ELF + n_object_labels=1; +#else + n_object_labels=0; +#endif + setvbuf (output_file,NULL,_IOFBF,IO_BUFFER_SIZE); + + first_object_label=NULL; + last_object_label_l=&first_object_label; + + first_code_relocation=NULL; + first_data_relocation=NULL; + last_code_relocation_l=&first_code_relocation; + last_data_relocation_l=&first_data_relocation; + n_code_relocations=0; + n_data_relocations=0; + + first_call_and_jump=NULL; + first_mapping_symbol=NULL; + n_mapping_symbols=0; +#ifdef ELF +# ifndef FUNCTION_LEVEL_LINKING + string_table_offset=13; +# else + string_table_offset=7; +# endif +#else + string_table_offset=4; +#endif + initialize_buffers(); + +#ifdef FUNCTION_LEVEL_LINKING + code_object_label=NULL; + n_code_sections=0; + + data_object_label=NULL; + n_data_sections=0; +#else + code_object_label=fast_memory_allocate_type (struct object_label); +# ifdef ELF + ++n_object_labels; +# else + n_object_labels+=2; +# endif + *last_object_label_l=code_object_label; + last_object_label_l=&code_object_label->next; + code_object_label->next=NULL; + + code_object_label->object_label_offset=0; + code_object_label->object_label_length=0; + code_object_label->object_label_kind=CODE_CONTROL_SECTION; + + data_object_label=fast_memory_allocate_type (struct object_label); +# ifdef ELF + ++n_object_labels; +# else + n_object_labels+=2; +# endif + *last_object_label_l=data_object_label; + last_object_label_l=&data_object_label->next; + data_object_label->next=NULL; + + data_object_label->object_label_offset=0; + data_object_label->object_label_length=0; + data_object_label->object_label_kind=DATA_CONTROL_SECTION; + data_object_label->object_section_align8=0; +#endif +} + +#define MAX_LITERAL_INSTRUCTION_OFFSET 4092 + +static unsigned long literal_table_at_offset; +static unsigned char *literal_table_at_buffer_p; + +static void write_branch_and_literals (void); + +static void store_c (int c) +{ + if (code_buffer_free>0){ + --code_buffer_free; + *code_buffer_p++=c; + } else { + struct object_buffer *new_buffer; + + current_code_buffer->size=BUFFER_SIZE; + + new_buffer=memory_allocate (sizeof (struct object_buffer)); + + new_buffer->size=0; + new_buffer->next=NULL; + + current_code_buffer->next=new_buffer; + current_code_buffer=new_buffer; + code_buffer_offset+=BUFFER_SIZE; + + code_buffer_free=BUFFER_SIZE-1; + code_buffer_p=new_buffer->data; + + *code_buffer_p++=c; + + if (literal_table_at_offset-(unsigned long)code_buffer_offset <= (unsigned long) BUFFER_SIZE) + literal_table_at_buffer_p = current_code_buffer->data + (literal_table_at_offset-(unsigned long)code_buffer_offset); + } +} + +static void store_l (ULONG i) +{ + if (code_buffer_p>=literal_table_at_buffer_p) + write_branch_and_literals(); + + store_c (i); + store_c (i>>8); + store_c (i>>16); + store_c (i>>24); +} + +static void store_l_no_literal_table (ULONG i) +{ + store_c (i); + store_c (i>>8); + store_c (i>>16); + store_c (i>>24); +} + +void store_long_word_in_data_section (ULONG c) +{ + if (data_buffer_free>=4){ + data_buffer_free-=4; + *(ULONG*)data_buffer_p=c; + data_buffer_p+=4; + } else { + struct object_buffer *new_buffer; + + current_data_buffer->size=BUFFER_SIZE; + + new_buffer=memory_allocate (sizeof (struct object_buffer)); + + new_buffer->size=0; + new_buffer->next=NULL; + + current_data_buffer->next=new_buffer; + current_data_buffer=new_buffer; + data_buffer_offset+=BUFFER_SIZE; + + data_buffer_free=BUFFER_SIZE-4; + data_buffer_p=(void*)new_buffer->data; + + *(ULONG*)data_buffer_p=c; + data_buffer_p+=4; + } +} + +void store_2_words_in_data_section (UWORD w1,UWORD w2) +{ + store_long_word_in_data_section (((UWORD)w1) | (w2<<16)); +} + +static void flush_code_buffer (void) +{ + current_code_buffer->size=BUFFER_SIZE-code_buffer_free; + code_buffer_offset+=BUFFER_SIZE-code_buffer_free; +} + +static void flush_data_buffer (void) +{ + current_data_buffer->size=BUFFER_SIZE-data_buffer_free; + data_buffer_offset+=BUFFER_SIZE-data_buffer_free; +} + +void store_abc_string_in_data_section (char *string,int length) +{ + unsigned char *string_p; + + string_p=(unsigned char*)string; + store_long_word_in_data_section (length); + + while (length>=4){ + store_long_word_in_data_section (*(ULONG*)string_p); + string_p+=4; + length-=4; + } + + if (length>0){ + ULONG d; + int shift; + + d=0; + shift=0; + while (length>0){ + d |= string_p[0]<<shift; + shift+=8; + --length; + ++string_p; + } + store_long_word_in_data_section (d); + } +} + +void store_c_string_in_data_section (char *string,int length) +{ + unsigned char *string_p; + ULONG d; + int shift; + + string_p=(unsigned char*)string; + + while (length>=4){ + store_long_word_in_data_section (*(ULONG*)string_p); + string_p+=4; + length-=4; + } + + d=0; + shift=0; + while (length>0){ + d |= string_p[0]<<shift; + shift+=8; + --length; + ++string_p; + } + store_long_word_in_data_section (d); +} + +#define CURRENT_CODE_OFFSET (code_buffer_offset+(code_buffer_p-current_code_buffer->data)) +#define CURRENT_DATA_OFFSET (data_buffer_offset+(data_buffer_p-current_data_buffer->data)) + +static void store_label_in_code_section (struct label *label) +{ + struct relocation *new_relocation; + + new_relocation=fast_memory_allocate_type (struct relocation); + ++n_code_relocations; + + *last_code_relocation_l=new_relocation; + last_code_relocation_l=&new_relocation->next; + new_relocation->next=NULL; + + new_relocation->relocation_label=label; + new_relocation->relocation_offset=CURRENT_CODE_OFFSET-4; + new_relocation->relocation_kind=LONG_WORD_RELOCATION; +} + +static void store_relative_label_in_code_section (struct label *label) +{ + struct relocation *new_relocation; + + new_relocation=fast_memory_allocate_type (struct relocation); + ++n_code_relocations; + + *last_code_relocation_l=new_relocation; + last_code_relocation_l=&new_relocation->next; + new_relocation->next=NULL; + + new_relocation->relocation_label=label; + new_relocation->relocation_offset=CURRENT_CODE_OFFSET-4; + new_relocation->relocation_kind=RELATIVE_LONG_WORD_RELOCATION; +} + +struct literal_entry { + LABEL * le_label; + int le_offset; + DOUBLE * le_r_p; + struct label le_load_instruction_label; + struct literal_entry * le_next; +}; + +struct literal_entry *first_literal_entry,**literal_entry_l; + +static void begin_data_mapping (void) +{ + unsigned long current_code_offset; + struct mapping_symbol *new_mapping_symbol; + + current_code_offset = CURRENT_CODE_OFFSET; + + if (! (first_mapping_symbol!=NULL && last_mapping_symbol->ms_code_offset==current_code_offset && last_mapping_symbol->ms_data_offset>=current_code_offset)){ + if (code_object_label->object_label_offset==current_code_offset) + n_mapping_symbols+=1; /* $d at begin of section, $a */ + else + n_mapping_symbols+=2; /* $d and $a */ + + new_mapping_symbol = allocate_memory_from_heap (sizeof (struct mapping_symbol)); + new_mapping_symbol->ms_next = NULL; + new_mapping_symbol->ms_data_offset = current_code_offset; + + if (first_mapping_symbol==NULL) + first_mapping_symbol = new_mapping_symbol; + else + last_mapping_symbol->ms_next = new_mapping_symbol; + last_mapping_symbol = new_mapping_symbol; + } +} + +static void write_literals (void) +{ + struct literal_entry *literal_entry; + + literal_entry=first_literal_entry; + + if (literal_entry!=NULL){ + begin_data_mapping(); + + for (; literal_entry!=NULL; literal_entry=literal_entry->le_next){ + unsigned long load_data_offset,current_code_offset; + + load_data_offset = literal_entry->le_load_instruction_label.label_offset; + current_code_offset = CURRENT_CODE_OFFSET; + + literal_entry->le_load_instruction_label.label_flags=0; + literal_entry->le_load_instruction_label.label_id=TEXT_LABEL_ID; +#ifdef FUNCTION_LEVEL_LINKING + literal_entry->le_load_instruction_label.label_object_label=code_object_label; +#endif + literal_entry->le_load_instruction_label.label_offset=current_code_offset; + + if (literal_entry->le_label){ + literal_entry->le_label->label_flags &= ~HAS_LITERAL_ENTRY; + if (!pic_flag){ + store_l_no_literal_table (literal_entry->le_offset); + store_label_in_code_section (literal_entry->le_label); + } else { + store_l_no_literal_table (current_code_offset - load_data_offset -12 + literal_entry->le_offset); + store_relative_label_in_code_section (literal_entry->le_label); + } + } else { + if (literal_entry->le_r_p==NULL){ + store_l_no_literal_table (literal_entry->le_offset); + } else { + // to do: align 8 + store_l_no_literal_table (((LONG*)(literal_entry->le_r_p))[0]); + store_l_no_literal_table (((LONG*)(literal_entry->le_r_p))[1]); + } + } + } + + literal_entry_l=&first_literal_entry; + first_literal_entry=NULL; + + last_mapping_symbol->ms_code_offset = CURRENT_CODE_OFFSET; + } + + literal_table_at_offset = 0ul-1ul; + literal_table_at_buffer_p = (unsigned char*)0ul-1ul; +} + +static void as_branch_label (struct label *label,int relocation_kind) +{ + struct relocation *new_relocation; + + new_relocation=fast_memory_allocate_type (struct relocation); + + *last_code_relocation_l=new_relocation; + last_code_relocation_l=&new_relocation->next; + new_relocation->next=NULL; + + new_relocation->relocation_label=label; + new_relocation->relocation_offset=CURRENT_CODE_OFFSET-4; +#ifdef FUNCTION_LEVEL_LINKING + new_relocation->relocation_object_label=code_object_label; +#endif + new_relocation->relocation_kind=relocation_kind; +} + +static void write_branch_and_literals (void) +{ + LABEL *new_label; + + literal_table_at_offset = 0ul-1ul; + literal_table_at_buffer_p = (unsigned char*)0ul-1ul; + + new_label=allocate_memory_from_heap (sizeof (struct label)); + + store_l (0xea000000); /* b */ + as_branch_label (new_label,JUMP_RELOCATION); + + write_literals(); + + new_label->label_flags=0; + new_label->label_id=TEXT_LABEL_ID; +#ifdef FUNCTION_LEVEL_LINKING + new_label->label_object_label=code_object_label; +#endif + new_label->label_offset=CURRENT_CODE_OFFSET; +} + +static void as_literal_label (struct label *label,int relocation_kind) +{ + struct relocation *new_relocation; + unsigned long current_code_offset; + + new_relocation=fast_memory_allocate_type (struct relocation); + + *last_code_relocation_l=new_relocation; + last_code_relocation_l=&new_relocation->next; + new_relocation->next=NULL; + + current_code_offset = CURRENT_CODE_OFFSET-4; + + if (current_code_offset+MAX_LITERAL_INSTRUCTION_OFFSET < literal_table_at_offset){ + literal_table_at_offset = current_code_offset+MAX_LITERAL_INSTRUCTION_OFFSET; + + if (literal_table_at_offset-(unsigned long)code_buffer_offset <= (unsigned long) BUFFER_SIZE) + literal_table_at_buffer_p = current_code_buffer->data + (literal_table_at_offset-(unsigned long)code_buffer_offset); + } + + new_relocation->relocation_label=label; + new_relocation->relocation_offset=current_code_offset; + label->label_offset=current_code_offset; /* for pic store offset of load instead, label offset stored by write_literals */ +#ifdef FUNCTION_LEVEL_LINKING + new_relocation->relocation_object_label=code_object_label; +#endif + new_relocation->relocation_kind=relocation_kind; +} + +static void as_literal_constant_entry (int offset) +{ + struct literal_entry *new_literal_entry; + + new_literal_entry=allocate_memory_from_heap (sizeof (struct literal_entry)); + + new_literal_entry->le_label=NULL; + new_literal_entry->le_offset=offset; + new_literal_entry->le_r_p=NULL; + + *literal_entry_l=new_literal_entry; + literal_entry_l=&new_literal_entry->le_next; + + new_literal_entry->le_next=NULL; + + as_literal_label (&new_literal_entry->le_load_instruction_label,LDR_OFFSET_RELOCATION); +} + +static void as_literal_label_entry (LABEL *label,int offset) +{ + struct literal_entry *new_literal_entry; + + if (label->label_flags & HAS_LITERAL_ENTRY && label->label_literal_entry->le_offset==offset) + new_literal_entry=label->label_literal_entry; + else { + new_literal_entry=allocate_memory_from_heap (sizeof (struct literal_entry)); + + new_literal_entry->le_label=label; + new_literal_entry->le_offset=offset; + new_literal_entry->le_r_p=NULL; + + *literal_entry_l=new_literal_entry; + literal_entry_l=&new_literal_entry->le_next; + + new_literal_entry->le_next=NULL; + + if (!pic_flag){ + label->label_flags |= HAS_LITERAL_ENTRY; + label->label_literal_entry=new_literal_entry; + } + } + + as_literal_label (&new_literal_entry->le_load_instruction_label,LDR_OFFSET_RELOCATION); +} + +static void as_float_load_int_literal_entry (int offset) +{ + struct literal_entry *new_literal_entry; + + new_literal_entry=allocate_memory_from_heap (sizeof (struct literal_entry)); + + new_literal_entry->le_label=NULL; + new_literal_entry->le_offset=offset; + new_literal_entry->le_r_p=NULL; + + *literal_entry_l=new_literal_entry; + literal_entry_l=&new_literal_entry->le_next; + + new_literal_entry->le_next=NULL; + + as_literal_label (&new_literal_entry->le_load_instruction_label,VLDR_OFFSET_RELOCATION); +} + +static void as_float_literal_entry (DOUBLE *r_p) +{ + struct literal_entry *new_literal_entry; + + new_literal_entry=allocate_memory_from_heap (sizeof (struct literal_entry)); + + new_literal_entry->le_r_p=r_p; + new_literal_entry->le_label=NULL; + new_literal_entry->le_offset=0; + + *literal_entry_l=new_literal_entry; + literal_entry_l=&new_literal_entry->le_next; + + new_literal_entry->le_next=NULL; + + as_literal_label (&new_literal_entry->le_load_instruction_label,VLDR_OFFSET_RELOCATION); +} + +#ifdef FUNCTION_LEVEL_LINKING +void as_new_data_module (void) +{ + struct object_label *new_object_label; + unsigned long current_data_offset; + int data_section_label_number; + + new_object_label=fast_memory_allocate_type (struct object_label); + data_object_label=new_object_label; + +# ifdef ELF + data_section_label_number=0; +# else + data_section_label_number=n_object_labels; + n_object_labels+=2; +# endif + current_data_offset=CURRENT_DATA_OFFSET; + + *last_object_label_l=new_object_label; + last_object_label_l=&new_object_label->next; + new_object_label->next=NULL; + + new_object_label->object_label_offset=current_data_offset; + new_object_label->object_label_number=data_section_label_number; + new_object_label->object_label_section_n=n_data_sections; + ++n_data_sections; + new_object_label->object_label_length=0; + new_object_label->object_label_kind=DATA_CONTROL_SECTION; + new_object_label->object_section_align8=0; +} + +static void as_new_code_module (void) +{ + struct object_label *new_object_label; + unsigned long current_code_offset; + int code_section_label_number; + + current_code_offset=CURRENT_CODE_OFFSET; + if (first_mapping_symbol!=NULL && last_mapping_symbol->ms_code_offset==current_code_offset) + --n_mapping_symbols; /* $a at end of section */ + + new_object_label=fast_memory_allocate_type (struct object_label); + code_object_label=new_object_label; + +# ifdef ELF + code_section_label_number=0; +# else + code_section_label_number=n_object_labels; + n_object_labels+=2; +# endif + + *last_object_label_l=new_object_label; + last_object_label_l=&new_object_label->next; + new_object_label->next=NULL; + + new_object_label->object_label_offset=current_code_offset; + new_object_label->object_label_number=code_section_label_number; + new_object_label->object_label_section_n=n_code_sections; + ++n_code_sections; + new_object_label->object_label_length=0; + new_object_label->object_label_kind=CODE_CONTROL_SECTION; + ++n_mapping_symbols; /* $a at begin of section */ +} +#endif + +static void store_label_plus_offset_in_data_section (LABEL *label,int offset) +{ + struct relocation *new_relocation; + + store_long_word_in_data_section (offset); + + new_relocation=fast_memory_allocate_type (struct relocation); + ++n_data_relocations; + + *last_data_relocation_l=new_relocation; + last_data_relocation_l=&new_relocation->next; + new_relocation->next=NULL; + + new_relocation->relocation_label=label; + new_relocation->relocation_offset=CURRENT_DATA_OFFSET-4; + new_relocation->relocation_kind=LONG_WORD_RELOCATION; +} + +#define reg_num(r) (real_reg_num[(r)+7]) + +static unsigned char real_reg_num [16] + = { 13, 10, 9, 11, 8, 7, 6, 4, 3, 2, 1, 0, 5, 12, 14, 15 }; + +#define ESP (-6) +#define EBP (-3) +#define EAX 0 +#define REGISTER_PC 8 +#define REGISTER_R5 5 + +#define REGISTER_S0 6 +#define REGISTER_S1 7 + +static int immediate_shift (unsigned int i) +{ + if ((i & ~0xff)==0) return 0; + if ((i & ~0x3fc)==0) return 2; + if ((i & ~0xff0)==0) return 4; + if ((i & ~0x3fc0)==0) return 6; + if ((i & ~0xff00)==0) return 8; + if ((i & ~0x3fc00)==0) return 10; + if ((i & ~0xff000)==0) return 12; + if ((i & ~0x3fc0000)==0) return 14; + if ((i & ~0xff0000)==0) return 16; + if ((i & ~0x3fc0000)==0) return 18; + if ((i & ~0xff00000)==0) return 20; + if ((i & ~0x3fc00000)==0) return 22; + if ((i & ~0xff000000)==0) return 24; + if ((i & ~0xfc000003)==0) return 26; + if ((i & ~0xf000000f)==0) return 28; + if ((i & ~0xc000003f)==0) return 30; + return -1; +} + +static void store_l_is (int i_code,int i,int shift) +{ + if (shift==0){ + i_code |= i & 255; + } else { + i_code |= (((32-shift)>>1)<<8); + i_code |= (unsigned int)i >> (unsigned int)shift; + if (shift>=24) + i_code |= ((unsigned int)i << (unsigned int)(32-shift)) & 255; + } + store_l (i_code); +} + +static void as_move_i_r (int i,int reg1) +{ + int shift; + + shift = immediate_shift (i); + if (shift>=0) + store_l_is (0xe3a00000 | (reg_num (reg1)<<12),i,shift); /* mov rd,#i<<s */ + else { + shift = immediate_shift (~i); + if (shift>=0) + store_l_is (0xe3e00000 | (reg_num (reg1)<<12),~i,shift); /* mvn rd,#i<<s */ + else { + store_l (0xe59f0000 | (reg_num (reg1)<<12)); /* ldr rt,[pc+imm] */ + as_literal_constant_entry (i); + } + } +} + +static void as_mov_r_r (int s_reg,int d_reg) +{ + int i_code; + + i_code = 0xe1A00000 | (reg_num (d_reg)<<12) | reg_num (s_reg); + + store_l (i_code); +} + +static void as_ldr_id_r (int offset,int sa_reg,int d_reg) +{ + int i_code; + + i_code = 0xe5100000 | (reg_num (sa_reg)<<16) | (reg_num (d_reg)<<12); + + if (offset<0) + i_code |= (-offset) & 0xfff; + else + i_code |= (1<<23) | (offset & 0xfff); + + store_l (i_code); +} + +static void as_ldr_id_r_update (int offset,int sa_reg,int d_reg) +{ + int i_code; + + i_code = 0xe5300000 | (reg_num (sa_reg)<<16) | (reg_num (d_reg)<<12); + + if (offset<0) + i_code |= (-offset) & 0xfff; + else + i_code |= (1<<23) | (offset & 0xfff); + + store_l (i_code); +} + +static void as_ldr_id_r_post_add (int offset,int sa_reg,int d_reg) +{ + int i_code; + + i_code = 0xe4100000 | (reg_num (sa_reg)<<16) | (reg_num (d_reg)<<12); + + if (offset<0) + i_code |= (-offset) & 0xfff; + else + i_code |= (1<<23) | (offset & 0xfff); + + store_l (i_code); +} + +static void as_ldrb_id_r (int offset,int sa_reg,int d_reg) +{ + int i_code; + + i_code = 0xe5500000 | (reg_num (sa_reg)<<16) | (reg_num (d_reg)<<12); + + if (offset<0) + i_code |= (-offset) & 0xfff; + else + i_code |= (1<<23) | (offset & 0xfff); + + store_l (i_code); +} + +static void as_ldrsh_id_r (int offset,int sa_reg,int d_reg) +{ + int i_code; + + i_code = 0xe15000f0 | (reg_num (sa_reg)<<16) | (reg_num (d_reg)<<12); + + if (offset<0) + i_code |= (((-offset)<<4) & 0xf00) | ((-offset) & 0xf); + else + i_code |= (1<<23) | ((offset<<4) & 0xf00) | (offset & 0xf); + + store_l (i_code); +} + +static void as_ldr_ix_r (int reg_n,int reg_m,int shift,int reg_t) +{ + store_l (0xe7900000 | (reg_num (reg_n)<<16) | (reg_num (reg_t)<<12) | (shift<<7) | reg_num (reg_m)); +} + +static void as_ldrb_ix_r (int reg_n,int reg_m,int shift,int reg_t) +{ + store_l (0xe7d00000 | (reg_num (reg_n)<<16) | (reg_num (reg_t)<<12) | (shift<<7) | reg_num (reg_m)); +} + +static void as_subs_is_r_r (int i,int shift,int s_reg,int d_reg) +{ + store_l_is (0xe2500000 | (reg_num (s_reg)<<16) | (reg_num (d_reg)<<12),i,shift); +} + +#define ARM_OP_LSL 0 +#define ARM_OP_LSR 1 +#define ARM_OP_ASR 2 +#define ARM_OP_ROR 3 + +static void as_shift_i_r_r (int shift_op,int i,int reg_m,int reg_d) +{ + store_l (0xe1a00000 | (shift_op<<5) | (reg_num (reg_d)<<12) | (i<<7) | reg_num (reg_m)); +} + +static void as_lsl_i_r_r (int i,int reg_m,int reg_d) +{ + store_l (0xe1a00000 | (ARM_OP_LSL<<5) | (reg_num (reg_d)<<12) | (i<<7) | reg_num (reg_m)); +} + +static void as_lsr_i_r_r (int i,int reg_m,int reg_d) +{ + store_l (0xe1a00000 | (ARM_OP_LSR<<5) | (reg_num (reg_d)<<12) | (i<<7) | reg_num (reg_m)); +} + +static void as_asr_i_r_r (int i,int reg_m,int reg_d) +{ + store_l (0xe1a00000 | (ARM_OP_ASR<<5) | (reg_num (reg_d)<<12) | (i<<7) | reg_num (reg_m)); +} + +static void as_shift_r_r_r (int shift_op,int reg_m,int reg_n,int reg_d) +{ + store_l (0xe1a00010 | (shift_op<<5) | (reg_num (reg_d)<<12) | (reg_num (reg_m)<<8) | reg_num (reg_n)); +} + +static void as_str_r_id (int s_reg,int offset,int da_reg) +{ + int i_code; + + i_code = 0xe5000000 | (reg_num (da_reg)<<16) | (reg_num (s_reg)<<12); + + if (offset<0) + i_code |= (-offset) & 0xfff; + else + i_code |= (1<<23) | (offset & 0xfff); + + store_l (i_code); +} + +static void as_str_r_id_update (int s_reg,int offset,int da_reg) +{ + int i_code; + + i_code = 0xe5200000 | (reg_num (da_reg)<<16) | (reg_num (s_reg)<<12); + + if (offset<0) + i_code |= (-offset) & 0xfff; + else + i_code |= (1<<23) | (offset & 0xfff); + + store_l (i_code); +} + +static void as_str_r_id_post_add (int s_reg,int offset,int da_reg) +{ + int i_code; + + i_code = 0xe4000000 | (reg_num (da_reg)<<16) | (reg_num (s_reg)<<12); + + if (offset<0) + i_code |= (-offset) & 0xfff; + else + i_code |= (1<<23) | (offset & 0xfff); + + store_l (i_code); +} + +static void as_str_r_ix (int reg_t,int reg_n,int reg_m,int shift) +{ + store_l (0xe7800000 | (reg_num (reg_n)<<16) | (reg_num (reg_t)<<12) | (shift<<7) | reg_num (reg_m)); +} + +static void as_strb_r_id (int s_reg,int offset,int da_reg) +{ + int i_code; + + i_code = 0xe5400000 | (reg_num (da_reg)<<16) | (reg_num (s_reg)<<12); + + if (offset<0) + i_code |= (-offset) & 0xfff; + else + i_code |= (1<<23) | (offset & 0xfff); + + store_l (i_code); +} + +static void as_strb_r_ix (int reg_t,int reg_n,int reg_m,int shift) +{ + store_l (0xe7c00000 | (reg_num (reg_n)<<16) | (reg_num (reg_t)<<12) | (shift<<7) | reg_num (reg_m)); +} + +static void as_tst_ir_r (int i,int shift,int reg) +{ + store_l_is (0xe3100000 | (reg_num (reg)<<16),i,shift); +} + +static void as_vldr_r_id (int dreg,int offset,int sa_reg) +{ + int i_code; + + i_code = 0xed100b00 | (reg_num (sa_reg)<<16) | (dreg<<12); + + offset>>=2; + if (offset<0) + i_code |= (-offset) & 0xff; + else + i_code |= (1<<23) | (offset & 0xff); + + store_l (i_code); +} + +static void as_vldr_s_id (int sreg,int offset,int sa_reg) +{ + int i_code; + + i_code = 0xed100a00 | (reg_num (sa_reg)<<16) | (sreg<<12); + + offset>>=2; + if (offset<0) + i_code |= (-offset) & 0xff; + else + i_code |= (1<<23) | (offset & 0xff); + + store_l (i_code); +} + +static void as_vstr_r_id (int dreg,int offset,int da_reg) +{ + int i_code; + + i_code = 0xed000b00 | (reg_num (da_reg)<<16) | (dreg<<12); + + offset>>=2; + if (offset<0) + i_code |= (-offset) & 0xff; + else + i_code |= (1<<23) | (offset & 0xff); + + store_l (i_code); +} + +static void as_vstr_s_id (int sreg,int offset,int da_reg) +{ + int i_code; + + i_code = 0xed000a00 | (reg_num (da_reg)<<16) | (sreg<<12); + + offset>>=2; + if (offset<0) + i_code |= (-offset) & 0xff; + else + i_code |= (1<<23) | (offset & 0xff); + + store_l (i_code); +} + +#define ARM_OP_AND 0 +#define ARM_OP_EOR 1 +#define ARM_OP_SUB 2 +#define ARM_OP_RSB 3 +#define ARM_OP_ADD 4 +#define ARM_OP_ADC 5 +#define ARM_OP_SBC 6 +#define ARM_OP_CMP 10 +#define ARM_OP_CMN 11 +#define ARM_OP_ORR 12 +#define ARM_OP_BIC 14 +#define ARM_OP_MVN 15 + +static void as_op_r_r_r (int op,int reg_m,int reg_n,int reg_d) +{ + store_l (0xe0000000 | (op<<21) | (reg_num (reg_n)<<16) | (reg_num (reg_d)<<12) | reg_num(reg_m)); +} + +static void as_x_op_r_r_r (int x_op,int reg_m,int reg_n,int reg_d) +{ + store_l (0xe0000000 | (x_op<<20) | (reg_num (reg_n)<<16) | (reg_num (reg_d)<<12) | reg_num(reg_m)); +} + +static void as_op_is_r_r (int op,int i,int shift,int s_reg,int d_reg) +{ + store_l_is (0xe2000000 | (op<<21) | (reg_num (s_reg)<<16) | (reg_num (d_reg)<<12),i,shift); +} + +static void as_x_op_is_r_r (int x_op,int i,int shift,int s_reg,int d_reg) +{ + store_l_is (0xe2000000 | (x_op<<20) | (reg_num (s_reg)<<16) | (reg_num (d_reg)<<12),i,shift); +} + +static void as_add_r_r_r (int reg_m,int reg_n,int reg_d) +{ + store_l (0xe0000000 | (ARM_OP_ADD<<21) | (reg_num (reg_n)<<16) | (reg_num (reg_d)<<12) | reg_num (reg_m)); +} + +static void as_add_r_r_r_no_literal_table (int reg_m,int reg_n,int reg_d) +{ + store_l_no_literal_table (0xe0000000 | (ARM_OP_ADD<<21) | (reg_num (reg_n)<<16) | (reg_num (reg_d)<<12) | reg_num (reg_m)); +} + +static void as_add_r_lsl_r_r (int reg_m,int lsl_m,int reg_n,int reg_d) +{ + store_l (0xe0000000 | (ARM_OP_ADD<<21) | (reg_num (reg_n)<<16) | (reg_num (reg_d)<<12) | (lsl_m<<7) | reg_num (reg_m)); +} + +static void as_add_r_lsr_r_r (int reg_m,int lsr_m,int reg_n,int reg_d) +{ + store_l (0xe0000020 | (ARM_OP_ADD<<21) | (reg_num (reg_n)<<16) | (reg_num (reg_d)<<12) | (lsr_m<<7) | reg_num (reg_m)); +} + +static void as_add_r_asr_r_r (int reg_m,int asr_m,int reg_n,int reg_d) +{ + store_l (0xe0000040 | (ARM_OP_ADD<<21) | (reg_num (reg_n)<<16) | (reg_num (reg_d)<<12) | (asr_m<<7) | reg_num (reg_m)); +} + +static void as_add_is_r_r (int i,int shift,int s_reg,int d_reg) +{ + store_l_is (0xe2000000 | (ARM_OP_ADD<<21) | (reg_num (s_reg)<<16) | (reg_num (d_reg)<<12),i,shift); +} + +static void as_add_cc_is_r_r (int cc,int i,int shift,int s_reg,int d_reg) +{ + store_l_is (0x02000000 | (cc<<28) | (ARM_OP_ADD<<21) | (reg_num (s_reg)<<16) | (reg_num (d_reg)<<12),i,shift); +} + +static void as_sub_r_r_r (int reg_m,int reg_n,int reg_d) +{ + store_l (0xe0000000 | (ARM_OP_SUB<<21) | (reg_num (reg_n)<<16) | (reg_num (reg_d)<<12) | reg_num(reg_m)); +} + +static void as_sub_r_lsl_r_r (int reg_m,int lsl_m,int reg_n,int reg_d) +{ + store_l (0xe0000000 | (ARM_OP_SUB<<21) | (reg_num (reg_n)<<16) | (reg_num (reg_d)<<12) | (lsl_m<<7) | reg_num(reg_m)); +} + +static void as_sub_r_lsr_r_r (int reg_m,int lsr_m,int reg_n,int reg_d) +{ + store_l (0xe0000020 | (ARM_OP_SUB<<21) | (reg_num (reg_n)<<16) | (reg_num (reg_d)<<12) | (lsr_m<<7) | reg_num(reg_m)); +} + +static void as_sub_r_asr_r_r (int reg_m,int asr_m,int reg_n,int reg_d) +{ + store_l (0xe0000040 | (ARM_OP_SUB<<21) | (reg_num (reg_n)<<16) | (reg_num (reg_d)<<12) | (asr_m<<7) | reg_num(reg_m)); +} + +static void as_sub_is_r_r (int i,int shift,int s_reg,int d_reg) +{ + store_l_is (0xe2000000 | (ARM_OP_SUB<<21) | (reg_num (s_reg)<<16) | (reg_num (d_reg)<<12),i,shift); +} + +static void as_sub_cc_is_r_r (int cc,int i,int shift,int s_reg,int d_reg) +{ + store_l_is (0x02000000 | (cc<<28) | (ARM_OP_SUB<<21) | (reg_num (s_reg)<<16) | (reg_num (d_reg)<<12),i,shift); +} + +static void as_rsb_is_r_r (int i,int shift,int s_reg,int d_reg) +{ + store_l_is (0xe2000000 | (ARM_OP_RSB<<21) | (reg_num (s_reg)<<16) | (reg_num (d_reg)<<12),i,shift); +} + +static void as_cmp_r_r (int reg_m,int reg_n) +{ + store_l (0xe0100000 | (ARM_OP_CMP<<21) | (reg_num (reg_n)<<16) | reg_num(reg_m)); +} + +static void as_cmp_is_r (int i,int shift,int s_reg) +{ + store_l_is (0xe2100000 | (ARM_OP_CMP<<21) | (reg_num (s_reg)<<16),i,shift); +} + +static void as_cmn_is_r (int i,int shift,int s_reg) +{ + store_l_is (0xe2100000 | (ARM_OP_CMN<<21) | (reg_num (s_reg)<<16),i,shift); +} + +static void as_and_is_r_r (int i,int shift,int s_reg,int d_reg) +{ + store_l_is (0xe2000000 | (ARM_OP_AND<<21) | (reg_num (s_reg)<<16) | (reg_num (d_reg)<<12),i,shift); +} + +static void as_and_r_lsr_r_r (int reg_m,int lsr_m,int reg_n,int reg_d) +{ + store_l (0xe0000020 | (ARM_OP_AND<<21) | (reg_num (reg_n)<<16) | (reg_num (reg_d)<<12) | (lsr_m<<7) | reg_num(reg_m)); +} + +static void as_mla_r_r_r_r (int n_reg,int m_reg,int a_reg,int d_reg) +{ + store_l (0xe0200090 | (reg_num (d_reg)<<16) | (reg_num (a_reg)<<12) | (reg_num (m_reg)<<8) | reg_num (n_reg)); +} + +static void as_mls_r_r_r_r (int n_reg,int m_reg,int a_reg,int d_reg) +{ + store_l (0xe0600090 | (reg_num (d_reg)<<16) | (reg_num (a_reg)<<12) | (reg_num (m_reg)<<8) | reg_num (n_reg)); +} + +static void as_smmul_r_r_r (int n_reg,int m_reg,int d_reg) +{ + store_l (0xe750f010 | (reg_num (d_reg)<<16) | (reg_num (m_reg)<<8) | reg_num (n_reg)); +} + +static void as_smmla_r_r_r (int n_reg,int m_reg,int a_reg,int d_reg) +{ + store_l (0xe7500010 | (reg_num (d_reg)<<16) | (reg_num (a_reg)<<12) | (reg_num (m_reg)<<8) | reg_num (n_reg)); +} + +static void as_smmls_r_r_r (int n_reg,int m_reg,int a_reg,int d_reg) +{ + store_l (0xe75000d0 | (reg_num (d_reg)<<16) | (reg_num (a_reg)<<12) | (reg_num (m_reg)<<8) | reg_num (n_reg)); +} + +static void as_move_d_r (LABEL *label,int arity,int reg1) +{ + store_l (0xe59f0000 | (reg_num (reg1)<<12)); /* ldr rt,[pc+imm] */ + as_literal_label_entry (label,arity); + if (pic_flag) + as_add_r_r_r_no_literal_table (REGISTER_PC,reg1,reg1); +} + +static void as_move_l_r (LABEL *label,int reg1) +{ + store_l (0xe59f0000 | (reg_num (reg1)<<12)); /* ldr rt,[pc+imm] */ + as_literal_label_entry (label,0); + if (pic_flag) + as_add_r_r_r_no_literal_table (REGISTER_PC,reg1,reg1); +} + +static void as_load_indexed_reg (int offset,struct index_registers *index_registers,int reg) +{ + int reg1,reg2; + + reg1=index_registers->a_reg.r; + reg2=index_registers->d_reg.r; + if ((offset & -4)!=0){ + int shift; + + shift = immediate_shift (offset>>2); + if (shift>=0){ + as_add_is_r_r (offset>>2,shift,reg1,REGISTER_S0); + as_ldr_ix_r (REGISTER_S0,reg2,offset & 3,reg); + return; + } + } else { + as_ldr_ix_r (reg1,reg2,offset & 3,reg); + return; + } + + internal_error_in_function ("as_load_indexed_reg"); +} + +static void as_store_b_reg_indexed (int reg,int offset,struct index_registers *index_registers,int scratch_reg) +{ + int reg1,reg2; + + reg1=index_registers->a_reg.r; + reg2=index_registers->d_reg.r; + if ((offset & -4)!=0){ + int shift; + + shift = immediate_shift (offset>>2); + if (shift>=0){ + as_add_is_r_r (offset>>2,shift,reg1,scratch_reg); + as_strb_r_ix (reg,scratch_reg,reg2,offset & 3); + return; + } + } else { + as_strb_r_ix (reg,reg1,reg2,offset & 3); + return; + } + + internal_error_in_function ("as_store_b_reg_indexed"); +} + +static void as_load_parameter_to_scratch_register (struct parameter *parameter_p) +{ + switch (parameter_p->parameter_type){ + case P_INDIRECT: + as_ldr_id_r (parameter_p->parameter_offset,parameter_p->parameter_data.reg.r,REGISTER_S0); + break; + case P_INDEXED: + as_load_indexed_reg (parameter_p->parameter_offset,parameter_p->parameter_data.ir,REGISTER_S0); + break; + case P_POST_INCREMENT: + as_ldr_id_r_post_add (4,parameter_p->parameter_data.reg.r,REGISTER_S0); + break; + case P_INDIRECT_WITH_UPDATE: + as_ldr_id_r_update (parameter_p->parameter_offset,parameter_p->parameter_data.reg.r,REGISTER_S0); + break; + case P_INDIRECT_POST_ADD: + as_ldr_id_r_post_add (parameter_p->parameter_offset,parameter_p->parameter_data.reg.r,REGISTER_S0); + break; + default: + internal_error_in_function ("as_load_parameter_to_scratch_register"); + return; + } +} + +static void as_move_parameter_reg (struct parameter *parameter_p,int reg) +{ + switch (parameter_p->parameter_type){ + case P_REGISTER: + as_mov_r_r (parameter_p->parameter_data.reg.r,reg); + return; + case P_DESCRIPTOR_NUMBER: + as_move_d_r (parameter_p->parameter_data.l,parameter_p->parameter_offset,reg); + return; + case P_IMMEDIATE: + as_move_i_r (parameter_p->parameter_data.i,reg); + return; + case P_INDIRECT: + as_ldr_id_r (parameter_p->parameter_offset,parameter_p->parameter_data.reg.r,reg); + return; + case P_INDEXED: + as_load_indexed_reg (parameter_p->parameter_offset,parameter_p->parameter_data.ir,reg); + return; + case P_POST_INCREMENT: + as_ldr_id_r_post_add (4,parameter_p->parameter_data.reg.r,reg); + return; + case P_INDIRECT_WITH_UPDATE: + as_ldr_id_r_update (parameter_p->parameter_offset,parameter_p->parameter_data.reg.r,reg); + return; + case P_INDIRECT_POST_ADD: + as_ldr_id_r_post_add (parameter_p->parameter_offset,parameter_p->parameter_data.reg.r,reg); + return; + case P_LABEL: + as_move_l_r (parameter_p->parameter_data.l,reg); + as_ldr_id_r (0,reg,reg); + return; + default: + internal_error_in_function ("as_move_parameter_reg"); + return; + } +} + +static void as_move_instruction (struct instruction *instruction) +{ + if (instruction->instruction_parameters[1].parameter_type==P_REGISTER){ + as_move_parameter_reg (&instruction->instruction_parameters[0], + instruction->instruction_parameters[1].parameter_data.reg.r); + return; + } else if (instruction->instruction_parameters[0].parameter_type==P_REGISTER){ + switch (instruction->instruction_parameters[1].parameter_type){ + case P_INDIRECT: + as_str_r_id (instruction->instruction_parameters[0].parameter_data.reg.r, + instruction->instruction_parameters[1].parameter_offset, + instruction->instruction_parameters[1].parameter_data.reg.r); + return; + case P_PRE_DECREMENT: + as_str_r_id_update (instruction->instruction_parameters[0].parameter_data.reg.r, + -4,instruction->instruction_parameters[1].parameter_data.reg.r); + return; + case P_INDEXED: + { + int reg_0,reg_s,reg1,reg2,offset; + + reg_0 = instruction->instruction_parameters[0].parameter_data.reg.r; + reg_s = REGISTER_S0; + + offset=instruction->instruction_parameters[1].parameter_offset; + reg1=instruction->instruction_parameters[1].parameter_data.ir->a_reg.r; + reg2=instruction->instruction_parameters[1].parameter_data.ir->d_reg.r; + + if ((offset & -4)!=0){ + int shift; + + shift = immediate_shift (offset>>2); + if (shift>=0){ + as_add_is_r_r (offset>>2,shift,reg1,reg_s); + as_str_r_ix (reg_0,reg_s,reg2,offset & 3); + return; + } + } else { + as_str_r_ix (reg_0,reg1,reg2,offset & 3); + return; + } + + internal_error_in_function ("as_move_instruction"); + return; + } + case P_POST_INCREMENT: + as_ldr_id_r_post_add (4,instruction->instruction_parameters[1].parameter_offset, + instruction->instruction_parameters[1].parameter_data.reg.r); + return; + case P_INDIRECT_WITH_UPDATE: + as_str_r_id_update (instruction->instruction_parameters[0].parameter_data.reg.r, + instruction->instruction_parameters[1].parameter_offset, + instruction->instruction_parameters[1].parameter_data.reg.r); + return; + case P_INDIRECT_POST_ADD: + as_str_r_id_post_add (instruction->instruction_parameters[0].parameter_data.reg.r, + instruction->instruction_parameters[1].parameter_offset, + instruction->instruction_parameters[1].parameter_data.reg.r); + return; + case P_LABEL: + as_move_l_r (instruction->instruction_parameters[1].parameter_data.l,REGISTER_S0); + as_str_r_id (instruction->instruction_parameters[0].parameter_data.reg.r,0,REGISTER_S0); + return; + } + } else { + switch (instruction->instruction_parameters[0].parameter_type){ + case P_INDIRECT: + as_ldr_id_r (instruction->instruction_parameters[0].parameter_offset, + instruction->instruction_parameters[0].parameter_data.reg.r,REGISTER_S0); + break; + case P_INDEXED: + as_load_indexed_reg (instruction->instruction_parameters[0].parameter_offset, + instruction->instruction_parameters[0].parameter_data.ir,REGISTER_S0); + break; + case P_DESCRIPTOR_NUMBER: + as_move_d_r (instruction->instruction_parameters[0].parameter_data.l, + instruction->instruction_parameters[0].parameter_offset,REGISTER_S0); + break; + case P_IMMEDIATE: + as_move_i_r (instruction->instruction_parameters[0].parameter_data.i,REGISTER_S0); + break; + case P_POST_INCREMENT: + as_ldr_id_r_post_add (4,instruction->instruction_parameters[0].parameter_data.reg.r,REGISTER_S0); + break; + case P_INDIRECT_WITH_UPDATE: + as_ldr_id_r_update (instruction->instruction_parameters[0].parameter_offset, + instruction->instruction_parameters[0].parameter_data.reg.r,REGISTER_S0); + break; + case P_INDIRECT_POST_ADD: + as_ldr_id_r_post_add (instruction->instruction_parameters[0].parameter_offset, + instruction->instruction_parameters[0].parameter_data.reg.r,REGISTER_S0); + break; + default: + internal_error_in_function ("as_move_instruction"); + return; + } + + switch (instruction->instruction_parameters[1].parameter_type){ + case P_INDIRECT: + as_str_r_id (REGISTER_S0, + instruction->instruction_parameters[1].parameter_offset, + instruction->instruction_parameters[1].parameter_data.reg.r); + return; + case P_PRE_DECREMENT: + as_str_r_id_update (REGISTER_S0,-4,instruction->instruction_parameters[1].parameter_data.reg.r); + return; + case P_INDEXED: + { + int reg_0,reg_s,reg1,reg2,offset; + + reg_0 = REGISTER_S0; + reg_s = REGISTER_S1; + + offset=instruction->instruction_parameters[1].parameter_offset; + reg1=instruction->instruction_parameters[1].parameter_data.ir->a_reg.r; + reg2=instruction->instruction_parameters[1].parameter_data.ir->d_reg.r; + + if ((offset & -4)!=0){ + int shift; + + shift = immediate_shift (offset>>2); + if (shift>=0){ + as_add_is_r_r (offset>>2,shift,reg1,reg_s); + as_str_r_ix (reg_0,reg_s,reg2,offset & 3); + return; + } + } else { + as_str_r_ix (reg_0,reg1,reg2,offset & 3); + return; + } + + internal_error_in_function ("as_move_instruction"); + return; + } + case P_INDIRECT_WITH_UPDATE: + as_str_r_id_update (REGISTER_S0,instruction->instruction_parameters[1].parameter_offset, + instruction->instruction_parameters[1].parameter_data.reg.r); + return; + case P_INDIRECT_POST_ADD: + as_str_r_id_post_add (REGISTER_S0,instruction->instruction_parameters[1].parameter_offset, + instruction->instruction_parameters[1].parameter_data.reg.r); + return; + case P_LABEL: + as_move_l_r (instruction->instruction_parameters[1].parameter_data.l,REGISTER_S1); + as_str_r_id (REGISTER_S0,0,REGISTER_S1); + return; + } + } + internal_error_in_function ("as_move_instruction"); +} + +static void as_moveb_instruction (struct instruction *instruction) +{ + switch (instruction->instruction_parameters[1].parameter_type){ + case P_REGISTER: + { + int reg; + + reg=instruction->instruction_parameters[1].parameter_data.reg.r; + switch (instruction->instruction_parameters[0].parameter_type){ + case P_IMMEDIATE: + as_move_i_r (instruction->instruction_parameters[0].parameter_data.i,reg); + return; + case P_INDIRECT: + as_ldrb_id_r (instruction->instruction_parameters[0].parameter_offset, + instruction->instruction_parameters[0].parameter_data.reg.r,reg); + return; + case P_INDEXED: + { + int offset,reg1,reg2; + + reg1=instruction->instruction_parameters[0].parameter_data.ir->a_reg.r; + reg2=instruction->instruction_parameters[0].parameter_data.ir->d_reg.r; + + offset=instruction->instruction_parameters[0].parameter_offset; + if ((offset & -4)!=0){ + int shift; + + shift = immediate_shift (offset>>2); + if (shift>=0){ + as_add_is_r_r (offset>>2,shift,reg1,REGISTER_S0); + as_ldrb_ix_r (REGISTER_S0,reg2,offset & 3,reg); + return; + } else { + shift = immediate_shift (-(offset>>2)); + if (shift>=0){ + as_sub_is_r_r (-(offset>>2),shift,reg1,REGISTER_S0); + as_ldrb_ix_r (REGISTER_S0,reg2,offset & 3,reg); + return; + } + } + } else { + as_ldrb_ix_r (reg1,reg2,offset & 3,reg); + return; + } + + internal_error_in_function ("as_moveb_instruction"); + return; + } + } + + break; + } + case P_INDIRECT: + switch (instruction->instruction_parameters[0].parameter_type){ + case P_IMMEDIATE: + as_move_i_r (instruction->instruction_parameters[0].parameter_data.i,REGISTER_S0); + as_strb_r_id (REGISTER_S0, + instruction->instruction_parameters[1].parameter_offset, + instruction->instruction_parameters[1].parameter_data.reg.r); + return; + case P_REGISTER: + as_strb_r_id (instruction->instruction_parameters[0].parameter_data.reg.r, + instruction->instruction_parameters[1].parameter_offset, + instruction->instruction_parameters[1].parameter_data.reg.r); + return; + } + break; + case P_INDEXED: + switch (instruction->instruction_parameters[0].parameter_type){ + case P_IMMEDIATE: + as_move_i_r (instruction->instruction_parameters[0].parameter_data.i,REGISTER_S0); + as_store_b_reg_indexed (REGISTER_S0, + instruction->instruction_parameters[1].parameter_offset, + instruction->instruction_parameters[1].parameter_data.ir,REGISTER_S1); + return; + case P_REGISTER: + as_store_b_reg_indexed (instruction->instruction_parameters[0].parameter_data.reg.r, + instruction->instruction_parameters[1].parameter_offset, + instruction->instruction_parameters[1].parameter_data.ir,REGISTER_S0); + return; + } + break; + } + internal_error_in_function ("as_moveb_instruction"); +} + +static void as_movew_instruction (struct instruction *instruction) +{ + switch (instruction->instruction_parameters[1].parameter_type){ + case P_REGISTER: + { + int reg; + + reg=instruction->instruction_parameters[1].parameter_data.reg.r; + switch (instruction->instruction_parameters[0].parameter_type){ + case P_INDIRECT: + as_ldrsh_id_r (instruction->instruction_parameters[0].parameter_offset, + instruction->instruction_parameters[0].parameter_data.reg.r,reg); + return; + } + break; + } + } + internal_error_in_function ("as_movew_instruction"); +} + +static void as_lea_instruction (struct instruction *instruction) +{ + if (instruction->instruction_parameters[1].parameter_type==P_REGISTER){ + switch (instruction->instruction_parameters[0].parameter_type){ + case P_LABEL: + as_move_d_r (instruction->instruction_parameters[0].parameter_data.l, + instruction->instruction_parameters[0].parameter_offset, + instruction->instruction_parameters[1].parameter_data.reg.r); + return; + case P_INDIRECT: + { + int shift,i; + + i = instruction->instruction_parameters[0].parameter_offset; + shift = immediate_shift (i); + if (shift>=0){ + as_add_is_r_r (i,shift, + instruction->instruction_parameters[0].parameter_data.reg.r, + instruction->instruction_parameters[1].parameter_data.reg.r); + return; + } else { + shift = immediate_shift (-i); + if (shift>=0){ + as_sub_is_r_r (-i,shift, + instruction->instruction_parameters[0].parameter_data.reg.r, + instruction->instruction_parameters[1].parameter_data.reg.r); + return; + } + } + break; + } + case P_INDEXED: + if (instruction->instruction_parameters[0].parameter_offset==0){ + as_add_r_r_r (instruction->instruction_parameters[0].parameter_data.ir->d_reg.r, + instruction->instruction_parameters[0].parameter_data.ir->a_reg.r, + instruction->instruction_parameters[1].parameter_data.reg.r); + return; + } + } + } + internal_error_in_function ("as_lea_instruction"); +} + +static void as_movem_instruction (struct instruction *instruction) +{ + int n_regs; + unsigned short register_list; + + n_regs = instruction->instruction_arity-1; + register_list = 0u; + + if (instruction->instruction_parameters[0].parameter_type!=P_REGISTER){ + int s_reg,n; + + s_reg = instruction->instruction_parameters[0].parameter_data.reg.r; + + for (n=0; n<n_regs; ++n) + register_list |= 1u << (unsigned)reg_num(instruction->instruction_parameters[1+n].parameter_data.reg.r); + + if (instruction->instruction_parameters[0].parameter_type==P_PRE_DECREMENT){ + store_l (0xe9300000 | (reg_num (s_reg)<<16) | register_list); /* ldmdb */ + return; + } else if (instruction->instruction_parameters[0].parameter_type==P_POST_INCREMENT){ + store_l (0xe8b00000 | (reg_num (s_reg)<<16) | register_list); /* ldmia */ + return; + } + } else { + int d_reg,n; + + d_reg = instruction->instruction_parameters[n_regs].parameter_data.reg.r; + + for (n=0; n<n_regs; ++n) + register_list |= 1u << (unsigned)reg_num(instruction->instruction_parameters[n].parameter_data.reg.r); + + if (instruction->instruction_parameters[n_regs].parameter_type==P_PRE_DECREMENT){ + store_l (0xe9200000 | (reg_num (d_reg)<<16) | register_list); /* stmdb */ + return; + } else if (instruction->instruction_parameters[n_regs].parameter_type==P_POST_INCREMENT){ + store_l (0xe8a00000 | (reg_num (d_reg)<<16) | register_list); /* stmia */ + return; + } + } + internal_error_in_function ("as_movem_instruction"); +} + +static void as_add_instruction (struct instruction *instruction) +{ + switch (instruction->instruction_parameters[0].parameter_type){ + case P_REGISTER: + as_add_r_r_r (instruction->instruction_parameters[0].parameter_data.reg.r, + instruction->instruction_parameters[1].parameter_data.reg.r, + instruction->instruction_parameters[1].parameter_data.reg.r); + return; + case P_IMMEDIATE: + { + int shift,i; + + i = instruction->instruction_parameters[0].parameter_data.i; + shift = immediate_shift (i); + if (shift>=0){ + as_add_is_r_r (i,shift, + instruction->instruction_parameters[1].parameter_data.reg.r, + instruction->instruction_parameters[1].parameter_data.reg.r); + return; + } + + shift = immediate_shift (-i); + if (shift>=0){ + as_sub_is_r_r (-i,shift, + instruction->instruction_parameters[1].parameter_data.reg.r, + instruction->instruction_parameters[1].parameter_data.reg.r); + return; + } + + store_l (0xe59f0000 | (reg_num (REGISTER_S0)<<12)); /* ldr rt,[pc+imm] */ + as_literal_constant_entry (i); + break; + } + default: + as_load_parameter_to_scratch_register (&instruction->instruction_parameters[0]); + } + + as_add_r_r_r (REGISTER_S0,instruction->instruction_parameters[1].parameter_data.reg.r, + instruction->instruction_parameters[1].parameter_data.reg.r); +} + +static void as_sub_instruction (struct instruction *instruction) +{ + switch (instruction->instruction_parameters[0].parameter_type){ + case P_REGISTER: + as_sub_r_r_r (instruction->instruction_parameters[0].parameter_data.reg.r, + instruction->instruction_parameters[1].parameter_data.reg.r, + instruction->instruction_parameters[1].parameter_data.reg.r); + return; + case P_IMMEDIATE: + { + int shift,i; + + i = instruction->instruction_parameters[0].parameter_data.i; + shift = immediate_shift (i); + if (shift>=0){ + as_sub_is_r_r (i,shift, + instruction->instruction_parameters[1].parameter_data.reg.r, + instruction->instruction_parameters[1].parameter_data.reg.r); + return; + } + + shift = immediate_shift (-i); + if (shift>=0){ + as_add_is_r_r (-i,shift, + instruction->instruction_parameters[1].parameter_data.reg.r, + instruction->instruction_parameters[1].parameter_data.reg.r); + return; + } + + store_l (0xe59f0000 | (reg_num (REGISTER_S0)<<12)); /* ldr rt,[pc+imm] */ + as_literal_constant_entry (i); + break; + } + default: + as_load_parameter_to_scratch_register (&instruction->instruction_parameters[0]); + } + + as_sub_r_r_r (REGISTER_S0,instruction->instruction_parameters[1].parameter_data.reg.r, + instruction->instruction_parameters[1].parameter_data.reg.r); +} + +static void as_addi_instruction (struct instruction *instruction) +{ + int s_reg,d_reg,i,shift; + + s_reg = instruction->instruction_parameters[0].parameter_data.reg.r; + d_reg = instruction->instruction_parameters[1].parameter_data.reg.r; + i = instruction->instruction_parameters[2].parameter_data.i; + + shift = immediate_shift (i); + if (shift>=0){ + as_add_is_r_r (i,shift,s_reg,d_reg); + return; + } + + shift = immediate_shift (-i); + if (shift>=0){ + as_sub_is_r_r (-i,shift,s_reg,d_reg); + return; + } + + store_l (0xe59f0000 | (reg_num (REGISTER_S0)<<12)); /* ldr rt,[pc+imm] */ + as_literal_constant_entry (i); + + as_add_r_r_r (REGISTER_S0,s_reg,d_reg); +} + +static void as_add_or_sub_x_instruction (struct instruction *instruction,int arm_x_op,int arm_x_op_r) +{ + switch (instruction->instruction_parameters[0].parameter_type){ + case P_REGISTER: + as_x_op_r_r_r (arm_x_op,instruction->instruction_parameters[0].parameter_data.reg.r, + instruction->instruction_parameters[1].parameter_data.reg.r, + instruction->instruction_parameters[1].parameter_data.reg.r); + return; + case P_IMMEDIATE: + { + int shift,i; + + i = instruction->instruction_parameters[0].parameter_data.i; + shift = immediate_shift (i); + if (shift>=0){ + as_x_op_is_r_r (arm_x_op,i,shift, + instruction->instruction_parameters[1].parameter_data.reg.r, + instruction->instruction_parameters[1].parameter_data.reg.r); + return; + } + + shift = immediate_shift (-i); + if (shift>=0){ + as_x_op_is_r_r (arm_x_op_r,-i,shift, + instruction->instruction_parameters[1].parameter_data.reg.r, + instruction->instruction_parameters[1].parameter_data.reg.r); + return; + } + + store_l (0xe59f0000 | (reg_num (REGISTER_S0)<<12)); /* ldr rt,[pc+imm] */ + as_literal_constant_entry (i); + break; + } + default: + as_load_parameter_to_scratch_register (&instruction->instruction_parameters[0]); + } + + as_x_op_r_r_r (arm_x_op,REGISTER_S0,instruction->instruction_parameters[1].parameter_data.reg.r, + instruction->instruction_parameters[1].parameter_data.reg.r); +} + +enum { SIZE_LONG, SIZE_WORD, SIZE_BYTE }; + +static void as_cmp_i_parameter (int i,struct parameter *parameter) +{ + int reg,reg_i,shift; + + switch (parameter->parameter_type){ + case P_REGISTER: + reg=parameter->parameter_data.reg.r; + reg_i=REGISTER_S0; + break; + default: + as_load_parameter_to_scratch_register (parameter); + reg=REGISTER_S0; + reg_i=REGISTER_S1; + } + + shift = immediate_shift (i); + if (shift>=0){ + as_cmp_is_r (i,shift,reg); + return; + } else { + shift = immediate_shift (-i); + if (shift>=0){ + as_cmn_is_r (-i,shift,reg); + return; + } + } + + store_l (0xe59f0000 | (reg_num (reg_i)<<12)); /* ldr rt,[pc+imm] */ + as_literal_constant_entry (i); + + as_cmp_r_r (reg_i,reg); +} + +static void as_cmp_instruction (struct instruction *instruction) +{ + switch (instruction->instruction_parameters[0].parameter_type){ + case P_DESCRIPTOR_NUMBER: + switch (instruction->instruction_parameters[1].parameter_type){ + case P_REGISTER: + as_move_d_r (instruction->instruction_parameters[0].parameter_data.l, + instruction->instruction_parameters[0].parameter_offset,REGISTER_S1); + as_cmp_r_r (REGISTER_S1,instruction->instruction_parameters[1].parameter_data.reg.r); + return; + default: + as_load_parameter_to_scratch_register (&instruction->instruction_parameters[1]); + as_move_d_r (instruction->instruction_parameters[0].parameter_data.l, + instruction->instruction_parameters[0].parameter_offset,REGISTER_S1); + as_cmp_r_r (REGISTER_S1,REGISTER_S0); + return; + } + break; + case P_IMMEDIATE: + as_cmp_i_parameter (instruction->instruction_parameters[0].parameter_data.i, + &instruction->instruction_parameters[1]); + return; + } + + if (instruction->instruction_parameters[1].parameter_type==P_REGISTER) + switch (instruction->instruction_parameters[0].parameter_type){ + case P_REGISTER: + as_cmp_r_r (instruction->instruction_parameters[0].parameter_data.reg.r, + instruction->instruction_parameters[1].parameter_data.reg.r); + return; + default: + as_load_parameter_to_scratch_register (&instruction->instruction_parameters[0]); + as_cmp_r_r (REGISTER_S0,instruction->instruction_parameters[1].parameter_data.reg.r); + return; + } + + internal_error_in_function ("as_cmp_instruction"); +} + +void store_label_in_data_section (LABEL *label) +{ + store_label_plus_offset_in_data_section (label,0); +} + +void store_descriptor_in_data_section (LABEL *label) +{ + store_label_plus_offset_in_data_section (label,2); +} + +static void as_jmp_instruction (struct instruction *instruction) +{ + switch (instruction->instruction_parameters[0].parameter_type){ + case P_LABEL: + store_l (0xea000000); + as_branch_label (instruction->instruction_parameters[0].parameter_data.l,JUMP_RELOCATION); + break; + case P_INDIRECT: + as_ldr_id_r (instruction->instruction_parameters[0].parameter_offset, + instruction->instruction_parameters[0].parameter_data.reg.r,REGISTER_PC); + break; + case P_REGISTER: + as_mov_r_r (instruction->instruction_parameters[0].parameter_data.reg.r,REGISTER_PC); + break; + default: + internal_error_in_function ("as_jmp_instruction"); + } + + write_literals(); +} + +static void as_jmpp_instruction (struct instruction *instruction) +{ +#if 0 + switch (instruction->instruction_parameters[0].parameter_type){ + case P_LABEL: + { + int offset; + + offset=instruction->instruction_parameters[0].parameter_offset; + + if (offset==0){ + store_l (0xeb000000); /* bl */ + as_branch_label (profile_t_label,CALL_RELOCATION); + } + + store_l (0xea000000); /* b */ + /* + store_c (0351); + store_l (offset); + */ + as_branch_label (instruction->instruction_parameters[0].parameter_data.l,JUMP_RELOCATION); + break; + } + case P_INDIRECT: + store_c (0350); + store_l (0); + as_branch_label (profile_t_label,CALL_RELOCATION); + + as_id (0377,040,instruction->instruction_parameters[0].parameter_offset, + instruction->instruction_parameters[0].parameter_data.reg.r); + break; + case P_REGISTER: + store_c (0350); + store_l (0); + as_branch_label (profile_t_label,CALL_RELOCATION); + + store_c (0377); + store_c (0340 | reg_num (instruction->instruction_parameters[0].parameter_data.reg.r)); + break; + default: + internal_error_in_function ("as_jmpp_instruction"); + } +#else + internal_error_in_function ("as_jmpp_instruction"); +#endif +} + +static void as_jsr_instruction (struct instruction *instruction) +{ + switch (instruction->instruction_parameters[0].parameter_type){ + case P_LABEL: + if (instruction->instruction_arity>1) + switch (instruction->instruction_parameters[1].parameter_type){ + case P_INDIRECT_WITH_UPDATE: + as_str_r_id_update (REGISTER_PC,instruction->instruction_parameters[1].parameter_offset,B_STACK_POINTER); + break; + case P_INDIRECT: + as_str_r_id (REGISTER_PC,instruction->instruction_parameters[1].parameter_offset,B_STACK_POINTER); + } + store_l (0xeb000000); /* bl */ + as_branch_label (instruction->instruction_parameters[0].parameter_data.l,CALL_RELOCATION); + break; + case P_INDIRECT: + as_ldr_id_r (instruction->instruction_parameters[0].parameter_offset, + instruction->instruction_parameters[0].parameter_data.reg.r,REGISTER_S0); + if (instruction->instruction_arity>1) + if (instruction->instruction_parameters[1].parameter_type==P_INDIRECT_WITH_UPDATE) + as_str_r_id_update (REGISTER_PC,-4,B_STACK_POINTER); + store_l (0xe12fff30 | reg_num (REGISTER_S0)); /* blx r12*/ + break; + case P_REGISTER: + if (instruction->instruction_arity>1) + if (instruction->instruction_parameters[1].parameter_type==P_INDIRECT_WITH_UPDATE) + as_str_r_id_update (REGISTER_PC,-4,B_STACK_POINTER); + store_l (0xe12fff30 | reg_num (instruction->instruction_parameters[0].parameter_data.reg.r)); /* blx rm*/ + break; + default: + internal_error_in_function ("as_jsr_instruction"); + } +} + +static void as_rts_instruction() +{ + store_l (0xe49df004); /* ldr pc,[sp],#4 */ + write_literals(); +} + +static void as_rtsi_instruction (struct instruction *instruction) +{ + int offset; + + offset = instruction->instruction_parameters[0].parameter_data.imm; + store_l (0xe49df000 | (offset & 0xfff)); /* ldr pc,[sp],#offset */ + write_literals(); +} + +static void as_branch_instruction (struct instruction *instruction,int condition_code) +{ + store_l ((condition_code<<28) | 0x0a000000); /* b */ + as_branch_label (instruction->instruction_parameters[0].parameter_data.l,BRANCH_RELOCATION); +} + +static void as_nop (void) +{ + /* mov r0,r0 */ + store_l (0xe1A00000); +} + +static void as_shift_instruction (struct instruction *instruction,int shift_code) +{ + if (instruction->instruction_parameters[0].parameter_type==P_IMMEDIATE){ + as_shift_i_r_r (shift_code,instruction->instruction_parameters[0].parameter_data.i & 31, + instruction->instruction_parameters[1].parameter_data.reg.r, + instruction->instruction_parameters[1].parameter_data.reg.r); + } else { + int s_reg,d_reg; + + s_reg = instruction->instruction_parameters[0].parameter_data.reg.r; + d_reg = instruction->instruction_parameters[1].parameter_data.reg.r; + as_shift_r_r_r (shift_code,s_reg,d_reg,d_reg); + } +} + +static void as_lsli_instruction (struct instruction *instruction) +{ + as_lsl_i_r_r (instruction->instruction_parameters[2].parameter_data.i & 31, + instruction->instruction_parameters[0].parameter_data.reg.r, + instruction->instruction_parameters[1].parameter_data.reg.r); +} + +static void as_logic_instruction (struct instruction *instruction,int arm_op) +{ + switch (instruction->instruction_parameters[0].parameter_type){ + case P_REGISTER: + as_op_r_r_r (arm_op,instruction->instruction_parameters[0].parameter_data.reg.r, + instruction->instruction_parameters[1].parameter_data.reg.r, + instruction->instruction_parameters[1].parameter_data.reg.r); + return; + case P_IMMEDIATE: + { + int shift,i; + + i = instruction->instruction_parameters[0].parameter_data.i; + shift = immediate_shift (i); + if (shift>=0){ + as_op_is_r_r (arm_op,i,shift, + instruction->instruction_parameters[1].parameter_data.reg.r, + instruction->instruction_parameters[1].parameter_data.reg.r); + return; + } + + shift = immediate_shift (~i); + if (shift>=0){ + if (arm_op==ARM_OP_AND){ + as_op_is_r_r (ARM_OP_BIC,~i,shift, + instruction->instruction_parameters[1].parameter_data.reg.r, + instruction->instruction_parameters[1].parameter_data.reg.r); + } else { + store_l_is (0xe3e00000 | (reg_num (REGISTER_S0)<<12),~i,shift); /* mvn rd,#i<<s */ + as_op_r_r_r (arm_op,REGISTER_S0, + instruction->instruction_parameters[1].parameter_data.reg.r, + instruction->instruction_parameters[1].parameter_data.reg.r); + } + return; + } + + store_l (0xe59f0000 | (reg_num (REGISTER_S0)<<12)); /* ldr rt,[pc+imm] */ + as_literal_constant_entry (i); + as_op_r_r_r (arm_op,REGISTER_S0, + instruction->instruction_parameters[1].parameter_data.reg.r, + instruction->instruction_parameters[1].parameter_data.reg.r); + return; + } + default: + as_load_parameter_to_scratch_register (&instruction->instruction_parameters[0]); + as_op_r_r_r (arm_op,REGISTER_S0, + instruction->instruction_parameters[1].parameter_data.reg.r, + instruction->instruction_parameters[1].parameter_data.reg.r); + return; + } +} + +static void as_mul_instruction (struct instruction *instruction) +{ + int s_regn,real_d_regn; + + switch (instruction->instruction_parameters[0].parameter_type){ + case P_REGISTER: + s_regn = instruction->instruction_parameters[0].parameter_data.reg.r; + break; + case P_IMMEDIATE: + as_move_i_r (instruction->instruction_parameters[0].parameter_data.i,REGISTER_S0); + s_regn = REGISTER_S0; + break; + default: + as_load_parameter_to_scratch_register (&instruction->instruction_parameters[0]); + s_regn = REGISTER_S0; + } + + real_d_regn = reg_num (instruction->instruction_parameters[1].parameter_data.reg.r); + store_l (0xe0000090 | (real_d_regn<<16) | (real_d_regn<<8) | reg_num (s_regn)); /* mul rd,rn,rm */ +} + +#define CONDITION_EQ 0 +#define CONDITION_NE 1 +#define CONDITION_HS 2 +#define CONDITION_LO 3 +#define CONDITION_MI 4 +#define CONDITION_PL 5 +#define CONDITION_VS 6 +#define CONDITION_VC 7 +#define CONDITION_HI 8 +#define CONDITION_LS 9 +#define CONDITION_GE 10 +#define CONDITION_LT 11 +#define CONDITION_GT 12 +#define CONDITION_LE 13 + +/* + From The PowerPC Compiler Writer's Guide, + Warren, Henry S., Jr., IBM Research Report RC 18601 [1992]. Changing Division by a + Constant to Multiplication in Two's Complement Arithmetic, (December 21), + Granlund, Torbjorn and Montgomery, Peter L. [1994]. SIGPLAN Notices, 29 (June), 61. +*/ + +struct ms magic (int d) + /* must have 2 <= d <= 231-1 or -231 <= d <= -2 */ +{ + int p; + unsigned int ad, anc, delta, q1, r1, q2, r2, t; + const unsigned int two31 = 2147483648u;/* 231 */ + struct ms mag; + + ad = abs(d); + t = two31 + ((unsigned int)d >> 31); + anc = t - 1 - t%ad; /* absolute value of nc */ + p = 31; /* initialize p */ + q1 = two31/anc; /* initialize q1 = 2p/abs(nc) */ + r1 = two31 - q1*anc;/* initialize r1 = rem(2p,abs(nc)) */ + q2 = two31/ad; /* initialize q2 = 2p/abs(d) */ + r2 = two31 - q2*ad; /* initialize r2 = rem(2p,abs(d)) */ + + do { + p = p + 1; + q1 = 2*q1; /* update q1 = 2p/abs(nc) */ + r1 = 2*r1; /* update r1 = rem(2p/abs(nc)) */ + if (r1 >= anc) {/* must be unsigned comparison */ + q1 = q1 + 1; + r1 = r1 - anc; + } + q2 = 2*q2; /* update q2 = 2p/abs(d) */ + r2 = 2*r2; /* update r2 = rem(2p/abs(d)) */ + if (r2 >= ad) { /* must be unsigned comparison */ + q2 = q2 + 1; + r2 = r2 - ad; + } + delta = ad - r2; + } while (q1 < delta || (q1 == delta && r1 == 0)); + + mag.m = q2 + 1; + if (d < 0) mag.m = -mag.m; /* resulting magic number */ + mag.s = p - 32; /* resulting shift */ + + return mag; +} + +static void as_div_instruction (struct instruction *instruction) +{ + int i,abs_i,d_reg; + struct ms ms; + + if (instruction->instruction_parameters[0].parameter_type!=P_IMMEDIATE) + internal_error_in_function ("as_div_instruction"); + + i=instruction->instruction_parameters[0].parameter_data.i; + d_reg=instruction->instruction_parameters[1].parameter_data.reg.r; + + if (i==0){ + internal_error_in_function ("as_div_instruction"); + return; + } + + abs_i=abs (i); + + if ((abs_i & (abs_i-1))==0){ + int log2i; + unsigned int i2; + + if (abs_i==1){ + if (i<0) + as_rsb_is_r_r (0,0,d_reg,d_reg); + return; + } + + log2i=0; + i2=abs_i; + while (i2>1){ + i2>>=1; + ++log2i; + } + + if (log2i==1) + as_add_r_lsr_r_r (d_reg,31,d_reg,d_reg); + else { + as_cmp_is_r (0,0,d_reg); + if (log2i<=8) + as_add_cc_is_r_r (CONDITION_LT,abs_i-1,0,d_reg,d_reg); + else { + as_add_is_r_r (abs_i,immediate_shift (abs_i),d_reg,REGISTER_S0); + as_sub_cc_is_r_r (CONDITION_LT,1,0,REGISTER_S0,d_reg); + } + } + + if (i>0) + as_asr_i_r_r (log2i,d_reg,d_reg); + else { + as_move_i_r (0,REGISTER_S0); + as_sub_r_asr_r_r (d_reg,log2i,REGISTER_S0,d_reg); + } + + return; + } + + ms=magic (abs_i); + + as_move_i_r (ms.m,REGISTER_S0); + + if (ms.s==0){ + if (ms.m>=0){ + as_lsr_i_r_r (31,d_reg,REGISTER_S1); + as_smmla_r_r_r (d_reg,REGISTER_S0,REGISTER_S1,d_reg); + if (i<0) + as_rsb_is_r_r (0,0,d_reg,d_reg); + } else { + if (ms.m>=0) + as_smmul_r_r_r (REGISTER_S0,d_reg,REGISTER_S0); + else + as_smmla_r_r_r (REGISTER_S0,d_reg,d_reg,REGISTER_S0); + + if (i>=0) + as_add_r_lsr_r_r (d_reg,31,REGISTER_S0,d_reg); + else + as_sub_r_asr_r_r (d_reg,31,REGISTER_S0,d_reg); + } + } else { + if (ms.m>=0) + as_smmul_r_r_r (REGISTER_S0,d_reg,REGISTER_S0); + else + as_smmla_r_r_r (REGISTER_S0,d_reg,d_reg,REGISTER_S0); + + if (i>=0){ + as_lsr_i_r_r (31,d_reg,d_reg); + as_add_r_asr_r_r (REGISTER_S0,ms.s,d_reg,d_reg); + } else { + as_asr_i_r_r (31,d_reg,d_reg); + as_sub_r_asr_r_r (REGISTER_S0,ms.s,d_reg,d_reg); + } + } +} + +static void as_rem_instruction (struct instruction *instruction) +{ + int i,d_reg; + struct ms ms; + + if (instruction->instruction_parameters[0].parameter_type!=P_IMMEDIATE) + internal_error_in_function ("as_rem_instruction"); + + i=instruction->instruction_parameters[0].parameter_data.i; + d_reg=instruction->instruction_parameters[1].parameter_data.reg.r; + + if (i==0){ + internal_error_in_function ("as_rem_instruction"); + return; + } + + i=abs (i); + + if ((i & (i-1))==0){ + int log2i; + unsigned int i2; + + if (i==1){ + as_move_i_r (0,d_reg); + return; + } + + as_sub_r_lsr_r_r (d_reg,31,d_reg,REGISTER_S0); + + log2i=0; + i2=i; + while (i2>1){ + i2>>=1; + ++log2i; + } + + if (i<=256){ + if (log2i!=1) + as_asr_i_r_r (log2i-1,d_reg,d_reg); + as_and_is_r_r (i-1,0,REGISTER_S0,REGISTER_S0); + } else { + as_move_i_r (-1,REGISTER_S1); + as_asr_i_r_r (log2i-1,d_reg,d_reg); + as_and_r_lsr_r_r (REGISTER_S1,32-log2i,REGISTER_S0,REGISTER_S0); + } + + as_sub_r_lsr_r_r (d_reg,32-log2i,REGISTER_S0,d_reg); + return; + } + + ms=magic (i); + + as_move_i_r (ms.m,REGISTER_S0); + + if (ms.s==0){ + if (ms.m>=0){ + as_lsr_i_r_r (31,d_reg,REGISTER_S1); + as_smmla_r_r_r (d_reg,REGISTER_S0,REGISTER_S1,REGISTER_S0); + } else { + if (ms.m>=0) + as_smmul_r_r_r (REGISTER_S0,d_reg,REGISTER_S0); + else + as_smmla_r_r_r (REGISTER_S0,d_reg,d_reg,REGISTER_S0); + + as_add_r_lsr_r_r (d_reg,31,REGISTER_S0,REGISTER_S0); + } + } else { + if (ms.m>=0) + as_smmul_r_r_r (REGISTER_S0,d_reg,REGISTER_S0); + else + as_smmla_r_r_r (REGISTER_S0,d_reg,d_reg,REGISTER_S0); + + as_lsr_i_r_r (31,d_reg,REGISTER_S1); + as_add_r_asr_r_r (REGISTER_S0,ms.s,REGISTER_S1,REGISTER_S0); + } + + { + unsigned int i2; + + i2=i & (i-1); + if ((i2 & (i2-1))==0){ + unsigned int n; + int n_shifts; + + n=i; + + n_shifts=0; + while (n>0){ + while ((n & 1)==0){ + n>>=1; + ++n_shifts; + } + + if (n_shifts>0) + as_sub_r_lsl_r_r (REGISTER_S0,n_shifts,d_reg,d_reg); + else + as_sub_r_r_r (REGISTER_S0,d_reg,d_reg); + + n>>=1; + n_shifts=1; + } + } else { +#if 1 + as_move_i_r (-i,REGISTER_S1); + as_mla_r_r_r_r (REGISTER_S0,REGISTER_S1,d_reg,d_reg); +#else + /* mls is an illegal instruction on the raspberry pi b+ */ + as_move_i_r (i,REGISTER_S1); + as_mls_r_r_r_r (REGISTER_S0,REGISTER_S1,d_reg,d_reg); +#endif + } + } +} + +static void as_set_condition_instruction (struct instruction *instruction,int condition_code_true,int condition_code_false) +{ + unsigned int rn; + + rn = reg_num (instruction->instruction_parameters[0].parameter_data.reg.r); + + store_l (0x03a00001 | (condition_code_true<<28) | (rn<<12)); /* movcc rd,#1 */ + store_l (0x03a00000 | (condition_code_false<<28) | (rn<<12)); /* movcc rd,#0 */ +} + +static void as_tst_instruction (struct instruction *instruction) +{ + as_cmp_i_parameter (0,&instruction->instruction_parameters[0]); +} + +static void as_btst_instruction (struct instruction *instruction) +{ + int reg1,shift; + + if (instruction->instruction_parameters[1].parameter_type==P_REGISTER) + reg1=instruction->instruction_parameters[1].parameter_data.reg.r; + else { + reg1=instruction->instruction_parameters[1].parameter_data.reg.r; + + as_ldr_id_r (instruction->instruction_parameters[1].parameter_offset,reg1,REGISTER_S0); + reg1 = REGISTER_S0; + } + + shift = immediate_shift (instruction->instruction_parameters[0].parameter_data.i); + if (shift>=0){ + as_tst_ir_r (instruction->instruction_parameters[0].parameter_data.i,shift,reg1); + return; + } + + internal_error_in_function ("as_btst_instruction"); +} + +static void as_neg_instruction (struct instruction *instruction) +{ + int reg; + + reg = instruction->instruction_parameters[0].parameter_data.reg.r; + as_rsb_is_r_r (0,0,reg,reg); +} + +static void as_not_instruction (struct instruction *instruction) +{ + unsigned int regn; + + regn = reg_num (instruction->instruction_parameters[0].parameter_data.reg.r); + store_l (0xe0000000 | (ARM_OP_MVN<<21) | (regn<<12) | regn); /* mvn rd,rm */ +} + +static void as_fmove_instruction (struct instruction *instruction) +{ + switch (instruction->instruction_parameters[1].parameter_type){ + case P_F_REGISTER: + switch (instruction->instruction_parameters[0].parameter_type){ + case P_F_REGISTER: + { + int reg0,reg1; + + reg0=instruction->instruction_parameters[0].parameter_data.reg.r; + reg1=instruction->instruction_parameters[1].parameter_data.reg.r; + + store_l (0xeeb00b40 | (reg1<<12) | reg0); /* vmov dd,dm */ + return; + } + case P_INDIRECT: + as_vldr_r_id (instruction->instruction_parameters[1].parameter_data.reg.r, + instruction->instruction_parameters[0].parameter_offset, + instruction->instruction_parameters[0].parameter_data.reg.r); + return; + case P_INDEXED: + as_add_r_lsl_r_r (instruction->instruction_parameters[0].parameter_data.ir->d_reg.r, + instruction->instruction_parameters[0].parameter_offset & 3, + instruction->instruction_parameters[0].parameter_data.ir->a_reg.r,REGISTER_S0); + as_vldr_r_id (instruction->instruction_parameters[1].parameter_data.reg.r, + instruction->instruction_parameters[0].parameter_offset>>2,REGISTER_S0); + return; + case P_F_IMMEDIATE: + as_vldr_r_id (instruction->instruction_parameters[1].parameter_data.reg.r,0,REGISTER_PC); + as_float_literal_entry (instruction->instruction_parameters[0].parameter_data.r); + return; + default: + internal_error_in_function ("as_fmove_instruction"); + return; + } + case P_INDIRECT: + if (instruction->instruction_parameters[0].parameter_type==P_F_REGISTER){ + as_vstr_r_id (instruction->instruction_parameters[0].parameter_data.reg.r, + instruction->instruction_parameters[1].parameter_offset, + instruction->instruction_parameters[1].parameter_data.reg.r); + return; + } + break; + case P_INDEXED: + if (instruction->instruction_parameters[0].parameter_type==P_F_REGISTER){ + as_add_r_lsl_r_r (instruction->instruction_parameters[1].parameter_data.ir->d_reg.r, + instruction->instruction_parameters[1].parameter_offset & 3, + instruction->instruction_parameters[1].parameter_data.ir->a_reg.r,REGISTER_S0); + as_vstr_r_id (instruction->instruction_parameters[0].parameter_data.reg.r, + instruction->instruction_parameters[1].parameter_offset>>2,REGISTER_S0); + return; + } + } + internal_error_in_function ("as_fmove_instruction"); + return; +} + +static void as_floads_instruction (struct instruction *instruction) +{ + if (instruction->instruction_parameters[1].parameter_type==P_F_REGISTER){ + int freg; + + switch (instruction->instruction_parameters[0].parameter_type){ + case P_INDIRECT: + freg=instruction->instruction_parameters[1].parameter_data.reg.r; + as_vldr_s_id (freg,instruction->instruction_parameters[0].parameter_offset, + instruction->instruction_parameters[0].parameter_data.reg.r); + break; + case P_INDEXED: + freg=instruction->instruction_parameters[1].parameter_data.reg.r; + as_add_r_lsl_r_r (instruction->instruction_parameters[0].parameter_data.ir->d_reg.r, + instruction->instruction_parameters[0].parameter_offset & 3, + instruction->instruction_parameters[0].parameter_data.ir->a_reg.r,REGISTER_S0); + as_vldr_s_id (freg,instruction->instruction_parameters[0].parameter_offset>>2,REGISTER_S0); + break; + default: + internal_error_in_function ("as_floads_instruction"); + return; + } + + store_l (0xeeb70ac0 | (freg<<12) | freg); /* vcvtr.f64.f32 dd,sm */ + return; + } + + internal_error_in_function ("as_floads_instruction"); +} + +static void as_fmoves_instruction (struct instruction *instruction) +{ + if (instruction->instruction_parameters[0].parameter_type==P_F_REGISTER){ + int s_freg; + + s_freg=instruction->instruction_parameters[0].parameter_data.reg.r; + + store_l (0xeeb70bc0 | (15<<12) | s_freg); /* vcvtr.f32.f64 sd,dm */ + + switch (instruction->instruction_parameters[1].parameter_type){ + case P_INDIRECT: + as_vstr_s_id (15,instruction->instruction_parameters[1].parameter_offset, + instruction->instruction_parameters[1].parameter_data.reg.r); + return; + case P_INDEXED: + as_add_r_lsl_r_r (instruction->instruction_parameters[1].parameter_data.ir->d_reg.r, + instruction->instruction_parameters[1].parameter_offset & 3, + instruction->instruction_parameters[1].parameter_data.ir->a_reg.r,REGISTER_S0); + as_vstr_r_id (15,instruction->instruction_parameters[1].parameter_offset>>2,REGISTER_S0); + return; + } + } + internal_error_in_function ("as_fmoves_instruction"); + return; +} + +static void as_dyadic_float_instruction (struct instruction *instruction,int code) +{ + int d_freg,s_freg; + + switch (instruction->instruction_parameters[0].parameter_type){ + case P_F_IMMEDIATE: + as_vldr_r_id (15,0,REGISTER_PC); + as_float_literal_entry (instruction->instruction_parameters[0].parameter_data.r); + s_freg=15; + break; + case P_INDIRECT: + as_vldr_r_id (15,instruction->instruction_parameters[0].parameter_offset, + instruction->instruction_parameters[0].parameter_data.reg.r); + s_freg=15; + break; + case P_INDEXED: + as_add_r_lsl_r_r (instruction->instruction_parameters[0].parameter_data.ir->d_reg.r, + instruction->instruction_parameters[0].parameter_offset & 3, + instruction->instruction_parameters[0].parameter_data.ir->a_reg.r,REGISTER_S0); + as_vldr_r_id (15,instruction->instruction_parameters[0].parameter_offset>>2,REGISTER_S0); + s_freg=15; + break; + case P_F_REGISTER: + s_freg = instruction->instruction_parameters[0].parameter_data.reg.r; + break; + default: + internal_error_in_function ("as_dyadic_float_instruction"); + return; + } + + d_freg=instruction->instruction_parameters[1].parameter_data.reg.r; + store_l (0xee000b00 | code | (d_freg<<16) | (d_freg<<12) | s_freg); +} + +static void as_float_sub_or_div_instruction (struct instruction *instruction,int code) +{ + int d_freg,s_freg; + + switch (instruction->instruction_parameters[0].parameter_type){ + case P_F_IMMEDIATE: + as_vldr_r_id (15,0,REGISTER_PC); + as_float_literal_entry (instruction->instruction_parameters[0].parameter_data.r); + s_freg=15; + break; + case P_INDIRECT: + as_vldr_r_id (15,instruction->instruction_parameters[0].parameter_offset, + instruction->instruction_parameters[0].parameter_data.reg.r); + s_freg=15; + break; + case P_INDEXED: + as_add_r_lsl_r_r (instruction->instruction_parameters[0].parameter_data.ir->d_reg.r, + instruction->instruction_parameters[0].parameter_offset & 3, + instruction->instruction_parameters[0].parameter_data.ir->a_reg.r,REGISTER_S0); + as_vldr_r_id (15,instruction->instruction_parameters[0].parameter_offset>>2,REGISTER_S0); + s_freg=15; + break; + case P_F_REGISTER: + s_freg = instruction->instruction_parameters[0].parameter_data.reg.r; + break; + default: + internal_error_in_function ("as_float_sub_or_div_instruction"); + return; + } + + d_freg=instruction->instruction_parameters[1].parameter_data.reg.r; + if (instruction->instruction_parameters[1].parameter_flags & FP_REVERSE_SUB_DIV_OPERANDS) + store_l (0xee000b00 | code | (s_freg<<16) | (d_freg<<12) | d_freg); + else + store_l (0xee000b00 | code | (d_freg<<16) | (d_freg<<12) | s_freg); +} + +static void as_vcmp_f64_r_r (int freg_1,int freg_2) +{ + store_l (0xeeb40b40 | (freg_2<<12) | freg_1); /* vcmp.f64 dd,dm */ +} + +static void as_compare_float_instruction (struct instruction *instruction) +{ + int d_freg; + int code1,code2; + + d_freg=instruction->instruction_parameters[1].parameter_data.reg.r; + + switch (instruction->instruction_parameters[0].parameter_type){ + case P_F_IMMEDIATE: + { + DOUBLE *r_p; + + r_p=instruction->instruction_parameters[0].parameter_data.r; + if ((((LONG*)r_p)[0] | ((LONG*)r_p)[1])==0){ + store_l (0xeeb50b40 | (d_freg<<12)); /* vcmp.f64 dd,#0.0 */ + } else { + as_vldr_r_id (15,0,REGISTER_PC); + as_float_literal_entry (instruction->instruction_parameters[0].parameter_data.r); + as_vcmp_f64_r_r (15,d_freg); + } + return; + } + case P_INDIRECT: + as_vldr_r_id (15,instruction->instruction_parameters[0].parameter_offset, + instruction->instruction_parameters[0].parameter_data.reg.r); + as_vcmp_f64_r_r (15,d_freg); + return; + case P_INDEXED: + as_add_r_lsl_r_r (instruction->instruction_parameters[0].parameter_data.ir->d_reg.r, + instruction->instruction_parameters[0].parameter_offset & 3, + instruction->instruction_parameters[0].parameter_data.ir->a_reg.r,REGISTER_S0); + as_vldr_r_id (15,instruction->instruction_parameters[0].parameter_offset>>2,REGISTER_S0); + as_vcmp_f64_r_r (15,d_freg); + return; + case P_F_REGISTER: + as_vcmp_f64_r_r (instruction->instruction_parameters[0].parameter_data.reg.r,d_freg); + return; + default: + internal_error_in_function ("as_compare_float_instruction"); + return; + } +} + +static void as_monadic_float_instruction (struct instruction *instruction,int code) +{ + int s_freg,d_freg; + + switch (instruction->instruction_parameters[0].parameter_type){ + case P_F_IMMEDIATE: + as_vldr_r_id (15,0,REGISTER_PC); + as_float_literal_entry (instruction->instruction_parameters[0].parameter_data.r); + s_freg=15; + break; + case P_INDIRECT: + as_vldr_r_id (15,instruction->instruction_parameters[0].parameter_offset, + instruction->instruction_parameters[0].parameter_data.reg.r); + s_freg=15; + break; + case P_INDEXED: + as_add_r_lsl_r_r (instruction->instruction_parameters[0].parameter_data.ir->d_reg.r, + instruction->instruction_parameters[0].parameter_offset & 3, + instruction->instruction_parameters[0].parameter_data.ir->a_reg.r,REGISTER_S0); + as_vldr_r_id (15,instruction->instruction_parameters[0].parameter_offset>>2,REGISTER_S0); + s_freg=15; + break; + case P_F_REGISTER: + s_freg = instruction->instruction_parameters[0].parameter_data.reg.r; + break; + default: + internal_error_in_function ("as_dyadic_float_instruction"); + return; + } + + d_freg=instruction->instruction_parameters[1].parameter_data.reg.r; + store_l (0xeeb00b40 | code | (d_freg<<12) | s_freg); +} + +static void as_test_floating_point_condition_code (void) +{ + store_l (0xeef1fa10); /* vmrs APSR_nzcv,fpscr */ + /* APSR_nzcv is encoded as register 15, fpscr as register 1 */ +} + +static void as_float_branch_instruction (struct instruction *instruction,int condition_code) +{ + as_test_floating_point_condition_code(); + /* Z N C V + equal 1 0 1 0 + less than 0 1 0 0 + greater than 0 0 1 0 + unordered 0 0 1 1 + + bgt Z==0 && N==V + ble Z==1 || N!=V + */ + + store_l ((condition_code<<28) | 0x0a000000); /* b */ + as_branch_label (instruction->instruction_parameters[0].parameter_data.l,BRANCH_RELOCATION); +} + +static void as_set_float_condition_instruction (struct instruction *instruction,int condition_code_true,int condition_code_false) +{ + as_test_floating_point_condition_code(); + + as_set_condition_instruction (instruction,condition_code_true,condition_code_false); +} + +void define_data_label (LABEL *label) +{ + label->label_id=DATA_LABEL_ID; +#ifdef FUNCTION_LEVEL_LINKING + label->label_object_label=data_object_label; +#endif + label->label_offset=CURRENT_DATA_OFFSET; + + if (label->label_flags & EXPORT_LABEL){ + struct object_label *new_object_label; + int string_length; + + new_object_label=fast_memory_allocate_type (struct object_label); + *last_object_label_l=new_object_label; + last_object_label_l=&new_object_label->next; + new_object_label->next=NULL; + + new_object_label->object_label_label=label; +#if defined (RELOCATIONS_RELATIVE_TO_EXPORTED_DATA_LABEL) && defined (FUNCTION_LEVEL_LINKING) + new_object_label->object_label_number = n_object_labels; +#endif + + ++n_object_labels; + + string_length=strlen (label->label_name); +#ifndef ELF + if (string_length<8) + new_object_label->object_label_string_offset=0; + else +#endif + { + new_object_label->object_label_string_offset=string_table_offset; + string_table_offset+=string_length+1; + } + +#if defined (RELOCATIONS_RELATIVE_TO_EXPORTED_DATA_LABEL) && defined (FUNCTION_LEVEL_LINKING) + label->label_object_label=new_object_label; + new_object_label->object_label_section_n = data_object_label->object_label_section_n; +#endif + + new_object_label->object_label_kind=EXPORTED_DATA_LABEL; + } +} + +void store_descriptor_string_in_data_section (char *string,int length,LABEL *string_label) +{ + define_data_label (string_label); + store_abc_string_in_data_section (string,length); +} + +static void as_fmovel_instruction (struct instruction *instruction) +{ + if (instruction->instruction_parameters[0].parameter_type==P_F_REGISTER){ + if (instruction->instruction_parameters[1].parameter_type==P_REGISTER){ + int s_freg; + + s_freg=instruction->instruction_parameters[0].parameter_data.reg.r; + + /* s30 */ + store_l (0xeebd0b40 | (15<<12) | s_freg); /* vcvtr.s32.f64 sd,dm */ + store_l (0xee100a10 | (15<<16) | (reg_num (instruction->instruction_parameters[1].parameter_data.reg.r)<<12)); /* vmov rt,sn */ + return; + } else + internal_error_in_function ("as_fmovel_instruction"); + } else { + int freg; + + switch (instruction->instruction_parameters[0].parameter_type){ + case P_REGISTER: + freg=instruction->instruction_parameters[1].parameter_data.reg.r; + store_l (0xee000a10 | (freg<<16) | (reg_num (instruction->instruction_parameters[0].parameter_data.reg.r)<<12)); /* vmov sn,rt */ + break; + case P_INDIRECT: + as_vldr_r_id (15,instruction->instruction_parameters[0].parameter_offset, + instruction->instruction_parameters[0].parameter_data.reg.r); + freg=instruction->instruction_parameters[1].parameter_data.reg.r; + store_l (0xee000a10 | (freg<<16) | (reg_num (REGISTER_S0)<<12)); /* vmov sn,rt */ + break; + case P_INDEXED: + as_add_r_lsl_r_r (instruction->instruction_parameters[0].parameter_data.ir->d_reg.r, + instruction->instruction_parameters[0].parameter_offset & 3, + instruction->instruction_parameters[0].parameter_data.ir->a_reg.r,REGISTER_S0); + as_vldr_r_id (15,instruction->instruction_parameters[0].parameter_offset>>2,REGISTER_S0); + freg=instruction->instruction_parameters[1].parameter_data.reg.r; + store_l (0xee000a10 | (freg<<16) | (reg_num (REGISTER_S0)<<12)); /* vmov sn,rt */ + break; + case P_IMMEDIATE: + freg=instruction->instruction_parameters[1].parameter_data.reg.r; + + as_vldr_s_id (freg,0,REGISTER_PC); + as_float_load_int_literal_entry (instruction->instruction_parameters[0].parameter_data.i); + break; + default: + internal_error_in_function ("as_fmovel_instruction"); + return; + } + store_l (0xeeb80bc0 | (freg<<12) | freg); /* vcvt.f64.s32 dd,sm */ + return; + } +} + +static void as_labels (struct block_label *labels) +{ + for (; labels!=NULL; labels=labels->block_label_next) +#if 0 + if (labels->block_label_label->label_number==0) +#endif + { + LABEL *label; + + label=labels->block_label_label; + + label->label_id=TEXT_LABEL_ID; +#ifdef FUNCTION_LEVEL_LINKING + label->label_object_label=code_object_label; +#endif + label->label_offset=CURRENT_CODE_OFFSET; + + if (label->label_flags & EXPORT_LABEL){ + struct object_label *new_object_label; + int string_length; + + new_object_label=fast_memory_allocate_type (struct object_label); + *last_object_label_l=new_object_label; + last_object_label_l=&new_object_label->next; + new_object_label->next=NULL; + + new_object_label->object_label_label=label; + + ++n_object_labels; + + string_length=strlen (label->label_name); +#ifndef ELF + if (string_length<8) + new_object_label->object_label_string_offset=0; + else +#endif + { + new_object_label->object_label_string_offset=string_table_offset; + string_table_offset+=string_length+1; + } + + new_object_label->object_label_kind=EXPORTED_CODE_LABEL; + } + } +} + +static void as_instructions (struct instruction *instruction) +{ + while (instruction!=NULL){ + switch (instruction->instruction_icode){ + case IMOVE: + as_move_instruction (instruction); + break; + case ILEA: + as_lea_instruction (instruction); + break; + case IADD: + as_add_instruction (instruction); + break; + case ISUB: + as_sub_instruction (instruction); + break; + case ICMP: + as_cmp_instruction (instruction); + break; + case IJMP: + as_jmp_instruction (instruction); + break; + case IJMPP: + as_jmpp_instruction (instruction); + break; + case IJSR: + as_jsr_instruction (instruction); + break; + case IRTS: + as_rts_instruction(); + break; + case IRTSI: + as_rtsi_instruction (instruction); + break; + case IRTSP: + store_l (0xea000000); /* b */ + as_branch_label (profile_r_label,JUMP_RELOCATION); + break; + case IBEQ: + as_branch_instruction (instruction,CONDITION_EQ); + break; + case IBGE: + as_branch_instruction (instruction,CONDITION_GE); + break; + case IBGEU: + as_branch_instruction (instruction,CONDITION_HS); + break; + case IBGT: + as_branch_instruction (instruction,CONDITION_GT); + break; + case IBGTU: + as_branch_instruction (instruction,CONDITION_HI); + break; + case IBLE: + as_branch_instruction (instruction,CONDITION_LE); + break; + case IBLEU: + as_branch_instruction (instruction,CONDITION_LS); + break; + case IBLT: + as_branch_instruction (instruction,CONDITION_LT); + break; + case IBLTU: + as_branch_instruction (instruction,CONDITION_LO); + break; + case IBNE: + as_branch_instruction (instruction,CONDITION_NE); + break; + case IBO: + as_branch_instruction (instruction,CONDITION_VS); + break; + case IBNO: + as_branch_instruction (instruction,CONDITION_VC); + break; + case ILSL: + as_shift_instruction (instruction,ARM_OP_LSL); + break; + case ILSR: + as_shift_instruction (instruction,ARM_OP_LSR); + break; + case IASR: + as_shift_instruction (instruction,ARM_OP_ASR); + break; + case IMUL: + as_mul_instruction (instruction); + break; + case IDIV: + as_div_instruction (instruction); + break; + case IREM: + as_rem_instruction (instruction); + break; + case IAND: + as_logic_instruction (instruction,ARM_OP_AND); + break; + case IOR: + as_logic_instruction (instruction,ARM_OP_ORR); + break; + case IEOR: + as_logic_instruction (instruction,ARM_OP_EOR); + break; + case IADDI: + as_addi_instruction (instruction); + break; + case ILSLI: + as_lsli_instruction (instruction); + break; + case ISEQ: + as_set_condition_instruction (instruction,CONDITION_EQ,CONDITION_NE); + break; + case ISGE: + as_set_condition_instruction (instruction,CONDITION_GE,CONDITION_LT); + break; + case ISGEU: + as_set_condition_instruction (instruction,CONDITION_HS,CONDITION_LO); + break; + case ISGT: + as_set_condition_instruction (instruction,CONDITION_GT,CONDITION_LE); + break; + case ISGTU: + as_set_condition_instruction (instruction,CONDITION_HI,CONDITION_LS); + break; + case ISLE: + as_set_condition_instruction (instruction,CONDITION_LE,CONDITION_GT); + break; + case ISLEU: + as_set_condition_instruction (instruction,CONDITION_LS,CONDITION_HI); + break; + case ISLT: + as_set_condition_instruction (instruction,CONDITION_LT,CONDITION_GE); + break; + case ISLTU: + as_set_condition_instruction (instruction,CONDITION_LO,CONDITION_HS); + break; + case ISNE: + as_set_condition_instruction (instruction,CONDITION_NE,CONDITION_EQ); + break; + case ISO: + as_set_condition_instruction (instruction,CONDITION_VS,CONDITION_VC); + break; + case ISNO: + as_set_condition_instruction (instruction,CONDITION_VC,CONDITION_VS); + break; + case ITST: + as_tst_instruction (instruction); + break; + case IBTST: + as_btst_instruction (instruction); + break; + case IMOVEDB: + as_movew_instruction (instruction); + break; + case IMOVEB: + as_moveb_instruction (instruction); + break; + case INEG: + as_neg_instruction (instruction); + break; + case INOT: + as_not_instruction (instruction); + break; + case IMOVEM: + as_movem_instruction (instruction); + break; + case IADC: + as_add_or_sub_x_instruction (instruction,ARM_OP_ADC<<1,ARM_OP_SBC<<1); + break; + case ISBB: + as_add_or_sub_x_instruction (instruction,ARM_OP_SBC<<1,ARM_OP_ADC<<1); + break; + case IWORD: + store_l (instruction->instruction_parameters[0].parameter_data.i); + break; + case IROTR: + as_shift_instruction (instruction,ARM_OP_ROR); + break; + case IADDO: + as_add_or_sub_x_instruction (instruction,(ARM_OP_ADD<<1) | 1,(ARM_OP_SUB<<1) | 1); + break; + case ISUBO: + as_add_or_sub_x_instruction (instruction,(ARM_OP_SUB<<1) | 1,(ARM_OP_ADD<<1) | 1); + break; + case IFMOVE: + as_fmove_instruction (instruction); + break; + case IFADD: + as_dyadic_float_instruction (instruction,0x00300000); + break; + case IFSUB: + as_float_sub_or_div_instruction (instruction,0x00300040); + break; + case IFCMP: + as_compare_float_instruction (instruction); + break; + case IFDIV: + as_float_sub_or_div_instruction (instruction,0x00800000); + break; + case IFMUL: + as_dyadic_float_instruction (instruction,0x00200000); + break; + case IFBEQ: + as_float_branch_instruction (instruction,CONDITION_EQ); + break; + case IFBGE: + as_float_branch_instruction (instruction,CONDITION_PL); + break; + case IFBGT: + as_float_branch_instruction (instruction,CONDITION_GT); + break; + case IFBLE: + as_float_branch_instruction (instruction,CONDITION_LE); + break; + case IFBLT: + as_float_branch_instruction (instruction,CONDITION_MI); + break; + case IFBNE: + as_float_branch_instruction (instruction,CONDITION_NE); + break; + case IFMOVEL: + as_fmovel_instruction (instruction); + break; + case IFLOADS: + as_floads_instruction (instruction); + break; + case IFMOVES: + as_fmoves_instruction (instruction); + break; + case IFSQRT: + as_monadic_float_instruction (instruction,0x10080); + break; + case IFNEG: + as_monadic_float_instruction (instruction,0x10000); + break; + case IFABS: + as_monadic_float_instruction (instruction,0x00080); + break; + case IFSEQ: + as_set_float_condition_instruction (instruction,CONDITION_EQ,CONDITION_NE); + break; + case IFSGE: + as_set_float_condition_instruction (instruction,CONDITION_PL,CONDITION_MI); + break; + case IFSGT: + as_set_float_condition_instruction (instruction,CONDITION_GT,CONDITION_LE); + break; + case IFSLE: + as_set_float_condition_instruction (instruction,CONDITION_LE,CONDITION_GT); + break; + case IFSLT: + as_set_float_condition_instruction (instruction,CONDITION_MI,CONDITION_PL); + break; + case IFSNE: + as_set_float_condition_instruction (instruction,CONDITION_NE,CONDITION_EQ); + break; + default: + internal_error_in_function ("as_instructions"); + } + instruction=instruction->instruction_next; + } +} + +static void as_garbage_collect_test (struct basic_block *block) +{ + LONG n_cells; + struct call_and_jump *new_call_and_jump; + int shift; + + n_cells=block->block_n_new_heap_cells; + + new_call_and_jump=allocate_memory_from_heap (sizeof (struct call_and_jump)); + new_call_and_jump->cj_next=NULL; + + switch (block->block_n_begin_a_parameter_registers){ + case 0: + new_call_and_jump->cj_call_label=collect_0_label; + break; + case 1: + new_call_and_jump->cj_call_label=collect_1_label; + break; + case 2: + new_call_and_jump->cj_call_label=collect_2_label; + break; + case 3: + new_call_and_jump->cj_call_label=collect_3_label; + break; + default: + internal_error_in_function ("as_garbage_collect_test"); + return; + } + + if (first_call_and_jump!=NULL) + last_call_and_jump->cj_next=new_call_and_jump; + else + first_call_and_jump=new_call_and_jump; + last_call_and_jump=new_call_and_jump; + + shift = immediate_shift (n_cells); + if (shift>=0){ + as_subs_is_r_r (n_cells,shift,REGISTER_R5,REGISTER_R5); + } else { + store_l (0xe59f0000 | (reg_num (REGISTER_S0)<<12)); /* ldr rt,[pc+imm] */ + as_literal_constant_entry (n_cells); + + as_x_op_r_r_r ((ARM_OP_SUB<<1) | 1,REGISTER_S0,REGISTER_R5,REGISTER_R5); /* subs */ + } + + store_l ((CONDITION_LO<<28) | 0x0a000000); /* blo */ + as_branch_label (&new_call_and_jump->cj_label,BRANCH_RELOCATION); + + new_call_and_jump->cj_jump.label_flags=0; + new_call_and_jump->cj_jump.label_id=TEXT_LABEL_ID; +#ifdef FUNCTION_LEVEL_LINKING + new_call_and_jump->cj_jump.label_object_label=code_object_label; +#endif + new_call_and_jump->cj_jump.label_offset=CURRENT_CODE_OFFSET; +} + +static void as_call_and_jump (struct call_and_jump *call_and_jump) +{ + call_and_jump->cj_label.label_flags=0; + call_and_jump->cj_label.label_id=TEXT_LABEL_ID; +#ifdef FUNCTION_LEVEL_LINKING + call_and_jump->cj_label.label_object_label=code_object_label; +#endif + call_and_jump->cj_label.label_offset=CURRENT_CODE_OFFSET; + + store_l (0xeb000000); /* bl */ + as_branch_label (call_and_jump->cj_call_label,CALL_RELOCATION); + + store_l (0xea000000); /* b */ + as_branch_label (&call_and_jump->cj_jump,JUMP_RELOCATION); +} + +static void as_check_stack (struct basic_block *block) +{ +#if 0 + if (block->block_a_stack_check_size>0){ + if (block->block_a_stack_check_size<=32) + as_r_a (0073,A_STACK_POINTER,end_a_stack_label); /* cmp */ + else { + as_id_r (0215,block->block_a_stack_check_size,A_STACK_POINTER,REGISTER_S0); /* lea */ + as_r_a (0073,REGISTER_S0,end_a_stack_label); /* cmp */ + } + + store_c (0x0f); + store_c (0x83); /* jae */ + store_l (0); + as_branch_label (stack_overflow_label,BRANCH_RELOCATION); + } + + if (block->block_b_stack_check_size>0){ + if (block->block_b_stack_check_size<=32) + as_r_a (0073,B_STACK_POINTER,end_b_stack_label); /* cmp */ + else { + as_id_r (0215,block->block_b_stack_check_size,B_STACK_POINTER,REGISTER_S0); /* lea */ + as_r_a (0073,REGISTER_S0,end_b_stack_label); /* cmp */ + } + + store_c (0x0f); + store_c (0x82); /* jb */ + store_l (0); + as_branch_label (stack_overflow_label,BRANCH_RELOCATION); + } +#else + internal_error_in_function ("as_check_stack"); +#endif +} + +static void as_profile_call (struct basic_block *block) +{ + LABEL *profile_label; + + as_move_d_r (block->block_profile_function_label,0,REGISTER_A2); + + if (block->block_n_node_arguments>-100) + profile_label=block->block_profile==2 ? profile_n2_label : profile_n_label; + else { + switch (block->block_profile){ + case 2: profile_label=profile_s2_label; break; + case 4: profile_label=profile_l_label; break; + case 5: profile_label=profile_l2_label; break; + default: profile_label=profile_s_label; + } + } + store_l (0xeb000000); /* bl */ + as_branch_label (profile_label,CALL_RELOCATION); +} + +#ifdef NEW_APPLY +extern LABEL *add_empty_node_labels[]; + +static void as_apply_update_entry (struct basic_block *block) +{ + if (block->block_profile) + as_profile_call (block); + + if (block->block_n_node_arguments==-200){ + store_l (0xea000000); /* b */ + as_branch_label (block->block_ea_label,JUMP_RELOCATION); + + as_nop(); + } else { + store_l (0xeb000000); /* bl */ + as_branch_label (add_empty_node_labels[block->block_n_node_arguments+200],CALL_RELOCATION); + + store_l (0xea000000); /* b */ + as_branch_label (block->block_ea_label,JUMP_RELOCATION); + } +} +#endif + +static void as_node_entry_info (struct basic_block *block) +{ + if (block->block_ea_label!=NULL){ + extern LABEL *eval_fill_label,*eval_upd_labels[]; + int n_node_arguments; + + n_node_arguments=block->block_n_node_arguments; + if (n_node_arguments<-2) + n_node_arguments=1; + + if (n_node_arguments>=0 && block->block_ea_label!=eval_fill_label){ + if (!block->block_profile){ + as_move_l_r (block->block_ea_label,REGISTER_A3); + + store_l (0xea000000); /* b */ + as_branch_label (eval_upd_labels[n_node_arguments],JUMP_RELOCATION); + + if (!pic_flag) + as_nop(); + } else { + as_move_l_r (block->block_ea_label,REGISTER_D0); + as_move_l_r (block->block_profile_function_label,REGISTER_A3); + + store_l (0xea000000); /* b */ + as_branch_label (eval_upd_labels[n_node_arguments],JUMP_RELOCATION); + } + } else { + store_l (0xea000000); /* b */ + as_branch_label (block->block_ea_label,JUMP_RELOCATION); + + as_nop(); + as_nop(); + } + + begin_data_mapping(); + + if (block->block_descriptor!=NULL && (block->block_n_node_arguments<0 || parallel_flag || module_info_flag)){ + store_l (0); + if (!pic_flag) + store_label_in_code_section (block->block_descriptor); + else + store_relative_label_in_code_section (block->block_descriptor); + } else + store_l (0); + } else { + begin_data_mapping(); + + if (block->block_descriptor!=NULL && (block->block_n_node_arguments<0 || parallel_flag || module_info_flag)){ + store_l (0); + if (!pic_flag) + store_label_in_code_section (block->block_descriptor); + else + store_relative_label_in_code_section (block->block_descriptor); + } + /* else + store_l (0); + */ + } + + store_l (block->block_n_node_arguments); + + last_mapping_symbol->ms_code_offset = CURRENT_CODE_OFFSET; +} + +static void write_code (void) +{ + struct basic_block *block; + struct call_and_jump *call_and_jump; + +#ifdef FUNCTION_LEVEL_LINKING + if (first_block!=NULL && !(first_block->block_begin_module && !first_block->block_link_module)) + first_block->block_begin_module=1; +#endif + + literal_entry_l=&first_literal_entry; + first_literal_entry=NULL; + + for_l (block,first_block,block_next){ +#ifdef FUNCTION_LEVEL_LINKING + if (block->block_begin_module){ + if (block->block_link_module){ + if (code_object_label!=NULL && CURRENT_CODE_OFFSET!=code_object_label->object_label_offset && block->block_labels){ +#if 1 + switch (3 & -(CURRENT_CODE_OFFSET-code_object_label->object_label_offset)){ + case 0: + break; + case 1: + store_c (0x90); + break; + case 2: + store_c (0213); + store_c (0300 | (reg_num (EBP)<<3) | reg_num (EBP)); + break; + case 3: + store_c (0215); + store_c (0x40 | (reg_num (EBP)<<3) | reg_num (EBP)); + store_c (0); + break; + } +#else + while (((CURRENT_CODE_OFFSET-code_object_label->object_label_offset) & 3)!=0) + store_c (0x90); +#endif + { + struct relocation *new_relocation; + + new_relocation=fast_memory_allocate_type (struct relocation); + + *last_code_relocation_l=new_relocation; + last_code_relocation_l=&new_relocation->next; + new_relocation->next=NULL; + + U4 (new_relocation, + relocation_label=block->block_labels->block_label_label, + relocation_offset=CURRENT_CODE_OFFSET, + relocation_object_label=code_object_label, + relocation_kind=DUMMY_BRANCH_RELOCATION); + } +#ifdef FUNCTION_LEVEL_LINKING + as_new_code_module(); +#endif + *(struct object_label**)&block->block_last_instruction = code_object_label; + } else + *(struct object_label**)&block->block_last_instruction = NULL; + } else { +#ifdef FUNCTION_LEVEL_LINKING + write_literals(); + as_new_code_module(); +#endif + *(struct object_label**)&block->block_last_instruction = code_object_label; + } + } else + *(struct object_label**)&block->block_last_instruction = NULL; +#endif + + if (block->block_n_node_arguments>-100){ +#ifndef FUNCTION_LEVEL_LINKING + while ((code_buffer_free & 3)!=0) + store_c (0x90); +#endif + + as_node_entry_info (block); + } +#ifdef NEW_APPLY + else if (block->block_n_node_arguments<-100) + as_apply_update_entry (block); +#endif + + as_labels (block->block_labels); + + if (block->block_profile) + as_profile_call (block); + + if (block->block_n_new_heap_cells>0) + as_garbage_collect_test (block); + + if (check_stack && (block->block_a_stack_check_size>0 || block->block_b_stack_check_size>0)) + as_check_stack (block); + + as_instructions (block->block_instructions); + } + + write_literals(); + + for_l (call_and_jump,first_call_and_jump,cj_next){ +#ifdef FUNCTION_LEVEL_LINKING + as_new_code_module(); +#endif + as_call_and_jump (call_and_jump); + } +} + +static void write_string_8 (char *string) +{ + int i; + + i=0; + + while (i<8){ + char c; + + c=string[i++]; + write_c (c); + + if (c=='\0'){ + while (i<8){ + write_c ('\0'); + ++i; + } + return; + } + } +} + +#ifdef ELF +static void write_zstring (char *string) +{ + char c; + + do { + c=*string++; + write_c (c); + } while (c!='\0'); +} +#endif + +extern char *this_module_name; + +#if defined (ELF) && defined (FUNCTION_LEVEL_LINKING) +static int compute_section_strings_size (int string_size_without_digits,int n_sections) +{ + int section_strings_size,max_n_digits,power10_max_n_digits; + + section_strings_size=0; + max_n_digits=1; + power10_max_n_digits=10; + while (n_sections>power10_max_n_digits){ + section_strings_size-=power10_max_n_digits; + ++max_n_digits; + power10_max_n_digits*=10; + } + section_strings_size+=(string_size_without_digits+max_n_digits+1)*n_sections; + + return section_strings_size; +} + +static int n_digits (int n) +{ + int i,power10; + + i=1; + power10=10; + + while (n>=power10){ + ++i; + power10*=10; + } + + return i; +} + +static int n_sections; +static int n_local_section_and_mapping_symbols; +#endif + +static void write_file_header_and_section_headers (void) +{ + unsigned int offset; + int n_code_relocation_sections,n_data_relocation_sections; + int section_strings_size; + +#ifdef FUNCTION_LEVEL_LINKING + n_sections=n_code_sections+n_data_sections; + n_local_section_and_mapping_symbols=n_sections+n_mapping_symbols; + + { + struct object_label *object_label,*previous_code_object_label,*previous_data_object_label; + struct relocation *code_relocation,*data_relocation; + int code_offset,data_offset; + + code_relocation=first_code_relocation; + code_offset=0; + n_code_relocation_sections=0; + previous_code_object_label=NULL; + + data_relocation=first_data_relocation; + data_offset=0; + n_data_relocation_sections=0; + previous_data_object_label=NULL; + + section_strings_size=0; + + for_l (object_label,first_object_label,next){ + if (object_label->object_label_kind==CODE_CONTROL_SECTION){ + if (previous_code_object_label!=NULL){ + int code_section_length,n_code_relocations_in_section; + + code_section_length=object_label->object_label_offset-code_offset; + + n_code_relocations_in_section=0; + while (code_relocation!=NULL && + (code_relocation->relocation_offset < code_offset+code_section_length + || (code_relocation->relocation_offset==code_offset+code_section_length && code_relocation->relocation_kind==DUMMY_BRANCH_RELOCATION))) + { + code_relocation->relocation_offset-=code_offset; + ++n_code_relocations_in_section; + + code_relocation=code_relocation->next; + } + + previous_code_object_label->object_label_length=code_section_length; + previous_code_object_label->object_label_n_relocations=n_code_relocations_in_section; + + code_offset+=code_section_length; + if (n_code_relocations_in_section>0){ + section_strings_size+=12+n_digits (previous_code_object_label->object_label_section_n); + ++n_code_relocation_sections; + } + } + + previous_code_object_label=object_label; + } else if (object_label->object_label_kind==DATA_CONTROL_SECTION){ + if (previous_data_object_label!=NULL){ + int data_section_length,n_data_relocations_in_section; + + data_section_length=object_label->object_label_offset-data_offset; + + n_data_relocations_in_section=0; + while (data_relocation!=NULL && data_relocation->relocation_offset < data_offset+data_section_length){ + data_relocation->relocation_offset-=data_offset; + ++n_data_relocations_in_section; + + data_relocation=data_relocation->next; + } + + previous_data_object_label->object_label_length=data_section_length; + previous_data_object_label->object_label_n_relocations=n_data_relocations_in_section; + + data_offset+=data_section_length; + if (n_data_relocations_in_section>0){ + section_strings_size+=12+n_digits (previous_data_object_label->object_label_section_n); + ++n_data_relocation_sections; + } + } + + previous_data_object_label=object_label; + } + } + + if (previous_code_object_label!=NULL){ + int code_section_length,n_code_relocations_in_section; + + code_section_length=code_buffer_offset-code_offset; + + n_code_relocations_in_section=0; + while (code_relocation!=NULL){ + code_relocation->relocation_offset-=code_offset; + ++n_code_relocations_in_section; + + code_relocation=code_relocation->next; + } + + previous_code_object_label->object_label_n_relocations=n_code_relocations_in_section; + previous_code_object_label->object_label_length=code_section_length; + + if (n_code_relocations_in_section>0){ + section_strings_size+=12+n_digits (previous_code_object_label->object_label_section_n); + ++n_code_relocation_sections; + } + } + + if (previous_data_object_label!=NULL){ + int data_section_length,n_data_relocations_in_section; + + data_section_length=data_buffer_offset-data_offset; + + n_data_relocations_in_section=0; + while (data_relocation!=NULL){ + data_relocation->relocation_offset-=data_offset; + ++n_data_relocations_in_section; + + data_relocation=data_relocation->next; + } + + previous_data_object_label->object_label_n_relocations=n_data_relocations_in_section; + previous_data_object_label->object_label_length=data_section_length; + + if (n_data_relocations_in_section>0){ + section_strings_size+=12+n_digits (previous_data_object_label->object_label_section_n); + ++n_data_relocation_sections; + } + } + } + + section_strings_size+=compute_section_strings_size (7,n_code_sections)+ + compute_section_strings_size (7,n_data_sections); +#endif + + write_l (0x464c457f); + write_l (0x00010101); + write_l (0); + write_l (0); + write_l (0x00280001); + write_l (1); + write_l (0); + write_l (0); + write_l (0x34); + write_l (EF_ARM_EABI_VER5); + write_l (0x00000034); + write_l (0x00280000); +#ifdef FUNCTION_LEVEL_LINKING + write_l (0x00010000 | (n_sections+n_code_relocation_sections+n_data_relocation_sections+4)); +#else + write_l (0x00010008); +#endif + + write_l (0); + write_l (0); + write_l (0); + write_l (0); + write_l (0); + write_l (0); + write_l (0); + write_l (0); + write_l (0); + write_l (0); +#ifdef FUNCTION_LEVEL_LINKING + offset=0xd4+40*(n_sections+n_code_relocation_sections+n_data_relocation_sections); +#else + offset=0x174; +#endif + + write_l (1); + write_l (SHT_STRTAB); + write_l (0); + write_l (0); + write_l (offset); +#ifdef FUNCTION_LEVEL_LINKING + write_l ((27+section_strings_size+3) & -4); +#else + write_l (60); +#endif + write_l (0); + write_l (0); + write_l (1); + write_l (0); +#ifdef FUNCTION_LEVEL_LINKING + offset+=(27+section_strings_size+3) & -4; +#else + offset+=60; +#endif +#ifdef FUNCTION_LEVEL_LINKING + { + struct object_label *object_label; + int code_offset,data_offset,code_relocations_offset,data_relocations_offset,section_string_offset; + + code_offset=0; + section_string_offset=11; + + for_l (object_label,first_object_label,next){ + if (object_label->object_label_kind==CODE_CONTROL_SECTION){ + int code_section_length; + + code_section_length=object_label->object_label_length; + + write_l (section_string_offset); + write_l (SHT_PROGBITS); + write_l (SHF_ALLOC | SHF_EXECINSTR); + write_l (0); + write_l (offset+code_offset); + write_l (code_section_length); + write_l (0); + write_l (0); + write_l (4); + write_l (0); + + section_string_offset+=8+n_digits (object_label->object_label_section_n); + code_offset+=code_section_length; + } + } + offset+=(code_offset+3) & -4; + + data_offset=0; + + for_l (object_label,first_object_label,next){ + if (object_label->object_label_kind==DATA_CONTROL_SECTION){ + int data_section_length; + + data_section_length=object_label->object_label_length; + + write_l (section_string_offset); + write_l (SHT_PROGBITS); + write_l (SHF_ALLOC | SHF_WRITE); + write_l (0); + write_l (offset+data_offset); + write_l (data_section_length); + write_l (0); + write_l (0); + write_l (object_label->object_section_align8 ? 8 : 4); + write_l (0); + + section_string_offset+=8+n_digits (object_label->object_label_section_n); + data_offset+=data_section_length; + } + } + + offset+=(data_offset+3) & -4; + + code_relocations_offset=0; + + for_l (object_label,first_object_label,next){ + if (object_label->object_label_kind==CODE_CONTROL_SECTION){ + int n_code_relocations_in_section; + + n_code_relocations_in_section=object_label->object_label_n_relocations; + + if (n_code_relocations_in_section>0){ + write_l (section_string_offset); + write_l (SHT_REL); + write_l (0); + write_l (0); + write_l (offset+code_relocations_offset); + write_l (8*n_code_relocations_in_section); + write_l (n_sections+n_code_relocation_sections+n_data_relocation_sections+2); + write_l (2+object_label->object_label_section_n); + write_l (4); + write_l (8); + section_string_offset+=12+n_digits (object_label->object_label_section_n); + code_relocations_offset+=8*n_code_relocations_in_section; + } + } + } + offset+=8*n_code_relocations; + + data_relocations_offset=0; + + for_l (object_label,first_object_label,next){ + if (object_label->object_label_kind==DATA_CONTROL_SECTION){ + int n_data_relocations_in_section; + + n_data_relocations_in_section=object_label->object_label_n_relocations; + + if (n_data_relocations_in_section>0){ + write_l (section_string_offset); + write_l (SHT_REL); + write_l (0); + write_l (0); + write_l (offset+data_relocations_offset); + write_l (8*n_data_relocations_in_section); + write_l (n_sections+n_code_relocation_sections+n_data_relocation_sections+2); + write_l (2+n_code_sections+object_label->object_label_section_n); + write_l (4); + write_l (8); + section_string_offset+=12+n_digits (object_label->object_label_section_n); + data_relocations_offset+=8*n_data_relocations_in_section; + } + } + } + offset+=8*n_data_relocations; + } +#else + write_l (11); + write_l (SHT_PROGBITS); + write_l (SHF_ALLOC | SHF_EXECINSTR); + write_l (0); + write_l (offset); + write_l (code_buffer_offset); + write_l (0); + write_l (0); + write_l (4); + write_l (0); + offset+=(code_buffer_offset+3 ) & ~3; + + write_l (17); + write_l (SHT_PROGBITS); + write_l (SHF_ALLOC | SHF_WRITE); + write_l (0); + write_l (offset); + write_l (data_buffer_offset); + write_l (0); + write_l (0); + write_l (4); + write_l (0); + offset+=(data_buffer_offset+3) & ~3; + + write_l (23); + write_l (SHT_REL); + write_l (0); + write_l (0); + write_l (offset); + write_l (8*n_code_relocations); + write_l (6); + write_l (2); + write_l (4); + write_l (8); + offset+=8*n_code_relocations; + + write_l (33); + write_l (SHT_REL); + write_l (0); + write_l (0); + write_l (offset); + write_l (8*n_data_relocations); + write_l (6); + write_l (3); + write_l (4); + write_l (8); + offset+=8*n_data_relocations; +#endif + +#ifdef FUNCTION_LEVEL_LINKING + write_l (11+section_strings_size); +#else + write_l (43); +#endif + write_l (SHT_SYMTAB); + write_l (0); + write_l (0); + write_l (offset); +#ifdef FUNCTION_LEVEL_LINKING + write_l (16*(n_object_labels+n_local_section_and_mapping_symbols)); + write_l (n_sections+n_code_relocation_sections+n_data_relocation_sections+3); + write_l (1+n_local_section_and_mapping_symbols); +#else + write_l (16*n_object_labels); + write_l (7); + write_l (3); +#endif + write_l (4); + write_l (16); +#ifdef FUNCTION_LEVEL_LINKING + offset+=16*(n_object_labels+n_local_section_and_mapping_symbols); +#else + offset+=16*n_object_labels; +#endif + +#ifdef FUNCTION_LEVEL_LINKING + write_l (19+section_strings_size); +#else + write_l (51); +#endif + write_l (SHT_STRTAB); + write_l (0); + write_l (0); + write_l (offset); + write_l (string_table_offset); + write_l (0); + write_l (0); + write_l (0); + write_l (0); + + write_c (0); + write_zstring (".shstrtab"); +#ifdef FUNCTION_LEVEL_LINKING + { + struct object_label *object_label; + int section_n; + char section_name[20]; + + for (section_n=0; section_n<n_code_sections; ++section_n){ + sprintf (section_name,".text.m%d",section_n); + write_zstring (section_name); + } + + for (section_n=0; section_n<n_data_sections; ++section_n){ + sprintf (section_name,".data.m%d",section_n); + write_zstring (section_name); + } + + for_l (object_label,first_object_label,next) + if (object_label->object_label_kind==CODE_CONTROL_SECTION && object_label->object_label_n_relocations>0){ + sprintf (section_name,".rel.text.m%d",object_label->object_label_section_n); + write_zstring (section_name); + } + + for_l (object_label,first_object_label,next) + if (object_label->object_label_kind==DATA_CONTROL_SECTION && object_label->object_label_n_relocations>0){ + sprintf (section_name,".rel.data.m%d",object_label->object_label_section_n); + write_zstring (section_name); + } + } +#else + write_zstring (".text"); + write_zstring (".data"); + write_zstring (".rel.text"); + write_zstring (".rel.data"); +#endif + write_zstring (".symtab"); + write_zstring (".strtab"); + + if (((27+section_strings_size) & 3)!=0){ + int n; + + n=4-((27+section_strings_size) & 3); + do { + write_c (0); + } while (--n); + } +} + +static void relocate_code (void) +{ + struct relocation *relocation,**relocation_p; + struct object_buffer *object_buffer; + int code_buffer_offset; + struct label *label; + int instruction_offset; + LONG v; + + object_buffer=first_code_buffer; + code_buffer_offset=0; + + relocation_p=&first_code_relocation; + + while ((relocation=*relocation_p)!=NULL){ + label=relocation->relocation_label; + + switch (relocation->relocation_kind){ + case CALL_RELOCATION: + case BRANCH_RELOCATION: + case JUMP_RELOCATION: + if (label->label_id==TEXT_LABEL_ID){ + instruction_offset=relocation->relocation_offset; + +#ifdef FUNCTION_LEVEL_LINKING + if (label->label_object_label!=relocation->relocation_object_label){ + v=label->label_offset-label->label_object_label->object_label_offset; + + v-=8; + + ++n_code_relocations; + relocation_p=&relocation->next; + } else +#endif + { + v=label->label_offset-(instruction_offset+8); + *relocation_p=relocation->next; + } + } else { + ++n_code_relocations; + relocation_p=&relocation->next; + + instruction_offset=relocation->relocation_offset; + v= -8; + } + + while (instruction_offset >= code_buffer_offset+BUFFER_SIZE){ + object_buffer=object_buffer->next; + code_buffer_offset+=BUFFER_SIZE; + } + + if (instruction_offset-code_buffer_offset<=BUFFER_SIZE-4){ + LONG *instruction_p; + + instruction_p=(LONG*)(object_buffer->data+(instruction_offset-code_buffer_offset)); + + v >>= 2; + + *instruction_p = (*instruction_p & 0xff000000) | (v & 0x00ffffff); + } else { + unsigned char *p0,*p1,*p2,*end_buffer; + + p0=object_buffer->data+(instruction_offset-code_buffer_offset); + end_buffer=object_buffer->data+BUFFER_SIZE; + p1=p0+1; + if (p1==end_buffer) + p1=object_buffer->next->data; + p2=p1+1; + if (p2==end_buffer) + p2=object_buffer->next->data; + + v >>= 2; + v += (*p0 | (*p1<<8) | (*p2<<16)); + + *p0=v; + *p1=v>>8; + *p2=v>>16; + } + + continue; + case LDR_OFFSET_RELOCATION: + if (label->label_id==TEXT_LABEL_ID){ + instruction_offset=relocation->relocation_offset; + +#ifdef FUNCTION_LEVEL_LINKING + if (label->label_object_label!=relocation->relocation_object_label){ + v=label->label_offset-label->label_object_label->object_label_offset; + + v-=8; + + ++n_code_relocations; + relocation_p=&relocation->next; + } else +#endif + { + v=label->label_offset-(instruction_offset+8); + *relocation_p=relocation->next; + } + } else { + ++n_code_relocations; + relocation_p=&relocation->next; + + instruction_offset=relocation->relocation_offset; + v= -8; + } + + while (instruction_offset >= code_buffer_offset+BUFFER_SIZE){ + object_buffer=object_buffer->next; + code_buffer_offset+=BUFFER_SIZE; + } + + if (instruction_offset-code_buffer_offset<=BUFFER_SIZE-4){ + LONG *instruction_p; + + instruction_p=(LONG*)(object_buffer->data+(instruction_offset-code_buffer_offset)); + if (v>=0) + *instruction_p = (*instruction_p & 0xfffff000) | (v & 0x00000fff); + else + *instruction_p = (*instruction_p & 0xff7ff000) | ((-v) & 0x00000fff); /* clear add bit (23) */ + } else { + unsigned char *p0,*p1,*end_buffer; + + p0=object_buffer->data+(instruction_offset-code_buffer_offset); + end_buffer=object_buffer->data+BUFFER_SIZE; + p1=p0+1; + if (p1==end_buffer) + p1=object_buffer->next->data; + + v += (*p0 | (*p1<<8)) & 0xfff; + + if (v<0){ + unsigned char *p2; + + p2=p1+1; + if (p2==end_buffer) + p2=object_buffer->next->data; + + v = -v; + *p2 &= 0x7f; /* clear add bit (23) */ + } + *p0 = v; + *p1 = (*p1) | ((v>>8) & 0xf); + } + + continue; + case VLDR_OFFSET_RELOCATION: + if (label->label_id==TEXT_LABEL_ID){ + instruction_offset=relocation->relocation_offset; + +#ifdef FUNCTION_LEVEL_LINKING + if (label->label_object_label!=relocation->relocation_object_label){ + v=label->label_offset-label->label_object_label->object_label_offset; + + v-=8; + + ++n_code_relocations; + relocation_p=&relocation->next; + } else +#endif + { + v=label->label_offset-(instruction_offset+8); + *relocation_p=relocation->next; + } + } else { + ++n_code_relocations; + relocation_p=&relocation->next; + + instruction_offset=relocation->relocation_offset; + v= -8; + } + + while (instruction_offset >= code_buffer_offset+BUFFER_SIZE){ + object_buffer=object_buffer->next; + code_buffer_offset+=BUFFER_SIZE; + } + + { + unsigned char *p0; + + p0=object_buffer->data+(instruction_offset-code_buffer_offset); + + *p0 += (v>>2); + } + + continue; + case LONG_WORD_RELOCATION: + relocation_p=&relocation->next; + + if (label->label_id==TEXT_LABEL_ID || (label->label_id==DATA_LABEL_ID +#if defined (RELOCATIONS_RELATIVE_TO_EXPORTED_DATA_LABEL) && defined (FUNCTION_LEVEL_LINKING) + && !((label->label_flags & EXPORT_LABEL) && label->label_object_label->object_label_kind==EXPORTED_DATA_LABEL) +#endif + )) + { + instruction_offset=relocation->relocation_offset; + v=label->label_offset; +#ifdef FUNCTION_LEVEL_LINKING + v -= label->label_object_label->object_label_offset; +#endif + break; + } else + continue; + case RELATIVE_LONG_WORD_RELOCATION: + relocation_p=&relocation->next; + + if (label->label_id==TEXT_LABEL_ID || (label->label_id==DATA_LABEL_ID +#if defined (RELOCATIONS_RELATIVE_TO_EXPORTED_DATA_LABEL) && defined (FUNCTION_LEVEL_LINKING) + && !((label->label_flags & EXPORT_LABEL) && label->label_object_label->object_label_kind==EXPORTED_DATA_LABEL) +#endif + )) + { + instruction_offset=relocation->relocation_offset; + v=label->label_offset; +#ifdef FUNCTION_LEVEL_LINKING + v -= label->label_object_label->object_label_offset; +#endif + break; + } else + continue; +#ifdef FUNCTION_LEVEL_LINKING + case DUMMY_BRANCH_RELOCATION: + if (label->label_id==TEXT_LABEL_ID){ + if (label->label_object_label!=relocation->relocation_object_label){ + ++n_code_relocations; + relocation_p=&relocation->next; + continue; + } + *relocation_p=relocation->next; + continue; + } else { + internal_error_in_function ("relocate_code"); + *relocation_p=relocation->next; + } +#endif + default: + internal_error_in_function ("relocate_code"); + } + + while (instruction_offset >= code_buffer_offset+BUFFER_SIZE){ + object_buffer=object_buffer->next; + code_buffer_offset+=BUFFER_SIZE; + } + + if (instruction_offset-code_buffer_offset<=BUFFER_SIZE-4){ + LONG *instruction_p; + + instruction_p=(LONG*)(object_buffer->data+(instruction_offset-code_buffer_offset)); + *instruction_p += v; + } else { + unsigned char *p0,*p1,*p2,*p3,*end_buffer; + + p0=object_buffer->data+(instruction_offset-code_buffer_offset); + end_buffer=object_buffer->data+BUFFER_SIZE; + p1=p0+1; + if (p1==end_buffer) + p1=object_buffer->next->data; + p2=p1+1; + if (p2==end_buffer) + p2=object_buffer->next->data; + p3=p2+1; + if (p3==end_buffer) + p3=object_buffer->next->data; + + v+= (*p0) | (*p1<<8) | (*p2<<16) | (*p3<<24); + + *p0=v; + *p1=v>>8; + *p2=v>>16; + *p3=v>>24; + } + } +} + +static void relocate_data (void) +{ + struct relocation *relocation; + struct object_buffer *object_buffer; + int data_buffer_offset; + + object_buffer=first_data_buffer; + data_buffer_offset=0; + + for_l (relocation,first_data_relocation,next){ + struct label *label; + + label=relocation->relocation_label; + + if (relocation->relocation_kind==LONG_WORD_RELOCATION){ + if (label->label_id==TEXT_LABEL_ID || (label->label_id==DATA_LABEL_ID +#if defined (RELOCATIONS_RELATIVE_TO_EXPORTED_DATA_LABEL) && defined (FUNCTION_LEVEL_LINKING) + && !((label->label_flags & EXPORT_LABEL) && label->label_object_label->object_label_kind==EXPORTED_DATA_LABEL) +#endif + )) + { + int data_offset,v; + + data_offset=relocation->relocation_offset; + while (data_offset >= data_buffer_offset+BUFFER_SIZE){ + object_buffer=object_buffer->next; + data_buffer_offset+=BUFFER_SIZE; + } + + v = label->label_offset; +#ifdef FUNCTION_LEVEL_LINKING + v -= label->label_object_label->object_label_offset; +#endif + if (data_offset-data_buffer_offset<=BUFFER_SIZE-4){ + LONG *data_p; + + data_p=(LONG*)(object_buffer->data+(data_offset-data_buffer_offset)); + *data_p += v; + } else { + unsigned char *p0,*p1,*p2,*p3,*end_buffer; + + p0=object_buffer->data+(data_offset-data_buffer_offset); + end_buffer=object_buffer->data+BUFFER_SIZE; + p1=p0+1; + if (p1==end_buffer) + p1=object_buffer->next->data; + p2=p1+1; + if (p2==end_buffer) + p2=object_buffer->next->data; + p3=p2+1; + if (p3==end_buffer) + p3=object_buffer->next->data; + + v+= (*p0) | (*p1<<8) | (*p2<<16) | (*p3<<24); + + *p0=v; + *p1=v>>8; + *p2=v>>16; + *p3=v>>24; + } + } + } + } +} + +static void as_import_labels (struct label_node *label_node) +{ + LABEL *label; + + if (label_node==NULL) + return; + + label=&label_node->label_node_label; + + if (!(label->label_flags & LOCAL_LABEL) && label->label_number==0){ + struct object_label *new_object_label; + int string_length; + + new_object_label=fast_memory_allocate_type (struct object_label); + *last_object_label_l=new_object_label; + last_object_label_l=&new_object_label->next; + new_object_label->next=NULL; + + new_object_label->object_label_label=label; + + label->label_id=n_object_labels; + ++n_object_labels; + + label->label_offset=0; + + string_length=strlen (label->label_name); +#ifndef ELF + if (string_length<8) + new_object_label->object_label_string_offset=0; + else +#endif + { + new_object_label->object_label_string_offset=string_table_offset; + string_table_offset+=string_length+1; + } + + new_object_label->object_label_kind=IMPORTED_LABEL; + } + + as_import_labels (label_node->label_node_left); + as_import_labels (label_node->label_node_right); +} + +#define C_EXT 2 +#define C_STAT 3 + +static void write_object_labels (void) +{ + struct object_label *object_label; +#if defined (RELOCATIONS_RELATIVE_TO_EXPORTED_DATA_LABEL) && defined (FUNCTION_LEVEL_LINKING) + struct object_label *current_text_or_data_object_label; + + current_text_or_data_object_label=NULL; +#endif + +#ifdef ELF + write_l (0); + write_l (0); + write_l (0); + write_l (0); +# ifndef FUNCTION_LEVEL_LINKING + write_l (1); + write_l (0); + write_l (0); + write_c (ELF32_ST_INFO (STB_LOCAL,STT_SECTION)); + write_c (0); + write_w (2); + + write_l (7); + write_l (0); + write_l (0); + write_c (ELF32_ST_INFO (STB_LOCAL,STT_SECTION)); + write_c (0); + write_w (3); +# else + { + int section_n; + + for (section_n=0; section_n<n_code_sections; ++section_n){ + write_l (0); + write_l (0); + write_l (0); + write_c (ELF32_ST_INFO (STB_LOCAL,STT_SECTION)); + write_c (0); + write_w (2+section_n); + } + + for (section_n=0; section_n<n_data_sections; ++section_n){ + write_l (0); + write_l (0); + write_l (0); + write_c (ELF32_ST_INFO (STB_LOCAL,STT_SECTION)); + write_c (0); + write_w (2+n_code_sections+section_n); + } + + /* $a and $d symbols */ + section_n=0; + { + int n_generated_mapping_symbols; + struct mapping_symbol *mapping_symbol_p; + + mapping_symbol_p=first_mapping_symbol; + n_generated_mapping_symbols=0; + + object_label=first_object_label; + while (object_label!=NULL && object_label->object_label_kind!=CODE_CONTROL_SECTION) + object_label=object_label->next; + + while (object_label!=NULL){ + struct object_label *previous_object_label; + unsigned long current_control_section_code_offset,next_control_section_code_offset; + + current_control_section_code_offset=object_label->object_label_offset; + previous_object_label=object_label; + + object_label=object_label->next; + while (object_label!=NULL && object_label->object_label_kind!=CODE_CONTROL_SECTION) + object_label=object_label->next; + + if (object_label!=NULL) + next_control_section_code_offset = object_label->object_label_offset; + else + next_control_section_code_offset = end_code_offset; + + if (mapping_symbol_p==NULL || mapping_symbol_p->ms_data_offset!=current_control_section_code_offset){ + write_l (1); /* $a */ + write_l (0); + write_l (0); + write_c (ELF32_ST_INFO (STB_LOCAL,STT_NOTYPE)); + write_c (0); + write_w (2+section_n); + ++n_generated_mapping_symbols; + } + + while (mapping_symbol_p!=NULL && mapping_symbol_p->ms_data_offset<next_control_section_code_offset){ + write_l (4); /* $d */ + write_l (mapping_symbol_p->ms_data_offset-current_control_section_code_offset); + write_l (0); + write_c (ELF32_ST_INFO (STB_LOCAL,STT_NOTYPE)); + write_c (0); + write_w (2+section_n); + ++n_generated_mapping_symbols; + + if (mapping_symbol_p->ms_code_offset!=next_control_section_code_offset){ + write_l (1); /* $a */ + write_l (mapping_symbol_p->ms_code_offset-current_control_section_code_offset); + write_l (0); + write_c (ELF32_ST_INFO (STB_LOCAL,STT_NOTYPE)); + write_c (0); + write_w (2+section_n); + ++n_generated_mapping_symbols; + } + + mapping_symbol_p=mapping_symbol_p->ms_next; + } + ++section_n; + } + + if (section_n!=n_code_sections || n_generated_mapping_symbols!=n_mapping_symbols) + internal_error_in_function ("write_object_labels"); + } + } +# endif +#endif + + for_l (object_label,first_object_label,next){ + switch (object_label->object_label_kind){ + case CODE_CONTROL_SECTION: + { +#ifndef ELF + write_string_8 (".text"); + +# ifdef FUNCTION_LEVEL_LINKING + write_l (0); + write_w (1+object_label->object_label_section_n); +# else + write_l (object_label->object_label_offset); + write_w (1); +# endif + write_w (0); + write_c (C_STAT); + write_c (1); + + write_l (object_label->object_label_length); +# ifdef FUNCTION_LEVEL_LINKING + write_w (object_label->object_label_n_relocations); +# else + write_w (n_code_relocations); +# endif + write_w (0); + write_l (0); + write_l (0); + write_w (0); +#endif + break; + } + case DATA_CONTROL_SECTION: + { +#if defined (RELOCATIONS_RELATIVE_TO_EXPORTED_DATA_LABEL) && defined (FUNCTION_LEVEL_LINKING) + current_text_or_data_object_label=object_label; +#endif +#ifndef ELF + write_string_8 (".data"); + +# ifdef FUNCTION_LEVEL_LINKING + write_l (0); + write_w (1+n_code_sections+object_label->object_label_section_n); +# else + write_l (object_label->object_label_offset); + write_w (2); +# endif + write_w (0); + write_c (C_STAT); + write_c (1); + + write_l (object_label->object_label_length); +# ifdef FUNCTION_LEVEL_LINKING + write_w (object_label->object_label_n_relocations); +# else + write_w (n_data_relocations); +# endif + write_w (0); + write_l (0); + write_l (0); + write_w (0); +#endif + break; + } + case IMPORTED_LABEL: + { + struct label *label; + + label=object_label->object_label_label; +#ifdef ELF + write_l (object_label->object_label_string_offset); + write_l (0); + write_l (0); + write_c (ELF32_ST_INFO (STB_GLOBAL,STT_NOTYPE)); + write_c (0); + write_w (0); +#else + if (object_label->object_label_string_offset==0) + write_string_8 (label->label_name); + else { + write_l (0); + write_l (object_label->object_label_string_offset); + } + + write_l (0); + write_w (0); + write_w (0); + write_c (C_EXT); + write_c (0); +#endif + break; + } + case EXPORTED_CODE_LABEL: + { + struct label *label; + + label=object_label->object_label_label; +#ifdef ELF + write_l (object_label->object_label_string_offset); +# ifdef FUNCTION_LEVEL_LINKING + write_l (label->label_offset - label->label_object_label->object_label_offset); +# else + write_l (label->label_offset); +# endif + write_l (0); + write_c (ELF32_ST_INFO (STB_GLOBAL,STT_FUNC)); + write_c (label->label_flags & C_ENTRY_LABEL ? STV_DEFAULT : STV_HIDDEN); +# ifdef FUNCTION_LEVEL_LINKING + write_w (2+label->label_object_label->object_label_section_n); +# else + write_w (2); +# endif +#else + if (object_label->object_label_string_offset==0) + write_string_8 (label->label_name); + else { + write_l (0); + write_l (object_label->object_label_string_offset); + } + +#ifdef FUNCTION_LEVEL_LINKING + write_l (label->label_offset - label->label_object_label->object_label_offset); + write_w (1+label->label_object_label->object_label_section_n); +#else + write_l (label->label_offset); + write_w (1); +#endif + write_w (0); + write_c (C_EXT); + write_c (0); +#endif + break; + } + case EXPORTED_DATA_LABEL: + { + struct label *label; + + label=object_label->object_label_label; +#ifdef ELF + write_l (object_label->object_label_string_offset); +# ifdef FUNCTION_LEVEL_LINKING +# ifdef RELOCATIONS_RELATIVE_TO_EXPORTED_DATA_LABEL + write_l (label->label_offset - current_text_or_data_object_label->object_label_offset); +# else + write_l (label->label_offset - label->label_object_label->object_label_offset); +# endif +# else + write_l (label->label_offset); +# endif + write_l (0); + write_c (ELF32_ST_INFO (STB_GLOBAL,STT_OBJECT)); + write_c (label->label_flags & C_ENTRY_LABEL ? STV_DEFAULT : STV_HIDDEN); +# ifdef FUNCTION_LEVEL_LINKING + write_w (2+n_code_sections+label->label_object_label->object_label_section_n); +# else + write_w (3); +# endif +#else + if (object_label->object_label_string_offset==0) + write_string_8 (label->label_name); + else { + write_l (0); + write_l (object_label->object_label_string_offset); + } + +#ifdef FUNCTION_LEVEL_LINKING +# ifdef RELOCATIONS_RELATIVE_TO_EXPORTED_DATA_LABEL + write_l (label->label_offset - current_text_or_data_object_label->object_label_offset); +# else + write_l (label->label_offset - label->label_object_label->object_label_offset); +# endif + write_w (1+n_code_sections+label->label_object_label->object_label_section_n); +#else + write_l (label->label_offset); + write_w (2); +#endif + write_w (0); + write_c (C_EXT); + write_c (0); +#endif + break; + } + default: + internal_error_in_function ("write_object_labels"); + } + } +} + +static void write_string_table (void) +{ + struct object_label *object_label; + +#ifdef ELF + write_c (0); +# ifndef FUNCTION_LEVEL_LINKING + write_zstring (".text"); + write_zstring (".data"); +# else + write_zstring ("$a"); + write_zstring ("$d"); +# endif +#else + if (string_table_offset==4) + return; + + write_l (string_table_offset); +#endif + for_l (object_label,first_object_label,next){ + int object_label_kind; + + object_label_kind=object_label->object_label_kind; + + if ((object_label_kind==IMPORTED_LABEL || object_label_kind==EXPORTED_CODE_LABEL || object_label_kind==EXPORTED_DATA_LABEL) + && object_label->object_label_string_offset!=0) + { + char *s,c; + + s=object_label->object_label_label->label_name; + + do { + c=*s++; + write_c (c); + } while (c!='\0'); + } + } +} + +#define R_DIR32 6 + +#if defined (ELF) && defined (FUNCTION_LEVEL_LINKING) +static int elf_label_number (struct label *label) +{ + int label_n; + + label_n=label->label_id; + if (label_n==TEXT_LABEL_ID){ + label_n=label->label_object_label->object_label_number; + if (label_n==0) + return 1+label->label_object_label->object_label_section_n; + else + return label_n+n_local_section_and_mapping_symbols; + } else if (label_n==DATA_LABEL_ID){ + label_n=label->label_object_label->object_label_number; + if (label_n==0) + return 1+n_code_sections+label->label_object_label->object_label_section_n; + else + return label_n+n_local_section_and_mapping_symbols; + } else + return label_n+n_local_section_and_mapping_symbols; +} +#endif + +static void write_code_relocations (void) +{ + struct relocation *relocation; + + for_l (relocation,first_code_relocation,next){ + switch (relocation->relocation_kind){ + case BRANCH_RELOCATION: + case JUMP_RELOCATION: + { + struct label *label; + + label=relocation->relocation_label; +#ifdef FUNCTION_LEVEL_LINKING + if (label->label_id==-1) +#else + if (label->label_id<0) +#endif + internal_error_in_function ("write_code_relocations"); + + write_l (relocation->relocation_offset); +#ifdef FUNCTION_LEVEL_LINKING + write_l (ELF32_R_INFO (elf_label_number (label),R_ARM_JUMP24)); +#else + write_l (ELF32_R_INFO (label->label_id,R_ARM_JUMP24)); +#endif + break; + } + case CALL_RELOCATION: + { + struct label *label; + + label=relocation->relocation_label; +#ifdef FUNCTION_LEVEL_LINKING + if (label->label_id==-1) +#else + if (label->label_id<0) +#endif + internal_error_in_function ("write_code_relocations"); + + write_l (relocation->relocation_offset); +#ifdef FUNCTION_LEVEL_LINKING + write_l (ELF32_R_INFO (elf_label_number (label),R_ARM_CALL)); +#else + write_l (ELF32_R_INFO (label->label_id,R_ARM_CALL)); +#endif + break; + } + case LDR_OFFSET_RELOCATION: + { + struct label *label; + + label=relocation->relocation_label; +#ifdef FUNCTION_LEVEL_LINKING + if (label->label_id==-1) +#else + if (label->label_id<0) +#endif + internal_error_in_function ("write_code_relocations"); + + write_l (relocation->relocation_offset); +#ifdef FUNCTION_LEVEL_LINKING + write_l (ELF32_R_INFO (elf_label_number (label),R_ARM_LDR_PC_G0)); +#else + write_l (ELF32_R_INFO (label->label_id,R_ARM_LDR_PC_G0)); +#endif + break; + } + case VLDR_OFFSET_RELOCATION: + { + struct label *label; + + label=relocation->relocation_label; +#ifdef FUNCTION_LEVEL_LINKING + if (label->label_id==-1) +#else + if (label->label_id<0) +#endif + internal_error_in_function ("write_code_relocations"); + + write_l (relocation->relocation_offset); +#ifdef FUNCTION_LEVEL_LINKING + write_l (ELF32_R_INFO (elf_label_number (label),R_ARM_LDC_PC_G0)); +#else + write_l (ELF32_R_INFO (label->label_id,R_ARM_LDC_PC_G0)); +#endif + break; + } + case LONG_WORD_RELOCATION: + { + struct label *label; + + label=relocation->relocation_label; +#ifdef FUNCTION_LEVEL_LINKING + if (label->label_id==-1) +#else + if (label->label_id<0) +#endif + internal_error_in_function ("write_code_relocations"); + + write_l (relocation->relocation_offset); +#ifdef FUNCTION_LEVEL_LINKING + write_l (ELF32_R_INFO (elf_label_number (label),R_ARM_ABS32)); +#else + write_l (ELF32_R_INFO (label->label_id,R_ARM_ABS32)); +#endif + break; + } + case RELATIVE_LONG_WORD_RELOCATION: + { + struct label *label; + + label=relocation->relocation_label; +#ifdef FUNCTION_LEVEL_LINKING + if (label->label_id==-1) +#else + if (label->label_id<0) +#endif + internal_error_in_function ("write_code_relocations"); + + write_l (relocation->relocation_offset); +#ifdef FUNCTION_LEVEL_LINKING + write_l (ELF32_R_INFO (elf_label_number (label),R_ARM_REL32)); +#else + write_l (ELF32_R_INFO (label->label_id,R_ARM_REL32)); +#endif + break; + } +#ifdef FUNCTION_LEVEL_LINKING + case DUMMY_BRANCH_RELOCATION: + { + struct label *label; + + label=relocation->relocation_label; + if (label->label_id==-1) + internal_error_in_function ("write_code_relocations"); + + write_l (relocation->relocation_offset - 4); + write_l (ELF32_R_INFO (elf_label_number (label),R_ARM_NONE)); + break; + } +#endif + default: + internal_error_in_function ("write_code_relocations"); + } + } +} + +static void write_data_relocations (void) +{ + struct relocation *relocation; + + for_l (relocation,first_data_relocation,next){ + switch (relocation->relocation_kind){ + case LONG_WORD_RELOCATION: + { + struct label *label; + + label=relocation->relocation_label; +#ifdef FUNCTION_LEVEL_LINKING + if (label->label_id==-1) +#else + if (label->label_id<0) +#endif + internal_error_in_function ("write_data_relocations"); + + write_l (relocation->relocation_offset); +#ifdef ELF +# ifdef FUNCTION_LEVEL_LINKING + write_l (ELF32_R_INFO (elf_label_number (label),R_ARM_ABS32)); +# else + write_l (ELF32_R_INFO (label->label_id,R_ARM_ABS32)); +# endif +#else +# ifdef FUNCTION_LEVEL_LINKING + if (label->label_id==TEXT_LABEL_ID || label->label_id==DATA_LABEL_ID) + write_l (label->label_object_label->object_label_number); + else +# endif + write_l (label->label_id); + write_w (R_DIR32); +#endif + break; + } + default: + internal_error_in_function ("write_data_relocations"); + } + } +} + +void assemble_code (void) +{ + literal_table_at_offset = 0ul-1ul; + literal_table_at_buffer_p = (unsigned char*)0ul-1ul; + + as_import_labels (labels); + + write_code(); + + if (code_buffer_free & 1) + store_c (0x90); + + end_code_offset=CURRENT_CODE_OFFSET; + if (first_mapping_symbol!=NULL && last_mapping_symbol->ms_code_offset==end_code_offset) + --n_mapping_symbols; /* $a at end of section */ + + flush_data_buffer(); + flush_code_buffer(); + +#ifndef FUNCTION_LEVEL_LINKING + code_object_label->object_label_length=code_buffer_offset; + data_object_label->object_label_length=data_buffer_offset; +#endif + + relocate_code(); + relocate_data(); + + write_file_header_and_section_headers(); + + write_buffers_and_release_memory (&first_code_buffer); + +# ifdef ELF + if ((code_buffer_offset & 3)!=0){ + int n; + + n=4-(code_buffer_offset & 3); + do { + write_c (0); + } while (--n); + } +# endif + + write_buffers_and_release_memory (&first_data_buffer); + +# ifdef ELF + if ((data_buffer_offset & 3)!=0){ + int n; + + n=4-(data_buffer_offset & 3); + do { + write_c (0); + } while (--n); + } +# endif + + write_code_relocations(); + write_data_relocations(); + write_object_labels(); + write_string_table(); +} diff --git a/cgthumb2as.h b/cgthumb2as.h new file mode 100644 index 0000000..4e95422 --- /dev/null +++ b/cgthumb2as.h @@ -0,0 +1,34 @@ +
+void assemble_code (VOID);
+void initialize_assembler (FILE *file);
+void define_local_label (int id,int flag);
+void define_external_label (int id,int flag,char label_name[]);
+void store_word_in_data_section (UWORD i);
+void store_long_word_in_data_section (ULONG i);
+void define_data_label (LABEL *label);
+void store_label_in_data_section (LABEL *label);
+void store_label_offset_in_data_section (int label_id);
+void store_descriptor_in_data_section (LABEL *label);
+void store_descriptor_in_code_section (int label_id);
+void store_c_string_in_data_section (char *string,int length);
+void store_abc_string_in_data_section (char *string,int length);
+void store_c_string_in_code_section (char *string,int length);
+void store_abc_string_in_code_section (char *string,int length);
+void store_descriptor_string_in_code_section (char *string,int length,int string_code_label_id,LABEL *string_label);
+void store_label_offset_in_code_section (int label_id);
+void start_new_module (int flag);
+void store_descriptor_string_in_data_section (char *string,int length,LABEL *string_label);
+void store_2_words_in_data_section (UWORD w1,UWORD w2);
+#ifdef _WINDOWS_
+void as_new_data_module (void);
+#endif
+
+#ifndef GNU_C
+void write_version_and_options (int version,int options);
+void write_depend (char *module_name);
+#endif
+
+struct ms { int m; int s; };
+
+extern struct ms magic (int d);
+
diff --git a/cgthumb2c.c b/cgthumb2c.c new file mode 100644 index 0000000..0d2dfe6 --- /dev/null +++ b/cgthumb2c.c @@ -0,0 +1,753 @@ + +#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); + } +} + diff --git a/cgthumb2was.c b/cgthumb2was.c new file mode 100644 index 0000000..8529878 --- /dev/null +++ b/cgthumb2was.c @@ -0,0 +1,2908 @@ +/* + File: cgthumb2was.c + Original file: cgarmwas.c + Author: John van Groningen, adapted by Camil Staps for Thumb-2 + Machine: ARM, Thumb-2 encoding +*/ + +#include <stdio.h> +#include <string.h> +#include <ctype.h> +#include <stdlib.h> + +#include "cgport.h" +#include "cgrconst.h" +#include "cgtypes.h" +#include "cg.h" +#include "cgiconst.h" +#include "cgcode.h" +#include "cginstructions.h" +#include "cgarmas.h" +#include "cgarmwas.h" + +#define for_l(v,l,n) for(v=(l);v!=NULL;v=v->n) + +#define IO_BUF_SIZE 8192 + +#define FP_REVERSE_SUB_DIV_OPERANDS 1 + +static FILE *assembly_file; + +static void w_as_newline (VOID) +{ + putc ('\n',assembly_file); +} + +static void w_as_opcode (char *opcode) +{ + fprintf (assembly_file,"\t%s\t",opcode); +} + +static void w_as_instruction_without_parameters (char *opcode) +{ + fprintf (assembly_file,"\t%s\n",opcode); +} + +static void w_as_define_local_label (int label_number) +{ + fprintf (assembly_file,"l_%d:\n",label_number); +} + +static void w_as_define_local_data_label (int label_number) +{ + fprintf (assembly_file,"l_%d:\n",label_number); +} + +static void w_as_define_internal_label (int label_number) +{ + fprintf (assembly_file,"i_%d:\n",label_number); +} + +static void w_as_define_internal_data_label (int label_number) +{ + fprintf (assembly_file,"i_%d:\n",label_number); +} + +void w_as_internal_label_value (int label_id) +{ + fprintf (assembly_file,"\t.long\ti_%d\n",label_id); +} + +static int in_data_section; + +#ifdef FUNCTION_LEVEL_LINKING +void w_as_new_data_module (void) +{ +} +#endif + +void w_as_to_data_section (VOID) +{ + if (!in_data_section){ + in_data_section=1; + w_as_instruction_without_parameters (".data"); + } +} + +#ifdef DATA_IN_CODE_SECTION +# define w_as_to_data_section w_as_to_code_section +#endif + +static void w_as_to_code_section (VOID) +{ + if (in_data_section){ + in_data_section=0; + w_as_instruction_without_parameters (".text"); + } +} + +static void w_as_align (int i) +{ + fprintf (assembly_file,"\t.p2align\t%d\n",i); +} + +static void w_as_space (int i) +{ + fprintf (assembly_file,"\t.space\t%d\n",i); +} + +void w_as_word_in_data_section (int n) +{ + w_as_to_data_section(); + w_as_opcode (".hword"); + fprintf (assembly_file,"%d",n); + w_as_newline(); +} + +void w_as_long_in_data_section (int n) +{ +#ifdef DATA_IN_CODE_SECTION + if (!in_data_section){ + in_data_section=1; + w_as_instruction_without_parameters (".data"); + } +#else + w_as_to_data_section(); +#endif + w_as_opcode (".long"); + fprintf (assembly_file,"%d",n); + w_as_newline(); +} + +void w_as_label_in_data_section (char *label_name) +{ + w_as_to_data_section (); + fprintf (assembly_file,"\t.long\t%s\n",label_name); +} + +static void w_as_label_in_code_section (char *label_name) +{ + w_as_to_code_section (); + fprintf (assembly_file,"\t.long\t%s\n",label_name); +} + +void w_as_descriptor_in_data_section (char *label_name) +{ + w_as_to_data_section(); + w_as_align (2); + fprintf (assembly_file,"\t.long\t%s+2\n",label_name); +} + +#define MAX_BYTES_PER_LINE 16 + +static int w_as_data (int n,char *data,int length) +{ + int i,in_string; + + in_string=0; + + for (i=0; i<length; ++i){ + int c; + + if (n>=MAX_BYTES_PER_LINE){ + if (in_string){ + putc ('\"',assembly_file); + in_string=0; + } + w_as_newline(); + n=0; + } + + c=((unsigned char*)data)[i]; + if (isalnum (c) || c=='_' || c==' '){ + if (!in_string){ + if (n!=0) + w_as_newline(); + w_as_opcode (".ascii"); + putc ('\"',assembly_file); + in_string=1; + n=0; + } + putc (c,assembly_file); + } else { + if (n==0) + w_as_opcode (".byte"); + else { + if (in_string){ + putc ('\"',assembly_file); + w_as_newline(); + w_as_opcode (".byte"); + in_string=0; + n=0; + } else + putc (',',assembly_file); + } + + fprintf (assembly_file,"0x%02x",c); + } + ++n; + } + + if (in_string){ + putc ('\"',assembly_file); + w_as_newline(); + return 0; + } else + return n; +} + +static int w_as_zeros (register int n,register int length) +{ + register int i; + + for (i=0; i<length; ++i){ + if (n>=MAX_BYTES_PER_LINE){ + w_as_newline(); + n=0; + } + if (n==0) + w_as_opcode (".byte"); + else + putc (',',assembly_file); + fprintf (assembly_file,"0"); + ++n; + } + return n; +} + +void w_as_define_data_label (int label_number) +{ + w_as_to_data_section(); + + w_as_define_local_data_label (label_number); +} + +void w_as_labeled_c_string_in_data_section (char *string,int length,int label_number) +{ + int n; + + w_as_to_data_section(); + + w_as_define_local_data_label (label_number); + + n=w_as_data (0,string,length); + if (length & 3) + n=w_as_zeros (n,4-(length & 3)); + else + n=w_as_zeros (n,4); + if (n>0) + w_as_newline(); +} + +void w_as_c_string_in_data_section (char *string,int length) +{ + int n; + + w_as_to_data_section(); + + n=w_as_data (0,string,length); + if (length & 3) + n=w_as_zeros (n,4-(length & 3)); + /* CHANGED 30-7-92 */ + else + n=w_as_zeros (n,4); + /* */ + if (n>0) + w_as_newline(); +} + +void w_as_abc_string_in_data_section (char *string,int length) +{ + int n; + + w_as_to_data_section(); + + w_as_opcode (".long"); + fprintf (assembly_file,"%d\n",length); + n=w_as_data (0,string,length); + if (length & 3) + n=w_as_zeros (n,4-(length & 3)); + if (n>0) + w_as_newline(); +} + +void w_as_descriptor_string_in_data_section (char *string,int length,int string_label_id,LABEL *string_label) +{ + int n; + + w_as_to_data_section(); + + w_as_define_internal_data_label (string_label_id); + w_as_define_local_data_label (string_label->label_number); + + w_as_opcode (".long"); + fprintf (assembly_file,"%d\n",length); + n=w_as_data (0,string,length); + if (length & 3) + n=w_as_zeros (n,4-(length & 3)); + if (n>0) + w_as_newline(); +} + +enum { SIZE_LONG, SIZE_WORD, SIZE_BYTE }; + +static void w_as_label (char *label) +{ + int c; + + while ((c=*label++)!=0) + putc (c,assembly_file); +} + +#define MAX_LITERAL_INSTRUCTION_OFFSET 1023 + +static unsigned int instruction_n_after_ltorg,ltorg_at_instruction_n; + +static void w_as_local_label (int label_number) +{ + fprintf (assembly_file,"l_%d",label_number); +} + +static void w_as_label_parameter (struct parameter *parameter_p) +{ + if (parameter_p->parameter_data.l->label_number!=0) + w_as_local_label (parameter_p->parameter_data.l->label_number); + else + w_as_label (parameter_p->parameter_data.l->label_name); +} + +static void w_as_immediate_label (LABEL *label) +{ + if (instruction_n_after_ltorg+MAX_LITERAL_INSTRUCTION_OFFSET < ltorg_at_instruction_n) + ltorg_at_instruction_n = instruction_n_after_ltorg+MAX_LITERAL_INSTRUCTION_OFFSET; + + putc ('=',assembly_file); + if (label->label_number!=0) + w_as_local_label (label->label_number); + else + w_as_label (label->label_name); +} + +static void w_as_immediate_label_name (char *label_name) +{ + if (instruction_n_after_ltorg+MAX_LITERAL_INSTRUCTION_OFFSET < ltorg_at_instruction_n) + ltorg_at_instruction_n = instruction_n_after_ltorg+MAX_LITERAL_INSTRUCTION_OFFSET; + + putc ('=',assembly_file); + w_as_label (label_name); +} + +static void w_as_colon (VOID) +{ + putc (':',assembly_file); +} + +static void w_as_define_label_name (char *label_name) +{ + w_as_label (label_name); + w_as_colon(); + w_as_newline(); +} + +static void w_as_define_data_label_name (char *label_name) +{ + w_as_label (label_name); + w_as_colon(); + w_as_newline(); +} + +void w_as_define_label (LABEL *label) +{ + if (label->label_flags & EXPORT_LABEL){ + w_as_opcode (".globl"); + w_as_label (label->label_name); + w_as_newline(); + } + + w_as_label (label->label_name); + w_as_colon(); + w_as_newline(); +} + +static void w_as_define_code_label (LABEL *label) +{ + if (label->label_flags & EXPORT_LABEL){ + w_as_opcode (".globl"); + w_as_label (label->label_name); + w_as_newline(); + } + + w_as_label (label->label_name); + w_as_colon(); + w_as_newline(); +} + +static void w_as_internal_label (int label_number) +{ + fprintf (assembly_file,"i_%d",label_number); +} + +static void w_as_immediate (LONG i) +{ + fprintf (assembly_file,"#%ld",i); +} + +void w_as_abc_string_and_label_in_data_section (char *string,int length,char *label_name) +{ + int n; + + w_as_to_data_section(); + + w_as_define_data_label_name (label_name); + + w_as_opcode (".long"); + fprintf (assembly_file,"%d\n",length); + n=w_as_data (0,string,length); + if (length & 3) + n=w_as_zeros (n,4-(length & 3)); + if (n>0) + w_as_newline(); +} + +static char *register_name[15]={"sp","r10","r9","r11","r8","r7","r6","r4","r3","r2","r1","r0","r5","r12","r14"}; + +#define REGISTER_S0 6 +#define REGISTER_S1 7 + +static void w_as_indirect (int i,int reg) +{ + if (i==0) + fprintf (assembly_file,"[%s]",register_name[reg+7]); + else + fprintf (assembly_file,"[%s,#%d]",register_name[reg+7],i); +} + +static void w_as_indirect_with_update (int i,int reg) +{ + if (i==0) + fprintf (assembly_file,"[%s]",register_name[reg+7]); + else + fprintf (assembly_file,"[%s,#%d]!",register_name[reg+7],i); +} + +static void w_as_indirect_post_add (int i,int reg) +{ + if (i==0) + fprintf (assembly_file,"[%s]",register_name[reg+7]); + else + fprintf (assembly_file,"[%s],#%d",register_name[reg+7],i); +} + +static void w_as_register (int reg) +{ + fputs (register_name[reg+7],assembly_file); +} + +static void w_as_comma (VOID) +{ + putc (',',assembly_file); +} + +static void w_as_register_comma (int reg) +{ + w_as_register (reg); + w_as_comma(); +} + +static void w_as_comma_register (int reg) +{ + w_as_comma(); + w_as_register (reg); +} + +static void w_as_indexed_no_offset (int offset,int reg1,int reg2) +{ + int shift; + + shift=offset & 3; + if (shift!=0) + fprintf (assembly_file,"[%s,%s,lsl #%d]",register_name[reg1+7],register_name[reg2+7],shift); + else + fprintf (assembly_file,"[%s,%s]",register_name[reg1+7],register_name[reg2+7]); +} + +static void w_as_indexed_no_offset_ir (int offset,struct index_registers *index_registers) +{ + w_as_indexed_no_offset (offset,index_registers->a_reg.r,index_registers->d_reg.r); +} + +struct float_constant { + DOUBLE * float_constant_r_p; + int float_constant_label_number; + struct float_constant * float_constant_next; +}; + +struct float_constant *first_float_constant,**float_constant_l; + +static void write_float_constants (void) +{ + struct float_constant *float_constant; + + float_constant=first_float_constant; + + if (float_constant!=NULL){ + w_as_align (3); + + for (; float_constant!=NULL; float_constant=float_constant->float_constant_next){ + w_as_define_internal_data_label (float_constant->float_constant_label_number); + + w_as_opcode (".double"); + fprintf (assembly_file,"0r%.20e",*float_constant->float_constant_r_p); + w_as_newline(); + } + + float_constant_l=&first_float_constant; + first_float_constant=NULL; + } +} + +static void w_as_newline_after_instruction (VOID) +{ + w_as_newline(); + ++instruction_n_after_ltorg; + if (instruction_n_after_ltorg>=ltorg_at_instruction_n){ + int label_id; + + label_id=next_label_id++; + + w_as_opcode ("b"); + w_as_internal_label (label_id); + w_as_newline(); + + write_float_constants(); + w_as_opcode (".ltorg"); + w_as_newline(); + + w_as_define_internal_label (label_id); + + instruction_n_after_ltorg = 0u; + ltorg_at_instruction_n = 0u-1u; + } +} + +static void w_as_register_newline (int reg) +{ + w_as_register (reg); + w_as_newline_after_instruction(); +} + +static void w_as_indirect_newline (int i,int reg) +{ + w_as_indirect (i,reg); + w_as_newline_after_instruction(); +} + +static void w_as_indirect_with_update_newline (int i,int reg) +{ + w_as_indirect_with_update (i,reg); + w_as_newline_after_instruction(); +} + +static void w_as_indirect_post_add_newline (int i,int reg) +{ + w_as_indirect_post_add (i,reg); + w_as_newline_after_instruction(); +} + +static void w_as_immediate_newline (LONG i) +{ + fprintf (assembly_file,"#%ld",i); + w_as_newline_after_instruction(); +} + +void w_as_c_string_and_label_in_code_section (char *string,int length,char *label_name) +{ + int n; + +/* w_as_to_code_section(); */ + w_as_to_data_section(); + + w_as_define_data_label_name (label_name); + + n=w_as_data (0,string,length); + n=w_as_zeros (n,4-(length & 3)); + if (n>0) + w_as_newline(); +} + +static void w_as_scratch_register (void) +{ + fprintf (assembly_file,"r12"); +} + +static void w_as_scratch_register_comma (void) +{ + fprintf (assembly_file,"r12"); + w_as_comma(); +} + +static void w_as_comma_scratch_register (void) +{ + w_as_comma(); + fprintf (assembly_file,"r12"); +} + +static void w_as_comma_scratch_register_newline (void) +{ + w_as_comma(); + fprintf (assembly_file,"r12"); + w_as_newline_after_instruction(); +} + +static void w_as_fp_register (int fp_reg) +{ + fprintf (assembly_file,"d%d",fp_reg); +} + +static void w_as_fp_register_comma (int fp_reg) +{ + fprintf (assembly_file,"d%d,",fp_reg); +} + +static void w_as_fp_register_newline (int fp_reg) +{ + fprintf (assembly_file,"d%d",fp_reg); + w_as_newline_after_instruction(); +} + +static void w_as_descriptor (LABEL *label,int arity) +{ + if (instruction_n_after_ltorg+MAX_LITERAL_INSTRUCTION_OFFSET < ltorg_at_instruction_n) + ltorg_at_instruction_n = instruction_n_after_ltorg+MAX_LITERAL_INSTRUCTION_OFFSET; + + putc ('=',assembly_file); + if (label->label_number!=0) + w_as_local_label (label->label_number); + else + w_as_label (label->label_name); + + if (arity!=0) + if (arity>0) + fprintf (assembly_file,"+%d",arity); + else + fprintf (assembly_file,"-%d",-arity); +} + +static int mov_or_mvn_immediate (unsigned int i) +{ + if ((i & ~0xff)==0) return 1; + if ((i & ~0x3fc)==0) return 1; + if ((i & ~0xff0)==0) return 1; + if ((i & ~0x3fc0)==0) return 1; + if ((i & ~0xff00)==0) return 1; + if ((i & ~0x3fc00)==0) return 1; + if ((i & ~0xff000)==0) return 1; + if ((i & ~0x3fc000)==0) return 1; + if ((i & ~0xff0000)==0) return 1; + if ((i & ~0x3fc0000)==0) return 1; + if ((i & ~0xff00000)==0) return 1; + if ((i & ~0x3fc00000)==0) return 1; + if ((i & ~0xff000000)==0) return 1; + if ((i & ~0xfc000003)==0) return 1; + if ((i & ~0xf000000f)==0) return 1; + if ((i & ~0xc000003f)==0) return 1; + + i = ~i; + + if ((i & ~0xff)==0) return 1; + if ((i & ~0x3fc)==0) return 1; + if ((i & ~0xff0)==0) return 1; + if ((i & ~0x3fc0)==0) return 1; + if ((i & ~0xff00)==0) return 1; + if ((i & ~0x3fc00)==0) return 1; + if ((i & ~0xff000)==0) return 1; + if ((i & ~0x3fc000)==0) return 1; + if ((i & ~0xff0000)==0) return 1; + if ((i & ~0x3fc0000)==0) return 1; + if ((i & ~0xff00000)==0) return 1; + if ((i & ~0x3fc00000)==0) return 1; + if ((i & ~0xff000000)==0) return 1; + if ((i & ~0xfc000003)==0) return 1; + if ((i & ~0xf000000f)==0) return 1; + if ((i & ~0xc000003f)==0) return 1; + + return 0; +} + +static void w_as_opcode_mov (void) +{ + w_as_opcode ("mov"); +} + +static void w_as_opcode_load (int size_flag) +{ + w_as_opcode (size_flag==SIZE_LONG ? "ldr" : size_flag==SIZE_WORD ? "ldrsh" : "ldrb"); +} + +static void w_as_ld_indexed (struct parameter *parameter_p,int dreg,int size_flag) +{ + int offset; + + offset=parameter_p->parameter_offset; + if ((offset & -4)!=0){ + int reg1,reg2; + + reg1=parameter_p->parameter_data.ir->a_reg.r; + reg2=parameter_p->parameter_data.ir->d_reg.r; + + w_as_opcode ("add"); + w_as_scratch_register_comma(); + w_as_register_comma (reg1); + w_as_immediate_newline (offset>>2); + + w_as_opcode_load (size_flag); + w_as_register_comma (dreg); + w_as_indexed_no_offset (offset,REGISTER_S0,reg2); + w_as_newline_after_instruction(); + } else { + w_as_opcode_load (size_flag); + w_as_register_comma (dreg); + w_as_indexed_no_offset_ir (offset,parameter_p->parameter_data.ir); + w_as_newline_after_instruction(); + } +} + +static int w_as_register_parameter (struct parameter *parameter_p) +{ + switch (parameter_p->parameter_type){ + case P_REGISTER: + return parameter_p->parameter_data.reg.r; + case P_LABEL: + w_as_opcode ("ldr"); + w_as_scratch_register_comma(); + w_as_immediate_label (parameter_p->parameter_data.l); + w_as_newline_after_instruction(); + return REGISTER_S0; + case P_IMMEDIATE: + { + int i; + + i=parameter_p->parameter_data.i; + if (mov_or_mvn_immediate (i)){ + w_as_opcode_mov(); + w_as_scratch_register_comma(); + w_as_immediate_newline (i); + } else { + if (instruction_n_after_ltorg+MAX_LITERAL_INSTRUCTION_OFFSET < ltorg_at_instruction_n) + ltorg_at_instruction_n = instruction_n_after_ltorg+MAX_LITERAL_INSTRUCTION_OFFSET; + + w_as_opcode ("ldr"); + w_as_scratch_register_comma(); + fprintf (assembly_file,"=%d",i); + w_as_newline_after_instruction(); + } + return REGISTER_S0; + } + case P_INDIRECT: + w_as_opcode ("ldr"); + w_as_scratch_register_comma(); + w_as_indirect_newline (parameter_p->parameter_offset,parameter_p->parameter_data.reg.r); + return REGISTER_S0; + case P_INDEXED: + w_as_ld_indexed (parameter_p,REGISTER_S0,SIZE_LONG); + return REGISTER_S0; + case P_INDIRECT_WITH_UPDATE: + w_as_opcode ("ldr"); + w_as_scratch_register_comma; + w_as_indirect_with_update_newline (parameter_p->parameter_offset,parameter_p->parameter_data.reg.r); + return REGISTER_S0; + case P_PRE_DECREMENT: + w_as_opcode ("ldr"); + w_as_scratch_register_comma(); + fprintf (assembly_file,"[sp,#-4]"); + w_as_newline_after_instruction(); + return REGISTER_S0; + case P_POST_INCREMENT: + w_as_opcode ("ldr"); + w_as_scratch_register_comma(); + fprintf (assembly_file,"[sp],#4"); + w_as_newline_after_instruction(); + return REGISTER_S0; + case P_INDIRECT_POST_ADD: + w_as_opcode ("ldr"); + w_as_scratch_register_comma(); + w_as_indirect_post_add_newline (parameter_p->parameter_offset,parameter_p->parameter_data.reg.r); + return REGISTER_S0; + case P_F_REGISTER: + w_as_opcode ("ldr"); + w_as_scratch_register_comma(); + fprintf (assembly_file,"%%st(%d)",parameter_p->parameter_data.reg.r<<1); + w_as_newline_after_instruction(); + return REGISTER_S0; + default: + internal_error_in_function ("w_as_register_parameter"); + } +} + +static void w_as_jump_parameter (register struct parameter *parameter) +{ + switch (parameter->parameter_type){ + case P_LABEL: + if (parameter->parameter_data.l->label_number!=0) + w_as_local_label (parameter->parameter_data.l->label_number); + else + w_as_label (parameter->parameter_data.l->label_name); + break; + case P_INDIRECT: + { + int offset,reg; + + offset=parameter->parameter_offset; + reg=parameter->parameter_data.reg.r; + + if (offset!=0) + fprintf (assembly_file,"%d(%%%s)",offset,register_name[reg+7]); + else + fprintf (assembly_file,"(%%%s)",register_name[reg+7]); + break; + } + case P_REGISTER: + { + int reg; + + reg=parameter->parameter_data.reg.r; + + fprintf (assembly_file,"%s",register_name[reg+7]); + break; + } + default: + internal_error_in_function ("w_as_jump_parameter"); + } +} + +static void w_as_opcode_store (int size_flag) +{ + w_as_opcode (size_flag==SIZE_LONG ? "str" : size_flag==SIZE_WORD ? "strh" : "strb"); +} + +static void w_as_register_register_newline (int reg1,int reg2) +{ + w_as_register_comma (reg1); + w_as_register (reg2); + w_as_newline_after_instruction(); +} + +static void w_as_opcode_register_newline (char *opcode,int reg1) +{ + w_as_opcode (opcode); + w_as_register (reg1); + w_as_newline_after_instruction(); +} + +static void w_as_opcode_register_register_newline (char *opcode,int reg1,int reg2) +{ + w_as_opcode (opcode); + w_as_register_register_newline (reg1,reg2); +} + +static void w_as_movl_register_register_newline (int reg1,int reg2) +{ + w_as_opcode_mov(); + w_as_register_register_newline (reg1,reg2); +} + +static void w_as_immediate_register_newline (int i,int reg) +{ + w_as_immediate (i); + w_as_comma_register (reg); + w_as_newline_after_instruction(); +} + +static void w_as_ld_large_immediate (int i,int reg) +{ + if (instruction_n_after_ltorg+MAX_LITERAL_INSTRUCTION_OFFSET < ltorg_at_instruction_n) + ltorg_at_instruction_n = instruction_n_after_ltorg+MAX_LITERAL_INSTRUCTION_OFFSET; + + w_as_opcode ("ldr"); + w_as_register_comma (reg); + fprintf (assembly_file,"=%d",i); + w_as_newline_after_instruction(); +} + +static void w_as_ld_immediate (int i,int reg) +{ + if (mov_or_mvn_immediate (i)){ + w_as_opcode_mov(); + w_as_register_comma (reg); + w_as_immediate_newline (i); + } else + w_as_ld_large_immediate (i,reg); +} + +static void w_as_move_instruction (struct instruction *instruction,int size_flag) +{ + if (instruction->instruction_parameters[1].parameter_type==P_REGISTER){ + switch (instruction->instruction_parameters[0].parameter_type){ + case P_DESCRIPTOR_NUMBER: + w_as_opcode ("ldr"); + w_as_register_comma (instruction->instruction_parameters[1].parameter_data.reg.r); + w_as_descriptor (instruction->instruction_parameters[0].parameter_data.l, + instruction->instruction_parameters[0].parameter_offset); + w_as_newline_after_instruction(); + return; + case P_IMMEDIATE: + w_as_ld_immediate (instruction->instruction_parameters[0].parameter_data.i, + instruction->instruction_parameters[1].parameter_data.reg.r); + return; + case P_REGISTER: + w_as_opcode_mov(); + w_as_register_comma (instruction->instruction_parameters[1].parameter_data.reg.r); + w_as_register (instruction->instruction_parameters[0].parameter_data.reg.r); + w_as_newline_after_instruction(); + return; + case P_INDIRECT: + w_as_opcode_load (size_flag); + w_as_register_comma (instruction->instruction_parameters[1].parameter_data.reg.r); + w_as_indirect_newline (instruction->instruction_parameters[0].parameter_offset, + instruction->instruction_parameters[0].parameter_data.reg.r); + return; + case P_INDEXED: + w_as_ld_indexed (&instruction->instruction_parameters[0], + instruction->instruction_parameters[1].parameter_data.reg.r,size_flag); + return; + case P_INDIRECT_WITH_UPDATE: + w_as_opcode_load (size_flag); + w_as_register_comma (instruction->instruction_parameters[1].parameter_data.reg.r); + w_as_indirect_with_update_newline (instruction->instruction_parameters[0].parameter_offset, + instruction->instruction_parameters[0].parameter_data.reg.r); + return; + case P_POST_INCREMENT: + w_as_opcode ("ldr"); + w_as_register_comma (instruction->instruction_parameters[1].parameter_data.reg.r); + fprintf (assembly_file,"[sp],#4"); + w_as_newline_after_instruction(); + return; + case P_INDIRECT_POST_ADD: + w_as_opcode ("ldr"); + w_as_register_comma (instruction->instruction_parameters[1].parameter_data.reg.r); + w_as_indirect_post_add_newline (instruction->instruction_parameters[0].parameter_offset, + instruction->instruction_parameters[0].parameter_data.reg.r); + return; + case P_LABEL: + w_as_opcode_mov(); + w_as_label_parameter (&instruction->instruction_parameters[0]); + w_as_comma_register (instruction->instruction_parameters[1].parameter_data.reg.r); + w_as_newline_after_instruction(); + return; + } + internal_error_in_function ("w_as_move_instruction"); + return; + } else { + struct parameter parameter; + int s_reg; + + parameter=instruction->instruction_parameters[0]; + + switch (parameter.parameter_type){ + case P_REGISTER: + s_reg=parameter.parameter_data.reg.r; + break; + case P_INDIRECT: + w_as_opcode_load (size_flag); + w_as_scratch_register_comma(); + w_as_indirect_newline (parameter.parameter_offset,parameter.parameter_data.reg.r); + s_reg = REGISTER_S0; + break; + case P_INDEXED: + w_as_ld_indexed (¶meter,REGISTER_S0,size_flag); + s_reg = REGISTER_S0; + break; + case P_DESCRIPTOR_NUMBER: + w_as_opcode ("ldr"); + w_as_scratch_register(); + w_as_comma(); + w_as_descriptor (parameter.parameter_data.l,parameter.parameter_offset); + w_as_newline_after_instruction(); + s_reg = REGISTER_S0; + break; + case P_IMMEDIATE: + w_as_ld_immediate (instruction->instruction_parameters[0].parameter_data.i,REGISTER_S0); + s_reg = REGISTER_S0; + break; + case P_POST_INCREMENT: + w_as_opcode ("ldr"); + w_as_scratch_register(); + fprintf (assembly_file,",[sp],#4"); + w_as_newline_after_instruction(); + s_reg = REGISTER_S0; + break; + case P_INDIRECT_WITH_UPDATE: + w_as_opcode ("ldr"); + w_as_scratch_register_comma(); + w_as_indirect_with_update (parameter.parameter_offset,parameter.parameter_data.reg.r); + w_as_newline_after_instruction(); + s_reg = REGISTER_S0; + break; + case P_INDIRECT_POST_ADD: + w_as_opcode ("ldr"); + w_as_scratch_register_comma(); + w_as_indirect_post_add (parameter.parameter_offset,parameter.parameter_data.reg.r); + w_as_newline_after_instruction(); + s_reg = REGISTER_S0; + break; + default: + internal_error_in_function ("w_as_move_instruction"); + return; + } + + switch (instruction->instruction_parameters[1].parameter_type){ + case P_INDIRECT: + w_as_opcode (size_flag==SIZE_LONG ? "str" : size_flag==SIZE_WORD ? "strh" : "strb"); + w_as_register_comma (s_reg); + w_as_indirect_newline (instruction->instruction_parameters[1].parameter_offset, + instruction->instruction_parameters[1].parameter_data.reg.r); + return; + case P_PRE_DECREMENT: + w_as_opcode ("str"); + w_as_register (s_reg); + fprintf (assembly_file,",[sp,#-4]!"); + w_as_newline_after_instruction(); + return; + case P_INDEXED: + { + int offset; + + offset=instruction->instruction_parameters[1].parameter_offset; + if ((offset & -4)!=0){ + int reg1,reg2,reg3; + + reg1=instruction->instruction_parameters[1].parameter_data.ir->a_reg.r; + reg2=instruction->instruction_parameters[1].parameter_data.ir->d_reg.r; + + if (s_reg==REGISTER_S0) + reg3=REGISTER_S1; + else + reg3=REGISTER_S0; + + w_as_opcode ("add"); + w_as_register_comma (reg3); + w_as_register_comma (reg1); + w_as_immediate_newline (offset>>2); + + w_as_opcode_store (size_flag); + w_as_register_comma (s_reg); + w_as_indexed_no_offset (offset,reg3,reg2); + w_as_newline_after_instruction(); + } else { + w_as_opcode_store (size_flag); + w_as_register_comma (s_reg); + w_as_indexed_no_offset_ir (instruction->instruction_parameters[1].parameter_offset, + instruction->instruction_parameters[1].parameter_data.ir); + w_as_newline_after_instruction(); + } + return; + } + case P_INDIRECT_WITH_UPDATE: + w_as_opcode (size_flag==SIZE_LONG ? "str" : size_flag==SIZE_WORD ? "strh" : "strb"); + w_as_register_comma (s_reg); + w_as_indirect_with_update_newline (instruction->instruction_parameters[1].parameter_offset, + instruction->instruction_parameters[1].parameter_data.reg.r); + return; + case P_INDIRECT_POST_ADD: + w_as_opcode (size_flag==SIZE_LONG ? "str" : size_flag==SIZE_WORD ? "strh" : "strb"); + w_as_register_comma (s_reg); + w_as_indirect_post_add_newline (instruction->instruction_parameters[1].parameter_offset, + instruction->instruction_parameters[1].parameter_data.reg.r); + return; + case P_LABEL: + w_as_opcode_mov(); + w_as_register_comma (s_reg); + w_as_label_parameter (&instruction->instruction_parameters[1]); + w_as_newline_after_instruction(); + return; + default: + internal_error_in_function ("w_as_move_instruction"); + } + } +} + +static void w_as_movem_instruction (struct instruction *instruction) +{ + int n_regs; + + n_regs = instruction->instruction_arity-1; + + if (instruction->instruction_parameters[0].parameter_type!=P_REGISTER){ + int s_reg,reg_n; + + if (instruction->instruction_parameters[0].parameter_type==P_PRE_DECREMENT) + w_as_opcode ("ldmdb"); + else if (instruction->instruction_parameters[0].parameter_type==P_POST_INCREMENT) + w_as_opcode ("ldmia"); + else { + internal_error_in_function ("w_as_movem_instruction"); + return; + } + + w_as_register (instruction->instruction_parameters[0].parameter_data.reg.r); + fprintf (assembly_file,"!,{"); + w_as_register (instruction->instruction_parameters[1].parameter_data.reg.r); + for (reg_n=1; reg_n<n_regs; ++reg_n) + w_as_comma_register (instruction->instruction_parameters[1+reg_n].parameter_data.reg.r); + fprintf (assembly_file,"}"); + w_as_newline_after_instruction(); + + return; + } else { + int d_reg,reg_n; + + if (instruction->instruction_parameters[n_regs].parameter_type==P_PRE_DECREMENT) + w_as_opcode ("stmdb"); + else if (instruction->instruction_parameters[n_regs].parameter_type==P_POST_INCREMENT) + w_as_opcode ("stmia"); + else { + internal_error_in_function ("w_as_movem_instruction"); + return; + } + + w_as_register (instruction->instruction_parameters[n_regs].parameter_data.reg.r); + fprintf (assembly_file,"!,{"); + w_as_register (instruction->instruction_parameters[0].parameter_data.reg.r); + for (reg_n=1; reg_n<n_regs; ++reg_n) + w_as_comma_register (instruction->instruction_parameters[reg_n].parameter_data.reg.r); + fprintf (assembly_file,"}"); + w_as_newline_after_instruction(); + + return; + } + + internal_error_in_function ("w_as_movem_instruction"); +} + +static void w_as_lea_instruction (struct instruction *instruction) +{ + if (instruction->instruction_parameters[1].parameter_type==P_REGISTER){ + switch (instruction->instruction_parameters[0].parameter_type){ + case P_INDIRECT: + w_as_opcode ("add"); + w_as_register_comma (instruction->instruction_parameters[1].parameter_data.reg.r); + w_as_register_comma (instruction->instruction_parameters[0].parameter_data.reg.r); + fprintf (assembly_file,"#%d",instruction->instruction_parameters[0].parameter_offset); + w_as_newline_after_instruction(); + return; + case P_INDEXED: + if (instruction->instruction_parameters[0].parameter_offset==0){ + w_as_opcode ("add"); + w_as_register_comma (instruction->instruction_parameters[1].parameter_data.reg.r); + w_as_register_comma (instruction->instruction_parameters[0].parameter_data.ir->a_reg.r); + w_as_register_newline (instruction->instruction_parameters[0].parameter_data.ir->d_reg.r); + return; + } + break; + case P_LABEL: + if (instruction_n_after_ltorg+MAX_LITERAL_INSTRUCTION_OFFSET < ltorg_at_instruction_n) + ltorg_at_instruction_n = instruction_n_after_ltorg+MAX_LITERAL_INSTRUCTION_OFFSET; + + w_as_opcode ("ldr"); + w_as_register_comma (instruction->instruction_parameters[1].parameter_data.reg.r); + putc ('=',assembly_file); + w_as_label_parameter (&instruction->instruction_parameters[0]); + if (instruction->instruction_parameters[0].parameter_offset!=0){ + int offset; + + offset=instruction->instruction_parameters[0].parameter_offset; + fprintf (assembly_file,offset>=0 ? "+%d" : "%d",offset); + } + w_as_newline_after_instruction(); + return; + } + } + internal_error_in_function ("w_as_lea_instruction"); +} + +static void w_as_dyadic_instruction (struct instruction *instruction,char *opcode) +{ + if (instruction->instruction_parameters[0].parameter_type==P_IMMEDIATE && + mov_or_mvn_immediate (instruction->instruction_parameters[0].parameter_data.i)) + { + w_as_opcode (opcode); + w_as_register_comma (instruction->instruction_parameters[1].parameter_data.reg.r); + w_as_register_comma (instruction->instruction_parameters[1].parameter_data.reg.r); + w_as_immediate_newline (instruction->instruction_parameters[0].parameter_data.i); + } else { + int reg0; + + reg0 = w_as_register_parameter (&instruction->instruction_parameters[0]); + + w_as_opcode (opcode); + w_as_register_comma (instruction->instruction_parameters[1].parameter_data.reg.r); + w_as_register_comma (instruction->instruction_parameters[1].parameter_data.reg.r); + w_as_register_newline (reg0); + } +} + +static void w_as_reg_reg_imm_instruction (struct instruction *instruction,char *opcode) +{ + if (mov_or_mvn_immediate (instruction->instruction_parameters[2].parameter_data.i)){ + w_as_opcode (opcode); + w_as_register_comma (instruction->instruction_parameters[1].parameter_data.reg.r); + w_as_register_comma (instruction->instruction_parameters[0].parameter_data.reg.r); + w_as_immediate_newline (instruction->instruction_parameters[2].parameter_data.i); + } else { + int reg0; + + reg0 = w_as_register_parameter (&instruction->instruction_parameters[2]); + + w_as_opcode (opcode); + w_as_register_comma (instruction->instruction_parameters[1].parameter_data.reg.r); + w_as_register_comma (instruction->instruction_parameters[0].parameter_data.reg.r); + w_as_register_newline (reg0); + } +} + +static void w_as_mul_instruction (struct instruction *instruction) +{ + if (instruction->instruction_parameters[0].parameter_type==P_REGISTER){ + int reg0,reg1; + + reg0 = instruction->instruction_parameters[0].parameter_data.reg.r; + reg1 = instruction->instruction_parameters[1].parameter_data.reg.r; + + if (reg0==reg1){ + w_as_opcode_mov(); + w_as_scratch_register_comma(); + w_as_register (reg0); + w_as_newline_after_instruction(); + reg0 = REGISTER_S0; + } + + w_as_opcode ("mul"); + w_as_register_comma (reg1); + w_as_register_comma (reg0); + w_as_register_newline (reg1); + } else if (instruction->instruction_parameters[0].parameter_type==P_INDIRECT){ + int reg0; + + reg0 = w_as_register_parameter (&instruction->instruction_parameters[0]); + + w_as_opcode ("mul"); + w_as_register_comma (instruction->instruction_parameters[1].parameter_data.reg.r); + w_as_register_comma (reg0); + w_as_register_newline (instruction->instruction_parameters[1].parameter_data.reg.r); + } else { + int reg0; + + reg0 = w_as_register_parameter (&instruction->instruction_parameters[0]); + + w_as_opcode ("mul"); + w_as_register_comma (instruction->instruction_parameters[1].parameter_data.reg.r); + w_as_register_comma (reg0); + w_as_register_newline (instruction->instruction_parameters[1].parameter_data.reg.r); + } +} + +static void w_as_shift_instruction (struct instruction *instruction,char *opcode) +{ + if (instruction->instruction_parameters[0].parameter_type==P_IMMEDIATE){ + w_as_opcode (opcode); + w_as_register_comma (instruction->instruction_parameters[1].parameter_data.reg.r); + w_as_register_comma (instruction->instruction_parameters[1].parameter_data.reg.r); + w_as_immediate_newline (instruction->instruction_parameters[0].parameter_data.i & 31); + } else { + w_as_opcode (opcode); + w_as_register_comma (instruction->instruction_parameters[1].parameter_data.reg.r); + w_as_register_comma (instruction->instruction_parameters[1].parameter_data.reg.r); + w_as_register_newline (instruction->instruction_parameters[0].parameter_data.reg.r); + } +} + +static void w_as_cmp_instruction (struct instruction *instruction) +{ + switch (instruction->instruction_parameters[0].parameter_type){ + case P_DESCRIPTOR_NUMBER: + { + int reg1,reg2; + + reg1 = w_as_register_parameter (&instruction->instruction_parameters[1]); + reg2 = reg1!=REGISTER_S0 ? REGISTER_S0 : REGISTER_S1; + + w_as_opcode ("ldr"); + w_as_register_comma (reg2); + w_as_descriptor (instruction->instruction_parameters[0].parameter_data.l, + instruction->instruction_parameters[0].parameter_offset); + w_as_newline_after_instruction(); + + w_as_opcode ("cmp"); + w_as_register_comma (reg1); + w_as_register_newline (reg2); + return; + } + case P_IMMEDIATE: + { + int reg1; + + reg1 = w_as_register_parameter (&instruction->instruction_parameters[1]); + + if (mov_or_mvn_immediate (instruction->instruction_parameters[0].parameter_data.i)){ + w_as_opcode ("cmp"); + w_as_register_comma (reg1); + w_as_immediate_newline (instruction->instruction_parameters[0].parameter_data.i); + return; + } else { + int reg2; + + reg2 = reg1!=REGISTER_S0 ? REGISTER_S0 : REGISTER_S1; + + w_as_ld_large_immediate (instruction->instruction_parameters[0].parameter_data.i,reg2); + + w_as_opcode ("cmp"); + w_as_register_comma (reg1); + w_as_register_newline (reg2); + return; + } + } + } + + if (instruction->instruction_parameters[1].parameter_type==P_REGISTER){ + int reg0; + + reg0=w_as_register_parameter (&instruction->instruction_parameters[0]); + + w_as_opcode ("cmp"); + w_as_register_comma (instruction->instruction_parameters[1].parameter_data.reg.r); + w_as_register_newline (reg0); + return; + } + + internal_error_in_function ("w_as_cmp_instruction"); +} + +static void w_as_tst_instruction (struct instruction *instruction) +{ + int reg0; + + reg0=w_as_register_parameter (&instruction->instruction_parameters[0]); + + w_as_opcode ("cmp"); + w_as_register_comma (reg0); + w_as_immediate_newline (0); +} + +static void w_as_monadic_instruction (struct instruction *instruction,char *opcode) +{ + w_as_opcode (opcode); + w_as_register_comma (instruction->instruction_parameters[0].parameter_data.reg.r); + w_as_register_newline (instruction->instruction_parameters[0].parameter_data.reg.r); +} + +static void w_as_btst_instruction (struct instruction *instruction) +{ + if (instruction->instruction_parameters[1].parameter_type==P_REGISTER){ + w_as_opcode ("tst"); + w_as_register_comma (instruction->instruction_parameters[1].parameter_data.reg.r); + w_as_immediate_newline (instruction->instruction_parameters[0].parameter_data.i); + } else { + w_as_opcode ("ldr"); + w_as_scratch_register_comma(); + w_as_indirect_newline (instruction->instruction_parameters[1].parameter_offset,instruction->instruction_parameters[1].parameter_data.reg.r); + + w_as_opcode ("tst"); + w_as_scratch_register_comma(); + w_as_immediate_newline (instruction->instruction_parameters[0].parameter_data.i); + } +} + +void w_as_jmp_instruction (struct instruction *instruction) +{ + switch (instruction->instruction_parameters[0].parameter_type){ + case P_INDIRECT: + w_as_opcode ("ldr"); + fputs ("pc,",assembly_file); + w_as_indirect_newline (instruction->instruction_parameters[0].parameter_offset, + instruction->instruction_parameters[0].parameter_data.reg.r); + break; + case P_REGISTER: + w_as_opcode_mov(); + fputs ("pc",assembly_file); + w_as_comma(); + w_as_register_newline (instruction->instruction_parameters[0].parameter_data.reg.r); + break; + default: + w_as_opcode ("b"); + w_as_jump_parameter (&instruction->instruction_parameters[0]); + w_as_newline_after_instruction(); + } + write_float_constants(); + w_as_opcode (".ltorg"); + w_as_newline(); + instruction_n_after_ltorg = 0u; + ltorg_at_instruction_n = 0u-1u; +} + +void w_as_jmpp_instruction (struct instruction *instruction) +{ +#if 0 + struct parameter *parameter_p; + + parameter_p=&instruction->instruction_parameters[0]; + + switch (parameter_p->parameter_type){ + case P_LABEL: + { + int offset; + + offset=parameter_p->parameter_offset; + + if (offset==0){ + w_as_opcode ("call"); + w_as_label ("profile_t"); + w_as_newline_after_instruction(); + } + + w_as_opcode ("jmp"); + if (parameter_p->parameter_data.l->label_number!=0) + w_as_local_label (parameter_p->parameter_data.l->label_number); + else + w_as_label (parameter_p->parameter_data.l->label_name); + + if (offset!=0) + fprintf (assembly_file,"+%d",offset); + + break; + } + case P_INDIRECT: + case P_REGISTER: + w_as_opcode ("call"); + w_as_label ("profile_t"); + w_as_newline_after_instruction(); + + w_as_opcode ("jmp"); + w_as_jump_parameter (&instruction->instruction_parameters[0]); + break; + default: + internal_error_in_function ("w_as_jmpp_instruction"); + } + + w_as_newline_after_instruction(); +#else + internal_error_in_function ("w_as_jmpp_instruction"); +#endif +} + +static void w_as_branch_instruction (struct instruction *instruction,char *opcode) +{ + w_as_opcode (opcode); + w_as_label_parameter (&instruction->instruction_parameters[0]); + w_as_newline_after_instruction(); +} + +static void as_test_floating_point_condition_code (void) +{ + w_as_opcode ("fmstat"); + w_as_newline_after_instruction(); +} + +static void w_as_float_branch_instruction (struct instruction *instruction,char *opcode) +{ + as_test_floating_point_condition_code(); + + /* Z N C V + equal 1 0 1 0 + less than 0 1 0 0 + greater than 0 0 1 0 + unordered 0 0 1 1 + + bgt Z==0 && N==V + ble Z==1 || N!=V + */ + w_as_opcode (opcode); + w_as_label_parameter (&instruction->instruction_parameters[0]); + w_as_newline_after_instruction(); +} + +static void w_as_jsr_instruction (struct instruction *instruction) +{ + if (instruction->instruction_parameters[0].parameter_type==P_INDIRECT){ + w_as_opcode ("ldr"); + w_as_scratch_register_comma(); + w_as_indirect_newline (instruction->instruction_parameters[0].parameter_offset, + instruction->instruction_parameters[0].parameter_data.reg.r); + + if (instruction->instruction_arity>1) + switch (instruction->instruction_parameters[1].parameter_type){ + case P_INDIRECT_WITH_UPDATE: + w_as_opcode ("str"); + fprintf (assembly_file,"pc,[sp,#%d]!",instruction->instruction_parameters[1].parameter_offset); + w_as_newline_after_instruction(); + } + + w_as_opcode ("blx"); + w_as_scratch_register(); + w_as_newline_after_instruction(); + } else { + if (instruction->instruction_arity>1) + switch (instruction->instruction_parameters[1].parameter_type){ + case P_INDIRECT_WITH_UPDATE: + w_as_opcode ("str"); + fprintf (assembly_file,"pc,[sp,#%d]!",instruction->instruction_parameters[1].parameter_offset); + w_as_newline_after_instruction(); + break; + case P_INDIRECT: + w_as_opcode ("str"); + fprintf (assembly_file,"pc,[sp,#%d]",instruction->instruction_parameters[1].parameter_offset); + w_as_newline_after_instruction(); + break; + } + + if (instruction->instruction_parameters[0].parameter_type==P_REGISTER) + w_as_opcode ("blx"); + else + w_as_opcode ("bl"); + w_as_jump_parameter (&instruction->instruction_parameters[0]); + w_as_newline_after_instruction(); + } +} + +static void w_as_set_condition_instruction (struct instruction *instruction,char *opcode1,char *opcode2) +{ + int r; + char *reg_s; + + r=instruction->instruction_parameters[0].parameter_data.reg.r; + + w_as_opcode (opcode1); + w_as_register (r); + fprintf (assembly_file,",#1"); + w_as_newline_after_instruction(); + + w_as_opcode (opcode2); + w_as_register (r); + fprintf (assembly_file,",#0"); + w_as_newline_after_instruction(); +} + +static void w_as_set_float_condition_instruction (struct instruction *instruction,char *opcode1,char *opcode2) +{ + as_test_floating_point_condition_code(); + w_as_set_condition_instruction (instruction,opcode1,opcode2); +} + +static void w_as_lsl_register_newline (int reg,int shift) +{ + w_as_register (reg); + if (shift!=0) + fprintf (assembly_file,",lsl #%d",shift); + w_as_newline_after_instruction(); +} + +static void w_as_lsr_register_newline (int reg,int shift) +{ + w_as_register (reg); + fprintf (assembly_file,",lsr #%d",shift); + w_as_newline_after_instruction(); +} + +static void w_as_lea_indexed_no_offset_ir (int s_reg,int offset,struct index_registers *index_registers) +{ + w_as_opcode ("add"); + w_as_register_comma (s_reg); + w_as_register_comma (index_registers->a_reg.r); + w_as_lsl_register_newline (index_registers->d_reg.r,offset & 3); + w_as_newline_after_instruction(); +} + +static void w_as_div_instruction (struct instruction *instruction) +{ + int i,abs_i,d_reg; + struct ms ms; + + d_reg=instruction->instruction_parameters[1].parameter_data.reg.r; + + if (instruction->instruction_parameters[0].parameter_type!=P_IMMEDIATE){ + internal_error_in_function ("w_as_div_instruction"); + return; + } + i=instruction->instruction_parameters[0].parameter_data.i; + + if (i==0){ + internal_error_in_function ("w_as_div_instruction"); + return; + } + + abs_i=abs (i); + + if ((abs_i & (abs_i-1))==0){ + int log2i; + unsigned int i2; + + if (abs_i==1){ + if (i<0){ + w_as_opcode ("neg"); + w_as_register_comma (d_reg); + w_as_register_newline (d_reg); + } + return; + } + + log2i=0; + i2=abs_i; + while (i2>1){ + i2>>=1; + ++log2i; + } + + if (log2i==1){ + w_as_opcode ("add"); + w_as_register_comma (d_reg); + w_as_register_comma (d_reg); + w_as_lsr_register_newline (d_reg,31); + } else { + w_as_opcode ("cmp"); + w_as_register_comma (d_reg); + w_as_immediate_newline (0); + + if (log2i<=8){ + w_as_opcode ("addlt"); + w_as_register_comma (d_reg); + w_as_register_comma (d_reg); + w_as_immediate_newline (abs_i-1); + } else { + w_as_opcode ("add"); + w_as_scratch_register_comma(); + w_as_register_comma (d_reg); + w_as_immediate_newline (abs_i); + + w_as_opcode ("sublt"); + w_as_register_comma (d_reg); + w_as_scratch_register_comma(); + w_as_immediate_newline (1); + } + } + + if (i>=0){ + w_as_opcode ("asr"); + w_as_register_comma (d_reg); + w_as_register_comma (d_reg); + w_as_immediate_newline (log2i); + } else { + w_as_opcode_mov(); + w_as_scratch_register_comma(); + w_as_immediate_newline (0); + + w_as_opcode ("sub"); + w_as_register_comma (d_reg); + w_as_scratch_register_comma(); + w_as_register (d_reg); + fprintf (assembly_file,",asr #%d",log2i); + w_as_newline_after_instruction(); + } + return; + } + + ms=magic (abs_i); + + w_as_ld_immediate (ms.m,REGISTER_S0); + + if (ms.s==0){ + if (ms.m>=0){ + w_as_opcode ("lsr"); + w_as_register_comma (REGISTER_S1); + w_as_register_comma (d_reg); + w_as_immediate_newline (31); + + w_as_opcode ("smmla"); + w_as_register_comma (d_reg); + w_as_register_comma (d_reg); + w_as_scratch_register_comma(); + w_as_register_newline (REGISTER_S1); + + if (i<0){ + w_as_opcode ("neg"); + w_as_register_comma (d_reg); + w_as_register_newline (d_reg); + } + } else { + if (ms.m>=0){ + w_as_opcode ("smmul"); + w_as_scratch_register_comma(); + w_as_scratch_register_comma(); + w_as_register_newline (d_reg); + } else { + w_as_opcode ("smmla"); + w_as_scratch_register_comma(); + w_as_scratch_register_comma(); + w_as_register_comma (d_reg); + w_as_register_newline (d_reg); + } + if (i>=0){ + w_as_opcode ("add"); + w_as_register_comma (d_reg); + w_as_scratch_register_comma(); + w_as_lsr_register_newline (d_reg,31); + } else { + w_as_opcode ("sub"); + w_as_register_comma (d_reg); + w_as_scratch_register_comma(); + w_as_register (d_reg); + fprintf (assembly_file,",asr #%d",31); + w_as_newline_after_instruction(); + } + } + } else { + if (ms.m>=0){ + w_as_opcode ("smmul"); + w_as_scratch_register_comma(); + w_as_scratch_register_comma(); + w_as_register_newline (d_reg); + } else { + w_as_opcode ("smmla"); + w_as_scratch_register_comma(); + w_as_scratch_register_comma(); + w_as_register_comma (d_reg); + w_as_register_newline (d_reg); + } + if (i>=0){ + w_as_opcode ("lsr"); + w_as_register_comma (d_reg); + w_as_register_comma (d_reg); + w_as_immediate_newline (31); + + w_as_opcode ("add"); + w_as_register_comma (d_reg); + w_as_register_comma (d_reg); + w_as_scratch_register(); + fprintf (assembly_file,",asr #%d",ms.s); + w_as_newline_after_instruction(); + } else { + w_as_opcode ("asr"); + w_as_register_comma (d_reg); + w_as_register_comma (d_reg); + w_as_immediate_newline (31); + + w_as_opcode ("sub"); + w_as_register_comma (d_reg); + w_as_register_comma (d_reg); + w_as_scratch_register(); + fprintf (assembly_file,",asr #%d",ms.s); + w_as_newline_after_instruction(); + } + } +} + +static void w_as_rem_instruction (struct instruction *instruction) +{ + int i,d_reg; + struct ms ms; + + d_reg=instruction->instruction_parameters[1].parameter_data.reg.r; + + if (instruction->instruction_parameters[0].parameter_type!=P_IMMEDIATE){ + internal_error_in_function ("w_as_rem_instruction"); + return; + } + i=instruction->instruction_parameters[0].parameter_data.i; + + if (i==0){ + internal_error_in_function ("w_as_rem_instruction"); + return; + } + + i=abs (i); + + if ((i & (i-1))==0){ + int log2i; + unsigned int i2; + + if (i==1){ + w_as_ld_immediate (0,d_reg); + return; + } + + w_as_opcode ("sub"); + w_as_scratch_register_comma(); + w_as_register_comma (d_reg); + w_as_lsr_register_newline (d_reg,31); + + log2i=0; + i2=i; + while (i2>1){ + i2>>=1; + ++log2i; + } + + if (i<=256){ + if (log2i!=1){ + w_as_opcode ("asr"); + w_as_register_comma (d_reg); + w_as_register_comma (d_reg); + w_as_immediate_newline (log2i-1); + } + w_as_opcode ("and"); + w_as_scratch_register_comma(); + w_as_scratch_register_comma(); + w_as_immediate_newline (i-1); + } else { + w_as_ld_immediate (-1,REGISTER_S1); + + w_as_opcode ("asr"); + w_as_register_comma (d_reg); + w_as_register_comma (d_reg); + w_as_immediate_newline (log2i-1); + + w_as_opcode ("and"); + w_as_scratch_register_comma(); + w_as_scratch_register_comma(); + w_as_lsr_register_newline (REGISTER_S1,32-log2i); + } + + w_as_opcode ("sub"); + w_as_register_comma (d_reg); + w_as_scratch_register_comma(); + w_as_lsr_register_newline (d_reg,32-log2i); + + return; + } + + + ms=magic (i); + + w_as_ld_immediate (ms.m,REGISTER_S0); + + if (ms.s==0){ + if (ms.m>=0){ + w_as_opcode ("lsr"); + w_as_register_comma (REGISTER_S1); + w_as_register_comma (d_reg); + w_as_immediate_newline (31); + + w_as_opcode ("smmla"); + w_as_scratch_register_comma(); + w_as_register_comma (d_reg); + w_as_scratch_register_comma(); + w_as_register_newline (REGISTER_S1); + } else { + if (ms.m>=0){ + w_as_opcode ("smmul"); + w_as_scratch_register_comma(); + w_as_scratch_register_comma(); + w_as_register_newline (d_reg); + } else { + w_as_opcode ("smmla"); + w_as_scratch_register_comma(); + w_as_scratch_register_comma(); + w_as_register_comma (d_reg); + w_as_register_newline (d_reg); + } + + w_as_opcode ("add"); + w_as_scratch_register_comma(); + w_as_scratch_register_comma(); + w_as_lsr_register_newline (d_reg,31); + } + } else { + if (ms.m>=0){ + w_as_opcode ("smmul"); + w_as_scratch_register_comma(); + w_as_scratch_register_comma(); + w_as_register_newline (d_reg); + } else { + w_as_opcode ("smmla"); + w_as_scratch_register_comma(); + w_as_scratch_register_comma(); + w_as_register_comma (d_reg); + w_as_register_newline (d_reg); + } + + w_as_opcode ("lsr"); + w_as_register_comma (REGISTER_S1); + w_as_register_comma (d_reg); + w_as_immediate_newline (31); + + w_as_opcode ("add"); + w_as_scratch_register_comma(); + w_as_register_comma (REGISTER_S1); + w_as_scratch_register(); + fprintf (assembly_file,",asr #%d",ms.s); + w_as_newline_after_instruction(); + } + + { + unsigned int i2; + + i2=i & (i-1); + if ((i2 & (i2-1))==0){ + unsigned int n; + int n_shifts; + + n=i; + + n_shifts=0; + while (n>0){ + while ((n & 1)==0){ + n>>=1; + ++n_shifts; + } + + w_as_opcode ("sub"); + w_as_register_comma (d_reg); + w_as_register_comma (d_reg); + w_as_lsl_register_newline (REGISTER_S0,n_shifts); + + n>>=1; + n_shifts=1; + } + } else { +#if 1 + w_as_ld_immediate (-i,REGISTER_S1); + + w_as_opcode ("mla"); + w_as_register_comma (d_reg); + w_as_register_comma (REGISTER_S0); + w_as_register_comma (REGISTER_S1); + w_as_register_newline (d_reg); +#else + /* mls is an illegal instruction on the raspberry pi b+ */ + w_as_ld_immediate (i,REGISTER_S1); + + w_as_opcode ("mls"); + w_as_register_comma (d_reg); + w_as_register_comma (REGISTER_S0); + w_as_register_comma (REGISTER_S1); + w_as_register_newline (d_reg); +#endif + } + } +} + +static void w_as_word_instruction (struct instruction *instruction) +{ + fprintf (assembly_file,"\t.word\t%d\n", + (int)instruction->instruction_parameters[0].parameter_data.i); +} + +static void w_as_float_constant (int label_number,DOUBLE *r_p) +{ + struct float_constant *new_float_constant; + + new_float_constant=allocate_memory_from_heap (sizeof (struct float_constant)); + + new_float_constant->float_constant_r_p=r_p; + new_float_constant->float_constant_label_number=label_number; + + *float_constant_l=new_float_constant; + float_constant_l=&new_float_constant->float_constant_next; + + new_float_constant->float_constant_next=NULL; +} + +static void w_as_fld_parameter (struct parameter *parameter_p) +{ + switch (parameter_p->parameter_type){ + case P_F_IMMEDIATE: + { + int label_number; + + label_number=next_label_id++; + + w_as_opcode ("fldd"); + w_as_fp_register_comma (15); + fprintf (assembly_file,"i_%d",label_number); + w_as_newline_after_instruction(); + w_as_float_constant (label_number,parameter_p->parameter_data.r); + return; + } + case P_INDIRECT: + w_as_opcode ("fldd"); + w_as_fp_register_comma (15); + w_as_indirect_newline (parameter_p->parameter_offset,parameter_p->parameter_data.reg.r); + return; + case P_INDEXED: + { + int offset; + + offset=parameter_p->parameter_offset; + + w_as_lea_indexed_no_offset_ir (REGISTER_S0,offset,parameter_p->parameter_data.ir); + + w_as_opcode ("fldd"); + w_as_fp_register_comma (15); + w_as_indirect_newline (offset>>2,REGISTER_S0); + w_as_newline_after_instruction(); + return; + } + default: + internal_error_in_function ("w_as_fld_parameter"); + return; + } +} + +static void w_as_dyadic_float_instruction (struct instruction *instruction,char *opcode) +{ + int d_freg; + + d_freg=instruction->instruction_parameters[1].parameter_data.reg.r; + if (instruction->instruction_parameters[0].parameter_type==P_F_REGISTER){ + w_as_opcode (opcode); + w_as_fp_register_comma (d_freg); + w_as_fp_register_comma (d_freg); + w_as_fp_register_newline (instruction->instruction_parameters[0].parameter_data.reg.r); + } else { + w_as_fld_parameter (&instruction->instruction_parameters[0]); + + w_as_opcode (opcode); + w_as_fp_register_comma (d_freg); + w_as_fp_register_comma (d_freg); + w_as_fp_register_newline (15); + } +} + +static void w_as_float_sub_or_div_instruction (struct instruction *instruction,char *opcode) +{ + int d_freg; + + d_freg=instruction->instruction_parameters[1].parameter_data.reg.r; + if (instruction->instruction_parameters[0].parameter_type==P_F_REGISTER){ + w_as_opcode (opcode); + w_as_fp_register_comma (d_freg); + if (instruction->instruction_parameters[1].parameter_flags & FP_REVERSE_SUB_DIV_OPERANDS){ + w_as_fp_register_comma (instruction->instruction_parameters[0].parameter_data.reg.r); + w_as_fp_register_newline (d_freg); + } else { + w_as_fp_register_comma (d_freg); + w_as_fp_register_newline (instruction->instruction_parameters[0].parameter_data.reg.r); + } + } else { + w_as_fld_parameter (&instruction->instruction_parameters[0]); + + w_as_opcode (opcode); + w_as_fp_register_comma (d_freg); + if (instruction->instruction_parameters[1].parameter_flags & FP_REVERSE_SUB_DIV_OPERANDS){ + w_as_fp_register_comma (15); + w_as_fp_register_newline (d_freg); + } else { + w_as_fp_register_comma (d_freg); + w_as_fp_register_newline (15); + } + } +} + +static void w_as_compare_float_instruction (struct instruction *instruction) +{ + if (instruction->instruction_parameters[0].parameter_type!=P_F_REGISTER){ + if (instruction->instruction_parameters[0].parameter_type==P_F_IMMEDIATE && + ((int*)&instruction->instruction_parameters[0].parameter_data.r)[0]==0 && + ((int*)&instruction->instruction_parameters[0].parameter_data.r)[1]==0) + { + w_as_opcode ("fcmpzd"); + w_as_fp_register_newline (instruction->instruction_parameters[1].parameter_data.reg.r); + } else { + w_as_fld_parameter (&instruction->instruction_parameters[0]); + + w_as_opcode ("fcmpd"); + w_as_fp_register_comma (instruction->instruction_parameters[1].parameter_data.reg.r); + w_as_fp_register_newline (15); + } + } else { + w_as_opcode ("fcmpd"); + w_as_fp_register_comma (instruction->instruction_parameters[1].parameter_data.reg.r); + w_as_fp_register_newline (instruction->instruction_parameters[0].parameter_data.reg.r); + } +} + +static void w_as_monadic_float_instruction (struct instruction *instruction,char *opcode) +{ + int d_freg; + + d_freg=instruction->instruction_parameters[1].parameter_data.reg.r; + if (instruction->instruction_parameters[0].parameter_type==P_F_REGISTER){ + w_as_opcode (opcode); + w_as_fp_register (d_freg); + w_as_comma(); + w_as_fp_register_newline (instruction->instruction_parameters[0].parameter_data.reg.r); + } else { + w_as_fld_parameter (&instruction->instruction_parameters[0]); + + w_as_opcode (opcode); + w_as_fp_register (d_freg); + w_as_comma(); + w_as_fp_register_newline (15); + } +} + +static void w_as_fmove_instruction (struct instruction *instruction) +{ + switch (instruction->instruction_parameters[1].parameter_type){ + case P_F_REGISTER: + switch (instruction->instruction_parameters[0].parameter_type){ + case P_F_REGISTER: + w_as_opcode ("fcpyd"); + w_as_fp_register_comma (instruction->instruction_parameters[1].parameter_data.reg.r); + w_as_fp_register_newline (instruction->instruction_parameters[0].parameter_data.reg.r); + return; + case P_INDIRECT: + w_as_opcode ("fldd"); + w_as_fp_register_comma (instruction->instruction_parameters[1].parameter_data.reg.r); + w_as_indirect_newline (instruction->instruction_parameters[0].parameter_offset, + instruction->instruction_parameters[0].parameter_data.reg.r); + return; + case P_INDEXED: + { + int offset; + + offset=instruction->instruction_parameters[0].parameter_offset; + + w_as_lea_indexed_no_offset_ir (REGISTER_S0,offset,instruction->instruction_parameters[0].parameter_data.ir); + + w_as_opcode ("fldd"); + w_as_fp_register_comma (instruction->instruction_parameters[1].parameter_data.reg.r); + w_as_indirect_newline (offset>>2,REGISTER_S0); + return; + } + case P_F_IMMEDIATE: + { + int label_number=next_label_id++; + + w_as_float_constant (label_number,instruction->instruction_parameters[0].parameter_data.r); + w_as_opcode ("fldd"); + w_as_fp_register_comma (instruction->instruction_parameters[1].parameter_data.reg.r); + fprintf (assembly_file,"i_%d",label_number); + w_as_newline_after_instruction(); + return; + } + default: + internal_error_in_function ("w_as_fmove_instruction"); + return; + } + case P_INDIRECT: + case P_INDEXED: + if (instruction->instruction_parameters[0].parameter_type==P_F_REGISTER){ + if (instruction->instruction_parameters[1].parameter_type==P_INDIRECT){ + w_as_opcode ("fstd"); + w_as_fp_register_comma (instruction->instruction_parameters[0].parameter_data.reg.r); + w_as_indirect_newline (instruction->instruction_parameters[1].parameter_offset, + instruction->instruction_parameters[1].parameter_data.reg.r); + return; + } else { + int offset; + + offset=instruction->instruction_parameters[1].parameter_offset; + + w_as_lea_indexed_no_offset_ir (REGISTER_S0,offset,instruction->instruction_parameters[1].parameter_data.ir); + + w_as_opcode ("fstd"); + w_as_fp_register_comma (instruction->instruction_parameters[0].parameter_data.reg.r); + w_as_indirect_newline (offset>>2,REGISTER_S0); + return; + } + } + } + internal_error_in_function ("w_as_fmove_instruction"); +} + +static w_as_floads_instruction (struct instruction *instruction) +{ + switch (instruction->instruction_parameters[1].parameter_type){ + case P_F_REGISTER: + { + int d_freg; + + d_freg=instruction->instruction_parameters[1].parameter_data.reg.r; + + switch (instruction->instruction_parameters[0].parameter_type){ + case P_INDIRECT: + w_as_opcode ("vldr"); + fprintf (assembly_file,"s%d",d_freg<<1); + w_as_indirect_newline (instruction->instruction_parameters[0].parameter_offset, + instruction->instruction_parameters[0].parameter_data.reg.r); + break; + case P_INDEXED: + { + int offset; + + offset=instruction->instruction_parameters[0].parameter_offset; + + w_as_lea_indexed_no_offset_ir (REGISTER_S0,offset,instruction->instruction_parameters[0].parameter_data.ir); + + w_as_opcode ("vldr"); + fprintf (assembly_file,"s%d",d_freg<<1); + w_as_comma(); + w_as_indirect_newline (offset>>2,REGISTER_S0); + break; + } + default: + internal_error_in_function ("w_as_floads_instruction"); + return; + } + + w_as_opcode ("vcvtr.f64.f32"); + w_as_fp_register_comma (d_freg); + fprintf (assembly_file,"s%d",d_freg<<1); + w_as_newline_after_instruction(); + return; + } + } + internal_error_in_function ("w_as_floads_instruction"); +} + +static void w_as_fmoves_instruction (struct instruction *instruction) +{ + if (instruction->instruction_parameters[0].parameter_type==P_F_REGISTER){ + int s_freg; + + s_freg=instruction->instruction_parameters[0].parameter_data.reg.r; + + w_as_opcode ("vcvtr.f32.f64"); + fprintf (assembly_file,"s%d",s_freg<<1); + w_as_comma(); + w_as_fp_register_newline (15); + + switch (instruction->instruction_parameters[1].parameter_type){ + case P_INDIRECT: + w_as_opcode ("vstr"); + fprintf (assembly_file,"s%d",15<<1); + w_as_comma(); + w_as_indirect_newline (instruction->instruction_parameters[1].parameter_offset, + instruction->instruction_parameters[1].parameter_data.reg.r); + return; + case P_INDEXED: + { + int offset; + + offset=instruction->instruction_parameters[0].parameter_offset; + + w_as_lea_indexed_no_offset_ir (REGISTER_S0,offset,instruction->instruction_parameters[0].parameter_data.ir); + + w_as_opcode ("vstr"); + fprintf (assembly_file,"s%d",15<<1); + w_as_comma(); + w_as_indirect_newline (offset>>2,REGISTER_S0); + } + return; + } + } + internal_error_in_function ("w_as_fmoves_instruction"); +} + +static void w_as_fmovel_instruction (struct instruction *instruction) +{ + if (instruction->instruction_parameters[0].parameter_type==P_F_REGISTER){ + if (instruction->instruction_parameters[1].parameter_type==P_REGISTER){ + int s_freg; + + s_freg=instruction->instruction_parameters[0].parameter_data.reg.r; + + w_as_opcode ("vcvtr.s32.f64" /*"ftosid"*/); + fprintf (assembly_file,"s%d,d%d",s_freg<<1,s_freg); + w_as_newline_after_instruction(); + + w_as_opcode ("fmrs"); + w_as_register_comma (instruction->instruction_parameters[1].parameter_data.reg.r); + fprintf (assembly_file,"s%d",s_freg<<1); + w_as_newline_after_instruction(); + } else + internal_error_in_function ("w_as_fmovel_instruction"); + } else { + int freg; + + freg=instruction->instruction_parameters[1].parameter_data.reg.r; + + switch (instruction->instruction_parameters[0].parameter_type){ + case P_REGISTER: + w_as_opcode ("vmov"); + fprintf (assembly_file,"s%d",freg<<1); + w_as_comma_register (instruction->instruction_parameters[0].parameter_data.reg.r); + w_as_newline_after_instruction(); + break; + case P_INDIRECT: + w_as_opcode ("ldr"); + w_as_scratch_register_comma(); + w_as_indirect_newline (instruction->instruction_parameters[0].parameter_offset, + instruction->instruction_parameters[0].parameter_data.reg.r); + + w_as_opcode ("vmov"); + fprintf (assembly_file,"s%d",freg<<1); + w_as_comma_scratch_register_newline(); + break; + case P_INDEXED: + w_as_ld_indexed (&instruction->instruction_parameters[0],REGISTER_S0,SIZE_LONG); + + w_as_opcode ("vmov"); + fprintf (assembly_file,"s%d",freg<<1); + w_as_comma_scratch_register_newline(); + break; + case P_IMMEDIATE: + /* the assembler does not assemble the following instruction correctly */ + w_as_opcode ("vldr" /*"flds"*/); + fprintf (assembly_file,"s%d,=%d",freg<<1,instruction->instruction_parameters[0].parameter_data.i); + w_as_newline_after_instruction(); + break; + default: + internal_error_in_function ("w_as_fmovel_instruction"); + return; + } + + w_as_opcode ("vcvt.f64.s32" /*"fsitod"*/); + fprintf (assembly_file,"d%d,s%d",freg,freg<<1); + w_as_newline_after_instruction(); + return; + } +} + +static void w_as_rts_instruction (void) +{ + w_as_opcode ("ldr"); + fprintf (assembly_file,"pc,[sp],#4"); + w_as_newline_after_instruction(); + + write_float_constants(); + w_as_opcode (".ltorg"); + w_as_newline(); + instruction_n_after_ltorg = 0u; + ltorg_at_instruction_n = 0u-1u; +} + +static void w_as_rtsi_instruction (struct instruction *instruction) +{ + int offset; + + offset = instruction->instruction_parameters[0].parameter_data.imm; + w_as_opcode ("ldr"); + fprintf (assembly_file,"pc,[sp],#%d",offset); + w_as_newline_after_instruction(); + + write_float_constants(); + w_as_opcode (".ltorg"); + w_as_newline(); + instruction_n_after_ltorg = 0u; + ltorg_at_instruction_n = 0u-1u; +} + +static void w_as_rtsp_instruction (void) +{ + w_as_opcode ("b"); + w_as_label ("profile_r"); + w_as_newline_after_instruction(); +} + +static void w_as_instructions (struct instruction *instruction) +{ + while (instruction!=NULL){ + switch (instruction->instruction_icode){ + case IMOVE: + w_as_move_instruction (instruction,SIZE_LONG); + break; + case ILEA: + w_as_lea_instruction (instruction); + break; + case IADD: + w_as_dyadic_instruction (instruction,"add"); + break; + case ISUB: + w_as_dyadic_instruction (instruction,"sub"); + break; + case ICMP: + w_as_cmp_instruction (instruction); + break; + case IJMP: + w_as_jmp_instruction (instruction); + break; + case IJMPP: + w_as_jmpp_instruction (instruction); + break; + case IJSR: + w_as_jsr_instruction (instruction); + break; + case IRTS: + w_as_rts_instruction(); + break; + case IRTSI: + w_as_rtsi_instruction (instruction); + break; + case IRTSP: + w_as_rtsp_instruction(); + break; + case IBEQ: + w_as_branch_instruction (instruction,"beq"); + break; + case IBGE: + w_as_branch_instruction (instruction,"bge"); + break; + case IBGEU: + w_as_branch_instruction (instruction,"bhs"); + break; + case IBGT: + w_as_branch_instruction (instruction,"bgt"); + break; + case IBGTU: + w_as_branch_instruction (instruction,"bhi"); + break; + case IBLE: + w_as_branch_instruction (instruction,"ble"); + break; + case IBLEU: + w_as_branch_instruction (instruction,"bls"); + break; + case IBLT: + w_as_branch_instruction (instruction,"blt"); + break; + case IBLTU: + w_as_branch_instruction (instruction,"blo"); + break; + case IBNE: + w_as_branch_instruction (instruction,"bne"); + break; + case IBO: + w_as_branch_instruction (instruction,"bvs"); + break; + case IBNO: + w_as_branch_instruction (instruction,"bvc"); + break; + case ILSL: + w_as_shift_instruction (instruction,"lsl"); + break; + case ILSR: + w_as_shift_instruction (instruction,"lsr"); + break; + case IASR: + w_as_shift_instruction (instruction,"asr"); + break; + case IMUL: + w_as_mul_instruction (instruction); + break; + case IDIV: + w_as_div_instruction (instruction); + break; + case IREM: + w_as_rem_instruction (instruction); + break; + case IAND: + w_as_dyadic_instruction (instruction,"and"); + break; + case IOR: + w_as_dyadic_instruction (instruction,"orr"); + break; + case IEOR: + w_as_dyadic_instruction (instruction,"eor"); + break; + case IADDI: + w_as_reg_reg_imm_instruction (instruction,"add"); + break; + case ILSLI: + w_as_reg_reg_imm_instruction (instruction,"lsl"); + break; + case ISEQ: + w_as_set_condition_instruction (instruction,"moveq","movne"); + break; + case ISGE: + w_as_set_condition_instruction (instruction,"movge","movlt"); + break; + case ISGEU: + w_as_set_condition_instruction (instruction,"movhs","movlo"); + break; + case ISGT: + w_as_set_condition_instruction (instruction,"movgt","movle"); + break; + case ISGTU: + w_as_set_condition_instruction (instruction,"movhi","movls"); + break; + case ISLE: + w_as_set_condition_instruction (instruction,"movle","movgt"); + break; + case ISLEU: + w_as_set_condition_instruction (instruction,"movls","movhi"); + break; + case ISLT: + w_as_set_condition_instruction (instruction,"movlt","movge"); + break; + case ISLTU: + w_as_set_condition_instruction (instruction,"movlo","movhs"); + break; + case ISNE: + w_as_set_condition_instruction (instruction,"movne","moveq"); + break; + case ISO: + w_as_set_condition_instruction (instruction,"movvs","movvc"); + break; + case ISNO: + w_as_set_condition_instruction (instruction,"movvc","movvs"); + break; + case ITST: + w_as_tst_instruction (instruction); + break; + case IBTST: + w_as_btst_instruction (instruction); + break; + case IMOVEDB: + w_as_move_instruction (instruction,SIZE_WORD); + break; + case IMOVEB: + w_as_move_instruction (instruction,SIZE_BYTE); + break; + case INEG: + w_as_monadic_instruction (instruction,"neg"); + break; + case INOT: + w_as_monadic_instruction (instruction,"mvn"); + break; + case IMOVEM: + w_as_movem_instruction (instruction); + break; + case IADC: + w_as_dyadic_instruction (instruction,"adcl"); + break; + case ISBB: + w_as_dyadic_instruction (instruction,"sbbl"); + break; + case IROTR: + w_as_shift_instruction (instruction,"ror"); + break; + case IADDO: + w_as_dyadic_instruction (instruction,"adds"); + break; + case ISUBO: + w_as_dyadic_instruction (instruction,"subs"); + break; + case IFMOVE: + w_as_fmove_instruction (instruction); + break; + case IFADD: + w_as_dyadic_float_instruction (instruction,"faddd"); + break; + case IFSUB: + w_as_float_sub_or_div_instruction (instruction,"fsubd"); + break; + case IFCMP: + w_as_compare_float_instruction (instruction); + break; + case IFDIV: + w_as_float_sub_or_div_instruction (instruction,"fdivd"); + break; + case IFMUL: + w_as_dyadic_float_instruction (instruction,"fmuld"); + break; + case IFBEQ: + w_as_float_branch_instruction (instruction,"beq"); + break; + case IFBGE: + w_as_float_branch_instruction (instruction,"bpl"); + break; + case IFBGT: + w_as_float_branch_instruction (instruction,"bgt"); + break; + case IFBLE: + w_as_float_branch_instruction (instruction,"ble"); + break; + case IFBLT: + w_as_float_branch_instruction (instruction,"bmi"); + break; + case IFBNE: + w_as_float_branch_instruction (instruction,"bne"); + break; + case IFMOVEL: + w_as_fmovel_instruction (instruction); + break; + case IFLOADS: + w_as_floads_instruction (instruction); + break; + case IFMOVES: + w_as_fmoves_instruction (instruction); + break; + case IFSQRT: + w_as_monadic_float_instruction (instruction,"fsqrtd"); + break; + case IFNEG: + w_as_monadic_float_instruction (instruction,"fnegd"); + break; + case IFABS: + w_as_monadic_float_instruction (instruction,"fabsd"); + break; + case IFSEQ: + w_as_set_float_condition_instruction (instruction,"moveq","movne"); + break; + case IFSGE: + w_as_set_float_condition_instruction (instruction,"bpl","bmi"); + break; + case IFSGT: + w_as_set_float_condition_instruction (instruction,"movgt","movle"); + break; + case IFSLE: + w_as_set_float_condition_instruction (instruction,"movle","movgt"); + break; + case IFSLT: + w_as_set_float_condition_instruction (instruction,"bmi","bpl"); + break; + case IFSNE: + w_as_set_float_condition_instruction (instruction,"movne","moveq"); + break; + case IWORD: + w_as_word_instruction (instruction); + break; + case IFTST: + default: + internal_error_in_function ("w_as_instructions"); + } + instruction=instruction->instruction_next; + } +} + +static void w_as_number_of_arguments (int n_node_arguments) +{ + w_as_opcode (".long"); + fprintf (assembly_file,"%d",n_node_arguments); + w_as_newline(); +} + +struct call_and_jump { + struct call_and_jump *cj_next; + WORD cj_label_id; + WORD cj_jump_id; + char *cj_call_label_name; +}; + +static struct call_and_jump *first_call_and_jump,*last_call_and_jump; + +static void w_as_garbage_collect_test (register struct basic_block *block) +{ + LONG n_cells; + int label_id_1,label_id_2; + struct call_and_jump *new_call_and_jump; + + n_cells=block->block_n_new_heap_cells; + + label_id_1=next_label_id++; + label_id_2=next_label_id++; + + new_call_and_jump=allocate_memory_from_heap (sizeof (struct call_and_jump)); + + new_call_and_jump->cj_next=NULL; + new_call_and_jump->cj_label_id=label_id_1; + new_call_and_jump->cj_jump_id=label_id_2; + + switch (block->block_n_begin_a_parameter_registers){ + case 0: + new_call_and_jump->cj_call_label_name="collect_0"; + break; + case 1: + new_call_and_jump->cj_call_label_name="collect_1"; + break; + case 2: + new_call_and_jump->cj_call_label_name="collect_2"; + break; + case 3: + new_call_and_jump->cj_call_label_name="collect_3"; + break; + default: + internal_error_in_function ("w_as_garbage_collect_test"); + return; + } + + if (first_call_and_jump!=NULL) + last_call_and_jump->cj_next=new_call_and_jump; + else + first_call_and_jump=new_call_and_jump; + last_call_and_jump=new_call_and_jump; + + if (mov_or_mvn_immediate (n_cells)){ + w_as_opcode ("subs"); + fprintf (assembly_file,"r5,r5,#%d",n_cells); + w_as_newline_after_instruction(); + } else { + if (instruction_n_after_ltorg+MAX_LITERAL_INSTRUCTION_OFFSET < ltorg_at_instruction_n) + ltorg_at_instruction_n = instruction_n_after_ltorg+MAX_LITERAL_INSTRUCTION_OFFSET; + + w_as_opcode ("ldr"); + w_as_scratch_register_comma(); + fprintf (assembly_file,"=%d",n_cells); + w_as_newline_after_instruction(); + + w_as_opcode ("subs"); + fputs ("r5,r5",assembly_file); + w_as_comma_scratch_register_newline(); + } + + w_as_opcode ("blo"); + w_as_internal_label (label_id_1); + w_as_newline_after_instruction (); + + w_as_define_internal_label (label_id_2); +} + +static void w_as_call_and_jump (struct call_and_jump *call_and_jump) +{ + w_as_define_internal_label (call_and_jump->cj_label_id); + + w_as_opcode ("bl"); + w_as_label (call_and_jump->cj_call_label_name); + w_as_newline_after_instruction(); + + w_as_opcode ("b"); + w_as_internal_label (call_and_jump->cj_jump_id); + w_as_newline_after_instruction(); +} + +static void w_as_labels (register struct block_label *labels) +{ + for (; labels!=NULL; labels=labels->block_label_next) + if (labels->block_label_label->label_number==0) + w_as_define_code_label (labels->block_label_label); + else + w_as_define_local_label (labels->block_label_label->label_number); +} + +static void w_as_check_stack (struct basic_block *block) +{ + if (block->block_a_stack_check_size>0){ + if (block->block_a_stack_check_size<=32){ + w_as_opcode ("cmpl"); + fprintf (assembly_file,end_a_stack_label->label_name); + w_as_comma_register (A_STACK_POINTER); + } else { + w_as_opcode ("leal"); + w_as_indirect (block->block_a_stack_check_size,A_STACK_POINTER); + w_as_comma_scratch_register(); + w_as_newline_after_instruction(); + + w_as_opcode ("cmpl"); + fprintf (assembly_file,end_a_stack_label->label_name); + w_as_comma_scratch_register(); + } + w_as_newline_after_instruction(); + + w_as_opcode ("bhs"); + w_as_label (stack_overflow_label->label_name); + w_as_newline_after_instruction(); + } + + if (block->block_b_stack_check_size>0){ + if (block->block_b_stack_check_size<=32){ + w_as_opcode ("cmpl"); + fprintf (assembly_file,end_b_stack_label->label_name); + w_as_comma_register (B_STACK_POINTER); + } else { + w_as_opcode ("leal"); + w_as_indirect (block->block_b_stack_check_size,B_STACK_POINTER); + w_as_comma_scratch_register(); + w_as_newline_after_instruction(); + + w_as_opcode ("cmpl"); + fprintf (assembly_file,end_b_stack_label->label_name); + w_as_comma_scratch_register(); + } + w_as_newline_after_instruction(); + + w_as_opcode ("jb"); + w_as_label (stack_overflow_label->label_name); + w_as_newline_after_instruction(); + } +} + +void initialize_write_assembly (FILE *ass_file) +{ + assembly_file=ass_file; + + in_data_section=0; + + first_call_and_jump=NULL; +} + +extern LABEL *eval_fill_label,*eval_upd_labels[]; + +static void w_as_node_entry_info (struct basic_block *block) +{ + if (block->block_ea_label!=NULL){ + int n_node_arguments; + + n_node_arguments=block->block_n_node_arguments; + if (n_node_arguments<-2) + n_node_arguments=1; + + if (n_node_arguments>=0 && block->block_ea_label!=eval_fill_label){ + if (!block->block_profile){ + w_as_opcode ("ldr"); + w_as_register_comma (REGISTER_A3); + w_as_immediate_label_name (block->block_ea_label->label_name); + w_as_newline(); + + w_as_opcode ("b"); + w_as_label (eval_upd_labels[n_node_arguments]->label_name); + w_as_newline(); + + w_as_instruction_without_parameters ("nop"); + } else { + w_as_opcode_mov(); + w_as_immediate_label_name (block->block_ea_label->label_name); + w_as_comma_register (REGISTER_D0); + w_as_newline(); + + w_as_opcode_mov(); + w_as_descriptor (block->block_profile_function_label,0); + w_as_comma_register (REGISTER_A3); + w_as_newline(); + + w_as_opcode ("b"); + w_as_label (eval_upd_labels[n_node_arguments]->label_name); + fprintf (assembly_file,"-7"); + w_as_newline(); + } + } else { + w_as_opcode ("b"); + w_as_label (block->block_ea_label->label_name); + w_as_newline(); + + w_as_space (8); + } + + if (block->block_descriptor!=NULL && (block->block_n_node_arguments<0 || parallel_flag || module_info_flag)) + w_as_label_in_code_section (block->block_descriptor->label_name); + else + w_as_number_of_arguments (0); + } else + if (block->block_descriptor!=NULL && (block->block_n_node_arguments<0 || parallel_flag || module_info_flag)) + w_as_label_in_code_section (block->block_descriptor->label_name); + + w_as_number_of_arguments (block->block_n_node_arguments); +} + +static void w_as_profile_call (struct basic_block *block) +{ + w_as_opcode_mov(); + w_as_descriptor (block->block_profile_function_label,0); + w_as_comma_scratch_register(); + w_as_newline_after_instruction(); + + w_as_opcode ("call"); + + if (block->block_n_node_arguments>-100) + w_as_label (block->block_profile==2 ? "profile_n2" : "profile_n"); + else { + switch (block->block_profile){ + case 2: w_as_label ("profile_s2"); break; + case 4: w_as_label ("profile_l"); break; + case 5: w_as_label ("profile_l2"); break; + default: w_as_label ("profile_s"); + } + } + w_as_newline_after_instruction(); +} + +#ifdef NEW_APPLY +extern LABEL *add_empty_node_labels[]; + +static void w_as_apply_update_entry (struct basic_block *block) +{ + if (block->block_profile) + w_as_profile_call (block); + + if (block->block_n_node_arguments==-200){ + w_as_opcode ("b"); + w_as_label (block->block_ea_label->label_name); + w_as_newline(); + + w_as_instruction_without_parameters ("nop"); + } else { + w_as_opcode ("bl"); + w_as_label (add_empty_node_labels[block->block_n_node_arguments+200]->label_name); + w_as_newline(); + + w_as_opcode ("b"); + w_as_label (block->block_ea_label->label_name); + w_as_newline(); + } +} +#endif + +void write_assembly (VOID) +{ + struct basic_block *block; + struct call_and_jump *call_and_jump; + + instruction_n_after_ltorg = 0u; + ltorg_at_instruction_n = 0u-1u; + + fprintf (assembly_file,"\t.fpu\tvfp"); + w_as_newline(); + + w_as_to_code_section(); + + float_constant_l=&first_float_constant; + first_float_constant=NULL; + + for_l (block,first_block,block_next){ + if (block->block_n_node_arguments>-100){ + w_as_align (2); + w_as_node_entry_info (block); + } +#ifdef NEW_APPLY + else if (block->block_n_node_arguments<-100) + w_as_apply_update_entry (block); +#endif + + w_as_labels (block->block_labels); + + if (block->block_profile) + w_as_profile_call (block); + + if (block->block_n_new_heap_cells>0) + w_as_garbage_collect_test (block); + + if (check_stack && (block->block_a_stack_check_size>0 || block->block_b_stack_check_size>0)) + w_as_check_stack (block); + + w_as_instructions (block->block_instructions); + } + + for_l (call_and_jump,first_call_and_jump,cj_next) + w_as_call_and_jump (call_and_jump); + + write_float_constants(); +} diff --git a/cgthumb2was.h b/cgthumb2was.h new file mode 100644 index 0000000..f1845a3 --- /dev/null +++ b/cgthumb2was.h @@ -0,0 +1,25 @@ +void initialize_write_assembly (FILE *ass_file);
+void write_assembly (VOID);
+void w_as_abc_string_and_label_in_code_section (char *string,int length,char *label_name);
+void w_as_abc_string_in_code_section (char *string,int length,int label_number);
+void w_as_c_string_in_code_section (char *string,int length,int label_number);
+void w_as_c_string_in_data_section (char *string,int length);
+void w_as_descriptor_string_in_code_section (char *string,int length,int string_code_label_id,LABEL *string_label);
+void w_as_word_in_data_section (int n);
+void w_as_label_in_data_section (char *label_name);
+void w_as_descriptor_in_data_section (char *label_name);
+void w_as_define_label (LABEL *label);
+void w_as_internal_label_value (int label_id);
+void w_as_new_module (int flag);
+void w_as_long_in_data_section (int n);
+void w_as_to_data_section (void);
+void w_as_descriptor_in_code_section (char *label_name);
+void w_as_define_data_label (int label_number);
+void w_as_labeled_c_string_in_data_section (char *string,int length,int label_number);
+void w_as_abc_string_in_data_section (char *string,int length);
+void w_as_descriptor_string_in_data_section (char *string,int length,int string_label_id,LABEL *string_label);
+void w_as_abc_string_and_label_in_data_section (char *string,int length,char *label_name);
+void w_as_c_string_and_label_in_code_section (char *string,int length,char *label_name);
+#ifdef _WINDOWS_
+void w_as_new_data_module (void);
+#endif
|