Patchwork [04/13] tcg-sparc: Assume v9 cpu always, i.e. force v8plus in 32-bit mode.

login
register
mail settings
Submitter Richard Henderson
Date Sept. 17, 2012, 3:28 p.m.
Message ID <1347895732-22212-5-git-send-email-rth@twiddle.net>
Download mbox | patch
Permalink /patch/184480/
State New
Headers show

Comments

Richard Henderson - Sept. 17, 2012, 3:28 p.m.
Current code doesn't actually work in 32-bit mode at all.  Since
no one really noticed, drop the complication of v7 and v8 cpus.
Eliminate the --sparc_cpu configure option and standardize macro
testing on TCG_TARGET_REG_BITS / HOST_LONG_BITS

Also, a bug fix: don't MAP_FIXED right on top of the program
address space set in sparc64.ld.

Signed-off-by: Richard Henderson <rth@twiddle.net>
---
 configure              | 40 ++++------------------------------------
 disas.c                |  2 --
 exec.c                 | 12 +++++-------
 qemu-timer.h           |  8 +++++---
 tcg/sparc/tcg-target.c | 20 +++++---------------
 tcg/sparc/tcg-target.h |  7 ++++---
 tcg/tcg.c              |  3 ++-
 7 files changed, 25 insertions(+), 67 deletions(-)
Andreas Färber - Sept. 17, 2012, 4:04 p.m.
Am 17.09.2012 17:28, schrieb Richard Henderson:
> Current code doesn't actually work in 32-bit mode at all.  Since
> no one really noticed, drop the complication of v7 and v8 cpus.
> Eliminate the --sparc_cpu configure option and standardize macro
> testing on TCG_TARGET_REG_BITS / HOST_LONG_BITS
> 
> Also, a bug fix: don't MAP_FIXED right on top of the program
> address space set in sparc64.ld.
> 
> Signed-off-by: Richard Henderson <rth@twiddle.net>

Without knowing the code, this does not strike me as the best of ideas:
SPARC CPUs are rather uncommon these days, so being able to emulate it
in sparc32-softmmu may be helpful for keeping it working.

Could you elaborate on what exactly is broken and what would need to be
done as alternative?

The MAP_FIXED bugfix (keyword "also") should probably go into its own
patch either way.

Regards,
Andreas
Richard Henderson - Sept. 17, 2012, 5:05 p.m.
On 09/17/2012 09:04 AM, Andreas Färber wrote:
> Without knowing the code, this does not strike me as the best of ideas:
> SPARC CPUs are rather uncommon these days, so being able to emulate it
> in sparc32-softmmu may be helpful for keeping it working.
> 
> Could you elaborate on what exactly is broken and what would need to be
> done as alternative?

See, for instance, patch 2.  INDEX_op_qemu_ld64 and INDEX_op_qemu_st64
were unimplemented, caught during tcg startup with --enable-tcg-debug,
and crashing later without.

Handling only sparcv9 host cpus means that lots of code paths are able
to be cleaned up:

  (1) Multiply and divide insns are available
      (Conditional support for these is not easy.)

  (2) Endian-swapping load/store insns are available
      (Vastly cleans up qemu_ld/st; by the end of my patch set the
       fast path through the tlb is a single insn in the delay slot
       of the branch over the call to the helper.)

  (3) Conditional move insns are available
      (For setcond this is tidier than playing subtract-with-borrow games).

But sparcv9 is now coming up on 20 years old.  The amount of hardware
still live that isn't v9 capable is bound to be vanishingly small -- in
much the same way that i386 hosts without i486 bswap.  I don't think we
need to use the QEMU TCG code generator as a test case that keeps sparcv7
code alive.


r~
Blue Swirl - Sept. 17, 2012, 7:25 p.m.
On Mon, Sep 17, 2012 at 5:05 PM, Richard Henderson <rth@twiddle.net> wrote:
> On 09/17/2012 09:04 AM, Andreas Färber wrote:
>> Without knowing the code, this does not strike me as the best of ideas:
>> SPARC CPUs are rather uncommon these days, so being able to emulate it
>> in sparc32-softmmu may be helpful for keeping it working.
>>
>> Could you elaborate on what exactly is broken and what would need to be
>> done as alternative?
>
> See, for instance, patch 2.  INDEX_op_qemu_ld64 and INDEX_op_qemu_st64
> were unimplemented, caught during tcg startup with --enable-tcg-debug,
> and crashing later without.
>
> Handling only sparcv9 host cpus means that lots of code paths are able
> to be cleaned up:
>
>   (1) Multiply and divide insns are available
>       (Conditional support for these is not easy.)
>
>   (2) Endian-swapping load/store insns are available
>       (Vastly cleans up qemu_ld/st; by the end of my patch set the
>        fast path through the tlb is a single insn in the delay slot
>        of the branch over the call to the helper.)
>
>   (3) Conditional move insns are available
>       (For setcond this is tidier than playing subtract-with-borrow games).
>
> But sparcv9 is now coming up on 20 years old.  The amount of hardware
> still live that isn't v9 capable is bound to be vanishingly small -- in
> much the same way that i386 hosts without i486 bswap.  I don't think we
> need to use the QEMU TCG code generator as a test case that keeps sparcv7
> code alive.

No Linux distros supports Sparc32 anymore. There's NetBSD and OpenBSD though.

Would it make sense to break up tcg/sparc into tcg/sparc32 and
tcg/sparc64? That way it would be possible to give Sparc32 a chance of
getting fixed. But I wouldn't object removal either.

>
>
> r~
Richard Henderson - Sept. 17, 2012, 9:52 p.m.
On 09/17/2012 12:25 PM, Blue Swirl wrote:
> Would it make sense to break up tcg/sparc into tcg/sparc32 and
> tcg/sparc64? That way it would be possible to give Sparc32 a chance of
> getting fixed. But I wouldn't object removal either.

IMO someone would have to actively step forward to maintain sparcv8
before we should even consider keeping it.  It has been actively
broken for so long and no one has complained.


r~

Patch

diff --git a/configure b/configure
index 7e23309..07702b5 100755
--- a/configure
+++ b/configure
@@ -111,7 +111,6 @@  source_path=`dirname "$0"`
 cpu=""
 interp_prefix="/usr/gnemul/qemu-%M"
 static="no"
-sparc_cpu=""
 cross_prefix=""
 audio_drv_list=""
 audio_card_list="ac97 es1370 sb16 hda"
@@ -241,21 +240,6 @@  for opt do
   ;;
   --disable-debug-info) debug_info="no"
   ;;
-  --sparc_cpu=*)
-    sparc_cpu="$optarg"
-    case $sparc_cpu in
-    v7|v8|v8plus|v8plusa)
-      cpu="sparc"
-    ;;
-    v9)
-      cpu="sparc64"
-    ;;
-    *)
-      echo "undefined SPARC architecture. Exiting";
-      exit 1
-    ;;
-    esac
-  ;;
   esac
 done
 # OS specific
@@ -343,8 +327,6 @@  elif check_define __i386__ ; then
 elif check_define __x86_64__ ; then
   cpu="x86_64"
 elif check_define __sparc__ ; then
-  # We can't check for 64 bit (when gcc is biarch) or V8PLUSA
-  # They must be specified using --sparc_cpu
   if check_define __arch64__ ; then
     cpu="sparc64"
   else
@@ -792,8 +774,6 @@  for opt do
   ;;
   --enable-uname-release=*) uname_release="$optarg"
   ;;
-  --sparc_cpu=*)
-  ;;
   --enable-werror) werror="yes"
   ;;
   --disable-werror) werror="no"
@@ -881,31 +861,19 @@  for opt do
   esac
 done
 
-#
-# If cpu ~= sparc and  sparc_cpu hasn't been defined, plug in the right
-# QEMU_CFLAGS/LDFLAGS (assume sparc_v8plus for 32-bit and sparc_v9 for 64-bit)
-#
 host_guest_base="no"
 case "$cpu" in
-    sparc) case $sparc_cpu in
-           v7|v8)
-             QEMU_CFLAGS="-mcpu=${sparc_cpu} -D__sparc_${sparc_cpu}__ $QEMU_CFLAGS"
-           ;;
-           v8plus|v8plusa)
-             QEMU_CFLAGS="-mcpu=ultrasparc -D__sparc_${sparc_cpu}__ $QEMU_CFLAGS"
-           ;;
-           *) # sparc_cpu not defined in the command line
-             QEMU_CFLAGS="-mcpu=ultrasparc -D__sparc_v8plus__ $QEMU_CFLAGS"
-           esac
+    sparc)
            LDFLAGS="-m32 $LDFLAGS"
-           QEMU_CFLAGS="-m32 -ffixed-g2 -ffixed-g3 $QEMU_CFLAGS"
+           QEMU_CFLAGS="-m32 -mcpu=ultrasparc $QEMU_CFLAGS"
+           QEMU_CFLAGS="-ffixed-g2 -ffixed-g3 $QEMU_CFLAGS"
            if test "$solaris" = "no" ; then
              QEMU_CFLAGS="-ffixed-g1 -ffixed-g6 $QEMU_CFLAGS"
            fi
            ;;
     sparc64)
