summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCamil Staps2016-09-17 11:59:07 +0000
committerCamil Staps2016-09-17 12:28:16 +0000
commitf044d6d4eb48f26db0aec7e67faab6bae7057fd3 (patch)
treeb9fb9b268d4e920606c0f1c2db4ae05cedbdcf6c
parentadd Makefile.windows_mingw (diff)
Gitignore; copied stuff from arm to thumb2
-rw-r--r--.gitignore2
-rw-r--r--Makefile.linux_thumb212
-rw-r--r--cgthumb2as.c5100
-rw-r--r--cgthumb2as.h34
-rw-r--r--cgthumb2c.c753
-rw-r--r--cgthumb2was.c2908
-rw-r--r--cgthumb2was.h25
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 (&parameter,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