Preserve NEON/VFP registers across subroutines according to ARM PCS (5.1.2.1)
authorJerome Laheurte <jlaheurte@quividi.com>
Wed, 26 Nov 2014 12:29:08 +0000 (13:29 +0100)
committerSebastian Dröge <sebastian@centricular.com>
Thu, 27 Nov 2014 11:10:50 +0000 (12:10 +0100)
https://bugzilla.gnome.org/show_bug.cgi?id=727464

orc/orcarm.c
orc/orcarm.h
orc/orcprogram-arm.c
orc/orcprogram-neon.c

index e89066e..065fab4 100644 (file)
@@ -79,45 +79,91 @@ orc_arm_emit_bx_lr (OrcCompiler *compiler)
 }
 
 void
-orc_arm_emit_push (OrcCompiler *compiler, int regs)
+orc_arm_emit_push (OrcCompiler *compiler, int regs, orc_uint32 vregs)
 {
   int i;
-  int x = 0;
-
-  ORC_ASM_CODE(compiler,"  push {");
-  for(i=0;i<16;i++){
-    if (regs & (1<<i)) {
-      x |= (1<<i);
-      ORC_ASM_CODE(compiler,"r%d", i);
-      if (x != regs) {
-        ORC_ASM_CODE(compiler,", ");
+
+  if (regs) {
+    int x = 0;
+
+    ORC_ASM_CODE(compiler,"  push {");
+    for(i=0;i<16;i++){
+      if (regs & (1<<i)) {
+        x |= (1<<i);
+        ORC_ASM_CODE(compiler,"r%d", i);
+        if (x != regs) {
+          ORC_ASM_CODE(compiler,", ");
+        }
       }
     }
+    ORC_ASM_CODE(compiler,"}\n");
+
+    orc_arm_emit (compiler, 0xe92d0000 | regs);
   }
-  ORC_ASM_CODE(compiler,"}\n");
 
-  orc_arm_emit (compiler, 0xe92d0000 | regs);
+  if (vregs) {
+    int first = -1, last = -1, nregs;
+
+    ORC_ASM_CODE(compiler, "  vpush {");
+    for(i=0; i<32; ++i) {
+      if (vregs & (1U << i)) {
+        if (first==-1) {
+           ORC_ASM_CODE(compiler, "d%d", i);
+           first = i;
+        }
+        last = i;
+      }
+    }
+    // What's the deal with even/odd registers ?
+    ORC_ASM_CODE(compiler, "-d%d}\n", last+1);
+
+    nregs = last + 1 - first + 1;
+    orc_arm_emit (compiler, 0xed2d0b00 | ((first & 0x10) << 22) | ((first & 0x0f) << 12) | (nregs << 1));
+  }
 }
 
 void
-orc_arm_emit_pop (OrcCompiler *compiler, int regs)
+orc_arm_emit_pop (OrcCompiler *compiler, int regs, orc_uint32 vregs)
 {
   int i;
-  int x = 0;
-
-  ORC_ASM_CODE(compiler,"  pop {");
-  for(i=0;i<16;i++){
-    if (regs & (1<<i)) {
-      x |= (1<<i);
-      ORC_ASM_CODE(compiler,"r%d", i);
-      if (x != regs) {
-        ORC_ASM_CODE(compiler,", ");
+
+
+  if (vregs) {
+    int first = -1, last = -1, nregs;
+
+    ORC_ASM_CODE(compiler, "  vpop {");
+    for(i=0; i<32; ++i) {
+      if (vregs & (1U << i)) {
+        if (first==-1) {
+           ORC_ASM_CODE(compiler, "d%d", i);
+           first = i;
+        }
+        last = i;
       }
     }
+    ORC_ASM_CODE(compiler, "-d%d}\n", last+1);
+
+    nregs = last + 1 - first + 1;
+    orc_arm_emit (compiler, 0xecbd0b00 | ((first & 0x10) << 22) | ((first & 0x0f) << 12) | (nregs << 1));
   }
-  ORC_ASM_CODE(compiler,"}\n");
 
-  orc_arm_emit (compiler, 0xe8bd0000 | regs);
+  if (regs) {
+    int x = 0;
+
+    ORC_ASM_CODE(compiler,"  pop {");
+    for(i=0;i<16;i++){
+      if (regs & (1<<i)) {
+        x |= (1<<i);
+        ORC_ASM_CODE(compiler,"r%d", i);
+        if (x != regs) {
+          ORC_ASM_CODE(compiler,", ");
+        }
+      }
+    }
+    ORC_ASM_CODE(compiler,"}\n");
+
+    orc_arm_emit (compiler, 0xe8bd0000 | regs);
+  }
 }
 
 void
index 75651c1..1187aa3 100644 (file)
@@ -92,8 +92,8 @@ void orc_arm_emit_mov (OrcCompiler *compiler, int dest, int src);
 
 void orc_arm_emit_align (OrcCompiler *compiler, int align_shift);
 void orc_arm_emit_label (OrcCompiler *compiler, int label);
-void orc_arm_emit_push (OrcCompiler *compiler, int regs);
-void orc_arm_emit_pop (OrcCompiler *compiler, int regs);
+void orc_arm_emit_push (OrcCompiler *compiler, int regs, orc_uint32 vregs);
+void orc_arm_emit_pop (OrcCompiler *compiler, int regs, orc_uint32 vregs);
 void orc_arm_emit_branch (OrcCompiler *compiler, int cond, int label);
 void orc_arm_emit_data (OrcCompiler *compiler, orc_uint32 data);
 
index 1b62f78..86b7cf6 100644 (file)
@@ -41,7 +41,7 @@ orc_arm_emit_prologue (OrcCompiler *compiler)
       regs |= (1<<i);
     }
   }
-  if (regs) orc_arm_emit_push (compiler, regs);
+  if (regs) orc_arm_emit_push (compiler, regs, 0U);
 
 }
 
@@ -52,7 +52,7 @@ orc_arm_dump_insns (OrcCompiler *compiler)
 
   orc_arm_emit_add_r (compiler, ORC_ARM_COND_AL, 0, ORC_ARM_A2, ORC_ARM_A3, ORC_ARM_A4);
   orc_arm_emit_sub_r (compiler, ORC_ARM_COND_AL, 0, ORC_ARM_A2, ORC_ARM_A3, ORC_ARM_A4);
-  orc_arm_emit_push (compiler, 0x06);
+  orc_arm_emit_push (compiler, 0x06, 0U);
   orc_arm_emit_mov_r (compiler, ORC_ARM_COND_AL, 0, ORC_ARM_A2, ORC_ARM_A3);
 
   orc_arm_emit_branch (compiler, ORC_ARM_COND_LE, 0);
@@ -75,7 +75,7 @@ orc_arm_emit_epilogue (OrcCompiler *compiler)
       regs |= (1<<i);
     }
   }
-  if (regs) orc_arm_emit_pop (compiler, regs);
+  if (regs) orc_arm_emit_pop (compiler, regs, 0U);
   orc_arm_emit_bx_lr (compiler);
 
   /* orc_arm_dump_insns (compiler); */
index 984b089..cbe79ee 100644 (file)
@@ -34,6 +34,7 @@ void
 orc_neon_emit_prologue (OrcCompiler *compiler)
 {
   unsigned int regs = 0;
+  orc_uint32 vregs = 0;
   int i;
 
   orc_compiler_append_code(compiler,".global %s\n", compiler->program->name);
@@ -45,8 +46,15 @@ orc_neon_emit_prologue (OrcCompiler *compiler)
       regs |= (1<<i);
     }
   }
-  if (regs) orc_arm_emit_push (compiler, regs);
 
+  for(i=0;i<32;i++) {
+     if (compiler->used_regs[ORC_VEC_REG_BASE+i] &&
+         compiler->save_regs[ORC_VEC_REG_BASE+i]) {
+        vregs |= (1U << i);
+     }
+  }
+
+  orc_arm_emit_push (compiler, regs, vregs);
 }
 
 void
@@ -57,7 +65,7 @@ orc_neon_dump_insns (OrcCompiler *compiler)
 
   orc_arm_emit_add (compiler, ORC_ARM_A2, ORC_ARM_A3, ORC_ARM_A4);
   orc_arm_emit_sub (compiler, ORC_ARM_A2, ORC_ARM_A3, ORC_ARM_A4);
-  orc_arm_emit_push (compiler, 0x06);
+  orc_arm_emit_push (compiler, 0x06, 0U);
   orc_arm_emit_mov (compiler, ORC_ARM_A2, ORC_ARM_A3);
 
   orc_arm_emit_branch (compiler, ORC_ARM_COND_LE, 0);
@@ -73,6 +81,7 @@ orc_neon_emit_epilogue (OrcCompiler *compiler)
 {
   int i;
   unsigned int regs = 0;
+  orc_uint32 vregs = 0;
 
   for(i=0;i<16;i++){
     if (compiler->used_regs[ORC_GP_REG_BASE + i] &&
@@ -80,7 +89,15 @@ orc_neon_emit_epilogue (OrcCompiler *compiler)
       regs |= (1<<i);
     }
   }
-  if (regs) orc_arm_emit_pop (compiler, regs);
+
+  for(i=0;i<32;i++) {
+     if (compiler->used_regs[ORC_VEC_REG_BASE+i] &&
+         compiler->save_regs[ORC_VEC_REG_BASE+i]) {
+        vregs |= (1U << i);
+     }
+  }
+
+  orc_arm_emit_pop (compiler, regs, vregs);
   orc_arm_emit_bx_lr (compiler);
 
   /* arm_dump_insns (compiler); */
@@ -145,6 +162,9 @@ orc_compiler_neon_init (OrcCompiler *compiler)
   for(i=4;i<12;i++) {
     compiler->save_regs[ORC_GP_REG_BASE+i] = 1;
   }
+  for(i=8;i<16;i++) {
+    compiler->save_regs[ORC_VEC_REG_BASE+i] = 1;
+  }
   
   for(i=0;i<ORC_N_REGS;i++){
     compiler->alloc_regs[i] = 0;