-           QEMU_CFLAGS="-m64 -mcpu=ultrasparc -D__sparc_v9__ $QEMU_CFLAGS"
            LDFLAGS="-m64 $LDFLAGS"
+           QEMU_CFLAGS="-m64 -mcpu=ultrasparc $QEMU_CFLAGS"
            QEMU_CFLAGS="-ffixed-g5 -ffixed-g6 -ffixed-g7 $QEMU_CFLAGS"
            if test "$solaris" != "no" ; then
              QEMU_CFLAGS="-ffixed-g1 $QEMU_CFLAGS"
diff --git a/disas.c b/disas.c
index 7b2acc9..b801c8f 100644
--- a/disas.c
+++ b/disas.c
@@ -316,9 +316,7 @@  void disas(FILE *out, void *code, unsigned long size)
     print_insn = print_insn_alpha;
 #elif defined(__sparc__)
     print_insn = print_insn_sparc;
-#if defined(__sparc_v8plus__) || defined(__sparc_v8plusa__) || defined(__sparc_v9__)
     disasm_info.mach = bfd_mach_sparc_v9b;
-#endif
 #elif defined(__arm__)
     print_insn = print_insn_arm;
 #elif defined(__MIPSEB__)
diff --git a/exec.c b/exec.c
index 5834766..ad175db 100644
--- a/exec.c
+++ b/exec.c
@@ -86,7 +86,7 @@  static int nb_tbs;
 /* any access to the tbs or the page table must use this lock */
 spinlock_t tb_lock = SPIN_LOCK_UNLOCKED;
 
-#if defined(__arm__) || defined(__sparc_v9__)
+#if defined(__arm__) || defined(__sparc__)
 /* The prologue must be reachable with a direct jump. ARM and Sparc64
  have limited branch ranges (possibly also PPC) so place it in a
  section close to code segment. */
@@ -541,10 +541,9 @@  static void code_gen_alloc(unsigned long tb_size)
         /* Cannot map more than that */
         if (code_gen_buffer_size > (800 * 1024 * 1024))
             code_gen_buffer_size = (800 * 1024 * 1024);
-#elif defined(__sparc_v9__)
+#elif defined(__sparc__) && HOST_LONG_BITS == 64
         // Map the buffer below 2G, so we can use direct calls and branches
-        flags |= MAP_FIXED;
-        start = (void *) 0x60000000UL;
+        start = (void *) 0x40000000UL;
         if (code_gen_buffer_size > (512 * 1024 * 1024))
             code_gen_buffer_size = (512 * 1024 * 1024);
 #elif defined(__arm__)
@@ -582,10 +581,9 @@  static void code_gen_alloc(unsigned long tb_size)
         /* Cannot map more than that */
         if (code_gen_buffer_size > (800 * 1024 * 1024))
             code_gen_buffer_size = (800 * 1024 * 1024);
-#elif defined(__sparc_v9__)
+#elif defined(__sparc__) && HOST_LONG_BITS == 64
         // Map the buffer below 2G, so we can use direct calls and branches
-        flags |= MAP_FIXED;
-        addr = (void *) 0x60000000UL;
+        addr = (void *) 0x40000000UL;
         if (code_gen_buffer_size > (512 * 1024 * 1024)) {
             code_gen_buffer_size = (512 * 1024 * 1024);
         }
diff --git a/qemu-timer.h b/qemu-timer.h
index f8af595..da7e97c 100644
--- a/qemu-timer.h
+++ b/qemu-timer.h
@@ -218,7 +218,7 @@  static inline int64_t cpu_get_real_ticks(void)
     return val;
 }
 
-#elif defined(__sparc_v8plus__) || defined(__sparc_v8plusa__) || defined(__sparc_v9__)
+#elif defined(__sparc__)
 
 static inline int64_t cpu_get_real_ticks (void)
 {
@@ -227,6 +227,8 @@  static inline int64_t cpu_get_real_ticks (void)
     asm volatile("rd %%tick,%0" : "=r"(rval));
     return rval;
 #else
+    /* We need an %o or %g register for this.  For recent enough gcc
+       there is an "h" constraint for that.  Don't bother with that.  */
     union {
         uint64_t i64;
         struct {
@@ -234,8 +236,8 @@  static inline int64_t cpu_get_real_ticks (void)
             uint32_t low;
         }       i32;
     } rval;
-    asm volatile("rd %%tick,%1; srlx %1,32,%0"
-                 : "=r"(rval.i32.high), "=r"(rval.i32.low));
+    asm volatile("rd %%tick,%%g1; srlx %%g1,32,%0; mov %%g1,%1"
+                 : "=r"(rval.i32.high), "=r"(rval.i32.low) : : "g1");
     return rval.i64;
 #endif
 }
diff --git a/tcg/sparc/tcg-target.c b/tcg/sparc/tcg-target.c
index 0a19313..23c2fda 100644
--- a/tcg/sparc/tcg-target.c
+++ b/tcg/sparc/tcg-target.c
@@ -621,18 +621,10 @@  static void tcg_out_setcond_i32(TCGContext *s, TCGCond cond, TCGArg ret,
 
     default:
         tcg_out_cmp(s, c1, c2, c2const);
-#if defined(__sparc_v9__) || defined(__sparc_v8plus__)
         tcg_out_movi_imm13(s, ret, 0);
-        tcg_out32 (s, ARITH_MOVCC | INSN_RD(ret)
-                   | INSN_RS1(tcg_cond_to_bcond[cond])
-                   | MOVCC_ICC | INSN_IMM11(1));
-#else
-        t = gen_new_label();
-        tcg_out_branch_i32(s, INSN_COND(tcg_cond_to_bcond[cond], 1), t);
-        tcg_out_movi_imm13(s, ret, 1);
-        tcg_out_movi_imm13(s, ret, 0);
-        tcg_out_label(s, t, s->code_ptr);
-#endif
+        tcg_out32(s, ARITH_MOVCC | INSN_RD(ret)
+                  | INSN_RS1(tcg_cond_to_bcond[cond])
+                  | MOVCC_ICC | INSN_IMM11(1));
         return;
     }
 
@@ -742,7 +734,7 @@  static const void * const qemu_st_helpers[4] = {
 #endif
 #endif
 
-#ifdef __arch64__
+#if TCG_TARGET_REG_BITS == 64
 #define HOST_LD_OP LDX
 #define HOST_ST_OP STX
 #define HOST_SLL_OP SHIFT_SLLX
@@ -1600,11 +1592,9 @@  static void tcg_target_init(TCGContext *s)
 
 #if TCG_TARGET_REG_BITS == 64
 # define ELF_HOST_MACHINE  EM_SPARCV9
-#elif defined(__sparc_v8plus__)
+#else
 # define ELF_HOST_MACHINE  EM_SPARC32PLUS
 # define ELF_HOST_FLAGS    EF_SPARC_32PLUS
-#else
-# define ELF_HOST_MACHINE  EM_SPARC
 #endif
 
 typedef struct {
diff --git a/tcg/sparc/tcg-target.h b/tcg/sparc/tcg-target.h
index 0ea87be..3b897d5 100644
--- a/tcg/sparc/tcg-target.h
+++ b/tcg/sparc/tcg-target.h
@@ -67,7 +67,8 @@  typedef enum {
 
 /* used for function call generation */
 #define TCG_REG_CALL_STACK TCG_REG_I6
-#ifdef __arch64__
+
+#if TCG_TARGET_REG_BITS == 64
 // Reserve space for AREG0
 #define TCG_TARGET_STACK_MINFRAME (176 + 4 * (int)sizeof(long) + \
                                    TCG_STATIC_CALL_ARGS_SIZE)
@@ -81,7 +82,7 @@  typedef enum {
 #define TCG_TARGET_STACK_ALIGN 8
 #endif
 
-#ifdef __arch64__
+#if TCG_TARGET_REG_BITS == 64
 #define TCG_TARGET_EXTEND_ARGS 1
 #endif
 
@@ -127,7 +128,7 @@  typedef enum {
 
 #ifdef CONFIG_SOLARIS
 #define TCG_AREG0 TCG_REG_G2
-#elif defined(__sparc_v9__)
+#elif HOST_LONG_BITS == 64
 #define TCG_AREG0 TCG_REG_G5
 #else
 #define TCG_AREG0 TCG_REG_G6
diff --git a/tcg/tcg.c b/tcg/tcg.c
index a4e7f42..3943d09 100644
--- a/tcg/tcg.c
+++ b/tcg/tcg.c
@@ -1463,7 +1463,8 @@  static void temp_allocate_frame(TCGContext *s, int temp)
 {
     TCGTemp *ts;
     ts = &s->temps[temp];
-#ifndef __sparc_v9__ /* Sparc64 stack is accessed with offset of 2047 */
+#if !(defined(__sparc__) && TCG_TARGET_REG_BITS == 64)
+    /* Sparc64 stack is accessed with offset of 2047 */
     s->current_frame_offset = (s->current_frame_offset +
                                (tcg_target_long)sizeof(tcg_target_long) - 1) &
         ~(sizeof(tcg_target_long) - 1);