]> git.ipfire.org Git - thirdparty/valgrind.git/commitdiff
s390x: FLOGR is not universally available. Fixes #268715.
authorJulian Seward <jseward@acm.org>
Thu, 24 Mar 2011 08:57:29 +0000 (08:57 +0000)
committerJulian Seward <jseward@acm.org>
Thu, 24 Mar 2011 08:57:29 +0000 (08:57 +0000)
(Florian Krohm, britzel@acm.org)

git-svn-id: svn://svn.valgrind.org/vex/trunk@2114

VEX/priv/host_s390_defs.c
VEX/priv/host_s390_defs.h
VEX/priv/host_s390_isel.c

index 969382432fab64ec2bc285e65927f92e091c1973..b0504dec625bae118d4df703a7ed694790d16d4d 100644 (file)
@@ -574,10 +574,10 @@ s390_insn_get_reg_usage(HRegUsage *u, const s390_insn *insn)
       s390_opnd_RMI_get_reg_usage(u, insn->variant.divs.op2);
       break;
 
-   case S390_INSN_FLOGR:
-      addHRegUse(u, HRmWrite, insn->variant.flogr.bitpos);
-      addHRegUse(u, HRmWrite, insn->variant.flogr.modval);
-      s390_opnd_RMI_get_reg_usage(u, insn->variant.flogr.src);
+   case S390_INSN_CLZ:
+      addHRegUse(u, HRmWrite, insn->variant.clz.num_bits);
+      addHRegUse(u, HRmWrite, insn->variant.clz.clobber);
+      s390_opnd_RMI_get_reg_usage(u, insn->variant.clz.src);
       break;
 
    case S390_INSN_UNOP:
@@ -781,10 +781,10 @@ s390_insn_map_regs(HRegRemap *m, s390_insn *insn)
       s390_opnd_RMI_map_regs(m, &insn->variant.divs.op2);
       break;
 
-   case S390_INSN_FLOGR:
-      insn->variant.flogr.bitpos = lookupHRegRemap(m, insn->variant.flogr.bitpos);
-      insn->variant.flogr.modval = lookupHRegRemap(m, insn->variant.flogr.modval);
-      s390_opnd_RMI_map_regs(m, &insn->variant.flogr.src);
+   case S390_INSN_CLZ:
+      insn->variant.clz.num_bits = lookupHRegRemap(m, insn->variant.clz.num_bits);
+      insn->variant.clz.clobber  = lookupHRegRemap(m, insn->variant.clz.clobber);
+      s390_opnd_RMI_map_regs(m, &insn->variant.clz.src);
       break;
 
    case S390_INSN_UNOP:
@@ -3818,19 +3818,19 @@ s390_insn_divs(UChar size, HReg rem, HReg op1, s390_opnd_RMI op2)
 
 
 s390_insn *
-s390_insn_flogr(UChar size, HReg bitpos, HReg modval, s390_opnd_RMI src)
+s390_insn_clz(UChar size, HReg num_bits, HReg clobber, s390_opnd_RMI src)
 {
    s390_insn *insn = LibVEX_Alloc(sizeof(s390_insn));
 
    vassert(size == 8);
-   vassert(! hregIsVirtual(bitpos));
-   vassert(! hregIsVirtual(modval));
+   vassert(! hregIsVirtual(num_bits));
+   vassert(! hregIsVirtual(clobber));
 
-   insn->tag  = S390_INSN_FLOGR;
+   insn->tag  = S390_INSN_CLZ;
    insn->size = size;
-   insn->variant.flogr.bitpos = bitpos;   /* bit position */
-   insn->variant.flogr.modval = modval;   /* modified input value */
-   insn->variant.flogr.src = src;
+   insn->variant.clz.num_bits = num_bits;
+   insn->variant.clz.clobber  = clobber;
+   insn->variant.clz.src = src;
 
    return insn;
 }
@@ -4329,9 +4329,9 @@ s390_insn_as_string(const s390_insn *insn)
                    &insn->variant.divs.op2);
       break;
 
-   case S390_INSN_FLOGR:
-      s390_sprintf(buf, "%M %R,%O", "v-flogr", insn->variant.flogr.bitpos,
-                   &insn->variant.flogr.src);
+   case S390_INSN_CLZ:
+      s390_sprintf(buf, "%M %R,%O", "v-clz", insn->variant.clz.num_bits,
+                   &insn->variant.clz.src);
       break;
 
    case S390_INSN_UNOP:
@@ -6003,25 +6003,25 @@ s390_insn_divs_emit(UChar *buf, const s390_insn *insn)
 
 
 static UChar *
-s390_insn_flogr_emit(UChar *buf, const s390_insn *insn)
+s390_insn_clz_emit(UChar *buf, const s390_insn *insn)
 {
    s390_opnd_RMI src;
-   UChar r1, r1p1;
+   UChar r1, r1p1, r2, *p;
 
-   r1   = hregNumber(insn->variant.flogr.bitpos);
-   r1p1 = hregNumber(insn->variant.flogr.modval);
+   r1   = hregNumber(insn->variant.clz.num_bits);
+   r1p1 = hregNumber(insn->variant.clz.clobber);
 
    vassert((r1 & 0x1) == 0);
    vassert(r1p1 == r1 + 1);
 
-   src = insn->variant.flogr.src;
+   p = buf;
+   src = insn->variant.clz.src;
 
+   /* Get operand and move it to r2 */
    switch (src.tag) {
-   case S390_OPND_REG: {
-      UInt r2 = hregNumber(src.variant.reg);
-
-      return s390_emit_FLOGR(buf, r1, r2);
-   }
+   case S390_OPND_REG:
+      r2 = hregNumber(src.variant.reg);
+      break;
 
    case S390_OPND_AMODE: {
       const s390_amode *am = src.variant.am;
@@ -6029,23 +6029,49 @@ s390_insn_flogr_emit(UChar *buf, const s390_insn *insn)
       UChar x = hregNumber(am->x);
       Int   d = am->d;
 
-      buf = s390_emit_LG(buf, R0, x, b, DISP20(d));
-      return s390_emit_FLOGR(buf, r1, R0);
+      p  = s390_emit_LG(p, R0, x, b, DISP20(d));
+      r2 = R0;
+      break;
    }
 
    case S390_OPND_IMMEDIATE: {
       ULong value = src.variant.imm;
 
-      buf = s390_emit_load_64imm(buf, R0, value);
-      return s390_emit_FLOGR(buf, r1, R0);
+      p  = s390_emit_load_64imm(p, R0, value);
+      r2 = R0;
+      break;
    }
 
    default:
       goto fail;
    }
 
+   /* Use FLOGR if you can */
+   if (s390_host_has_eimm) {
+      return s390_emit_FLOGR(p, r1, r2);
+   }
+
+   /*
+      r0 = r2;
+      r1 = 64;
+      while (r0 != 0) {
+        r1 -= 1;
+        r0 >>= 1;
+      }
+   */
+   p = s390_emit_LTGR(p, R0, r2);
+   p = s390_emit_LLILL(p, r1,  64);
+
+   p = s390_emit_BRC(p, S390_CC_E, (4 + 4 + 6 + 4 + 4)/ 2);  /* 4 bytes */
+   p = s390_emit_AGHI(p, r1, (UShort)-1);         /* r1  -= 1;  4 bytes */
+   p = s390_emit_SRLG(p, R0, R0, R0, DISP20(1));  /* r0 >>= 1;  6 bytes */
+   p = s390_emit_LTGR(p, R0, R0);                 /* set cc     4 bytes */
+   p = s390_emit_BRC(p, S390_CC_NE,               /*            4 bytes */
+                     (UShort)(-(4 + 6 + 4) / 2));
+   return p;
+
  fail:
-   vpanic("s390_insn_flogr_emit");
+   vpanic("s390_insn_clz_emit");
 }
 
 
@@ -6721,8 +6747,8 @@ emit_S390Instr(UChar *buf, Int nbuf, struct s390_insn *insn,
       end = s390_insn_divs_emit(buf, insn);
       break;
 
-   case S390_INSN_FLOGR:
-      end = s390_insn_flogr_emit(buf, insn);
+   case S390_INSN_CLZ:
+      end = s390_insn_clz_emit(buf, insn);
       break;
 
    case S390_INSN_UNOP:
index 9b77c8dcca1174b90df89c42c1d529c8716d7d05..9781258c27a02ae343fd51782d817dba7362a89c 100644 (file)
@@ -131,7 +131,7 @@ typedef enum {
    S390_INSN_MUL,    /* n-bit operands; 2n-bit result */
    S390_INSN_DIV,    /* 2n-bit dividend; n-bit divisor; n-bit quot/rem */
    S390_INSN_DIVS,   /* n-bit dividend; n-bit divisor; n-bit quot/rem */
-   S390_INSN_FLOGR,
+   S390_INSN_CLZ,    /* count left-most zeroes */
    S390_INSN_UNOP,
    S390_INSN_TEST,   /* test operand and set cc */
    S390_INSN_CC2BOOL,/* convert condition code to 0/1 */
@@ -308,10 +308,10 @@ typedef struct s390_insn {
          s390_opnd_RMI op2;
       } divs;
       struct {
-         HReg          bitpos; /* position of leftmost '1' bit  r10 */
-         HReg          modval; /* modified input value          r11 */
+         HReg          num_bits; /* number of leftmost '0' bits  r10 */
+         HReg          clobber;  /* unspecified                  r11 */
          s390_opnd_RMI src;
-      } flogr;
+      } clz;
       struct {
          s390_unop_t   tag;
          HReg          dst;
@@ -418,8 +418,8 @@ s390_insn *s390_insn_mul(UChar size, HReg dst_hi, HReg dst_lo,
 s390_insn *s390_insn_div(UChar size, HReg op1_hi, HReg op1_lo,
                          s390_opnd_RMI op2, Bool signed_divide);
 s390_insn *s390_insn_divs(UChar size, HReg rem, HReg op1, s390_opnd_RMI op2);
-s390_insn *s390_insn_flogr(UChar size, HReg bitpos, HReg modval,
-                           s390_opnd_RMI op);
+s390_insn *s390_insn_clz(UChar size, HReg num_bits, HReg clobber,
+                         s390_opnd_RMI op);
 s390_insn *s390_insn_cas(UChar size, HReg op1, s390_amode *op2, HReg op3,
                          HReg old);
 s390_insn *s390_insn_unop(UChar size, s390_unop_t tag, HReg dst,
index 095221f15df653d2ee8461310a81478dcca2f73d..80e5759a54283077848a1db877b6dfaa0bfe5cad 100644 (file)
@@ -1182,17 +1182,14 @@ s390_isel_int_expr_wrk(ISelEnv *env, IRExpr *expr)
       case Iop_Clz64: {
          HReg r10, r11;
 
-         /* We use non-virtual registers r10 and r11 as pair for the two
-            output values */
+         /* This will be implemented using FLOGR, if possible. So we need to
+            set aside a pair of non-virtual registers. The result (number of
+            left-most zero bits) will be in r10. The value in r11 is unspecified
+            and must not be used. */
          r10  = make_gpr(env, 10);
          r11  = make_gpr(env, 11);
 
-         /* flogr */
-         addInstr(env, s390_insn_flogr(8, r10, r11, opnd));
-
-         /* The result is in registers r10 (bit position) and r11 (modified
-            input value). The value in r11 is not needed and will be
-            discarded. */
+         addInstr(env, s390_insn_clz(8, r10, r11, opnd));
          addInstr(env, s390_insn_move(8, dst, r10));
          return dst;
       }