1 /*
   2  * Copyright (c) 2002, 2019, Oracle and/or its affiliates. All rights reserved.
   3  * Copyright (c) 2012, 2019, SAP SE. All rights reserved.
   4  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   5  *
   6  * This code is free software; you can redistribute it and/or modify it
   7  * under the terms of the GNU General Public License version 2 only, as
   8  * published by the Free Software Foundation.
   9  *
  10  * This code is distributed in the hope that it will be useful, but WITHOUT
  11  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  12  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  13  * version 2 for more details (a copy is included in the LICENSE file that
  14  * accompanied this code).
  15  *
  16  * You should have received a copy of the GNU General Public License version
  17  * 2 along with this work; if not, write to the Free Software Foundation,
  18  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  19  *
  20  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  21  * or visit www.oracle.com if you need additional information or have any
  22  * questions.
  23  *
  24  */
  25 
  26 #include "precompiled.hpp"
  27 #include "asm/macroAssembler.inline.hpp"
  28 #include "runtime/stubRoutines.hpp"
  29 #include "runtime/vm_version.hpp"
  30 
  31 // Implementation of the platform-specific part of StubRoutines - for
  32 // a description of how to extend it, see the stubRoutines.hpp file.
  33 
  34 
  35 #define __ masm->
  36 
  37 // CRC constant compute functions
  38 static juint fold_byte(juint w, juint reverse_poly) {
  39   for (int i = 0; i < 8; i++) {
  40     int poly_if_odd = (-(w & 1)) & reverse_poly;
  41     w = (w >> 1) ^ poly_if_odd;
  42   }
  43   return w;
  44 }
  45 
  46 static juint fold_word(juint w, juint reverse_poly) {
  47   for (int i = 0; i < 32; i++) {
  48     int poly_if_odd = (-(w & 1)) & reverse_poly;
  49     w = (w >> 1) ^ poly_if_odd;
  50   }
  51   return w;
  52 }
  53 
  54 static julong numberOfLeadingZeros(julong p) {
  55   julong l = 1ull << 63;
  56   for (int i = 0; i < 64; ++i) {
  57     if (p & l) return i;
  58     l >>= 1;
  59   }
  60   return 64;
  61 }
  62 
  63 static julong compute_inverse_poly(julong long_poly) {
  64   // 2^64 / p
  65   julong mod = 0, div = 0;
  66   int d = numberOfLeadingZeros(long_poly);
  67   int s = d + 1;
  68   do {
  69     mod ^= (long_poly << s);
  70     div |= (1L << s);
  71     s = d - numberOfLeadingZeros(mod);
  72   } while (s >= 0);
  73   return div;
  74 }
  75 
  76 #ifndef VM_LITTLE_ENDIAN
  77 static void reverse_bytes(juint &w) {
  78   w = ((w >> 24) & 0xFF) | (((w >> 16) & 0xFF) << 8) | (((w >> 8) & 0xFF) << 16) | ((w & 0xFF) << 24);
  79 }
  80 #endif
  81 
  82 // Constants to fold n words as needed by macroAssembler.
  83 address StubRoutines::generate_crc_constants(juint reverse_poly) {
  84   // Layout of constant table:
  85   // <= Power7 Little Endian: 4 tables for byte folding
  86   // <= Power7 Big Endian: 1 table for single byte folding + 4 tables for multi-byte folding
  87   // >= Power8: 1 table for single byte folding + constants for fast vector implementation
  88   const bool use_vector = VM_Version::has_vpmsumb();
  89   const int vector_size = 16 * (CRC32_UNROLL_FACTOR2 + CRC32_UNROLL_FACTOR / CRC32_UNROLL_FACTOR2);
  90 
  91   const int size = use_vector ? CRC32_TABLE_SIZE + vector_size : (4 BIG_ENDIAN_ONLY(+1)) * CRC32_TABLE_SIZE;
  92   const address consts = (address)malloc(size);
  93   if (consts == NULL) {
  94     vm_exit_out_of_memory(size, OOM_MALLOC_ERROR, "CRC constants: no enough space");
  95   }
  96   juint* ptr = (juint*)consts;
  97 
  98   // Simple table used for single byte folding
  99   LITTLE_ENDIAN_ONLY(if (use_vector)) {
 100     for (int i = 0; i < 256; ++i) {
 101       ptr[i] = fold_byte(i, reverse_poly);
 102     }
 103   }
 104 
 105   if (!use_vector) {
 106     BIG_ENDIAN_ONLY(ptr = (juint*)(consts + CRC32_TABLE_SIZE);)
 107     // <= Power7: 4 tables
 108     for (int i = 0; i < 256; ++i) {
 109       juint a = fold_byte(i, reverse_poly),
 110             b = fold_byte(a, reverse_poly),
 111             c = fold_byte(b, reverse_poly),
 112             d = fold_byte(c, reverse_poly);
 113 #ifndef VM_LITTLE_ENDIAN
 114       reverse_bytes(a);
 115       reverse_bytes(b);
 116       reverse_bytes(c);
 117       reverse_bytes(d);
 118 #endif
 119       ptr[i         ] = a;
 120       ptr[i +    256] = b;
 121       ptr[i + 2* 256] = c;
 122       ptr[i + 3* 256] = d;
 123     }
 124 #if 0
 125     for (int i = 0; i < 4; ++i) {
 126       tty->print_cr("table %d:", i);
 127       for (int j = 0; j < 32; ++j) {
 128         for (int k = 0; k < 8; ++k) {
 129           tty->print("%08x ", ptr[i*256 + j*8 + k]);
 130         }
 131         tty->cr();
 132       }
 133     }
 134 #endif
 135     return consts;
 136   }
 137 
 138   // >= Power8: vector constants
 139   juint* ptr1 = (juint*)(consts + CRC32_TABLE_SIZE);
 140   guarantee(((intptr_t)ptr1 & 0xF) == 0, "16-byte alignment needed");
 141 
 142   // Generate constants for outer loop
 143   juint v0, v1, v2, v3 = 1;
 144   for (int i = 0; i < CRC32_UNROLL_FACTOR2 - 1; ++i) {
 145     v0 = fold_word(v3, reverse_poly);
 146     v1 = fold_word(v0, reverse_poly);
 147     v2 = fold_word(v1, reverse_poly);
 148     v3 = fold_word(v2, reverse_poly);
 149 #ifdef VM_LITTLE_ENDIAN
 150     ptr1[4*i  ] = v3;
 151     ptr1[4*i+1] = v2;
 152     ptr1[4*i+2] = v3;
 153     ptr1[4*i+3] = v2;
 154 #else
 155     ptr1[4*i  ] = v2;
 156     ptr1[4*i+1] = v3;
 157     ptr1[4*i+2] = v2;
 158     ptr1[4*i+3] = v3;
 159 #endif
 160   }
 161 
 162   // Generate constants for inner loop
 163   juint* ptr2 = ptr1 + 4 * (CRC32_UNROLL_FACTOR2 - 1);
 164   v3 = 1; // Restart from scratch.
 165   for (int i = 0; i < CRC32_UNROLL_FACTOR; ++i) {
 166     v0 = fold_word(v3, reverse_poly);
 167     v1 = fold_word(v0, reverse_poly);
 168     v2 = fold_word(v1, reverse_poly);
 169     v3 = fold_word(v2, reverse_poly);
 170     if (i % CRC32_UNROLL_FACTOR2 == 0) {
 171       int idx = CRC32_UNROLL_FACTOR / CRC32_UNROLL_FACTOR2 - 1 - i / CRC32_UNROLL_FACTOR2;
 172       for (int j = 0; j < 4; ++j) {
 173 #ifdef VM_LITTLE_ENDIAN
 174         ptr2[4*idx  ] = v3;
 175         ptr2[4*idx+1] = v2;
 176         ptr2[4*idx+2] = v1;
 177         ptr2[4*idx+3] = v0;
 178 #else
 179         ptr2[4*idx  ] = v0;
 180         ptr2[4*idx+1] = v1;
 181         ptr2[4*idx+2] = v2;
 182         ptr2[4*idx+3] = v3;
 183 #endif
 184       }
 185     }
 186   }
 187 
 188   // Constants to reduce 64 to 32 bit as needed by macroAssembler.
 189   juint* ptr3 = ptr2 + 4 * (CRC32_UNROLL_FACTOR / CRC32_UNROLL_FACTOR2);
 190   julong* c = (julong*)ptr3;
 191   julong long_poly = (((julong)reverse_poly) << 1) | 1;
 192   julong inverse_long_poly = compute_inverse_poly(long_poly);
 193 #ifdef VM_LITTLE_ENDIAN
 194   c[0] = inverse_long_poly;
 195   c[1] = long_poly;
 196 #else
 197   c[0] = long_poly;
 198   c[1] = inverse_long_poly;
 199 #endif
 200 
 201 #ifdef ASSERT
 202   if (reverse_poly == REVERSE_CRC32_POLY) {
 203     assert(INVERSE_REVERSE_CRC32_POLY == inverse_long_poly, "sanity");
 204   } else if (reverse_poly == REVERSE_CRC32C_POLY) {
 205     assert(INVERSE_REVERSE_CRC32C_POLY == inverse_long_poly, "sanity");
 206   }
 207 #endif
 208 
 209   //printf("inv poly: 0x%016llx\n", (long long unsigned int)inverse_long_poly);
 210 
 211   return consts;
 212 }