Commit acdaac31 authored by Jerome Laheurte's avatar Jerome Laheurte Committed by Sebastian Dröge

Preserve NEON/VFP registers across subroutines according to ARM PCS (5.1.2.1)

https://bugzilla.gnome.org/show_bug.cgi?id=727464
parent 463295f6
......@@ -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
......
......@@ -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);
......
......@@ -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); */
......
......@@ -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;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment