1 /* 2 * Copyright (c) 2002, 2025, 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 "asm/macroAssembler.inline.hpp" 27 #include "runtime/os.hpp" 28 #include "runtime/stubRoutines.hpp" 29 #include "runtime/vm_version.hpp" 30 #include "utilities/byteswap.hpp" 31 32 // Implementation of the platform-specific part of StubRoutines - for 33 // a description of how to extend it, see the stubRoutines.hpp file. 34 35 36 #define __ masm-> 37 38 // CRC constant compute functions 39 static juint fold_byte(juint w, juint reverse_poly) { 40 for (int i = 0; i < 8; i++) { 41 int poly_if_odd = (-(w & 1)) & reverse_poly; 42 w = (w >> 1) ^ poly_if_odd; 43 } 44 return w; 45 } 46 47 static juint fold_word(juint w, juint reverse_poly) { 48 for (int i = 0; i < 32; i++) { 49 int poly_if_odd = (-(w & 1)) & reverse_poly; 50 w = (w >> 1) ^ poly_if_odd; 51 } 52 return w; 53 } 54 55 static julong numberOfLeadingZeros(julong p) { 56 julong l = 1ull << 63; 57 for (int i = 0; i < 64; ++i) { 58 if (p & l) return i; 59 l >>= 1; 60 } 61 return 64; 62 } 63 64 static julong compute_inverse_poly(julong long_poly) { 65 // 2^64 / p 66 julong mod = 0, div = 0; 67 int d = numberOfLeadingZeros(long_poly); 68 int s = d + 1; 69 do { 70 mod ^= (long_poly << s); 71 div |= (1L << s); 72 s = d - numberOfLeadingZeros(mod); 73 } while (s >= 0); 74 return div; 75 } 76 77 static address _crc_table_addr = nullptr; 78 static address _crc32c_table_addr = nullptr; 79 80 address StubRoutines::crc_table_addr() { 81 if (_crc_table_addr == nullptr) { 82 _crc_table_addr = StubRoutines::ppc::generate_crc_constants(REVERSE_CRC32_POLY); 83 } 84 return _crc_table_addr; 85 } 86 address StubRoutines::crc32c_table_addr() { 87 if (_crc32c_table_addr == nullptr) { 88 _crc32c_table_addr = StubRoutines::ppc::generate_crc_constants(REVERSE_CRC32C_POLY); 89 } 90 return _crc32c_table_addr; 91 } 92 93 // Constants to fold n words as needed by macroAssembler. 94 address StubRoutines::ppc::generate_crc_constants(juint reverse_poly) { 95 // Layout of constant table: 96 // >= Power8: 1 table for single byte folding + constants for fast vector implementation 97 const int vector_size = 16 * (CRC32_UNROLL_FACTOR2 + CRC32_UNROLL_FACTOR / CRC32_UNROLL_FACTOR2); 98 99 const int size = CRC32_TABLE_SIZE + vector_size; 100 const address consts = (address)os::malloc(size, mtInternal); 101 if (consts == nullptr) { 102 vm_exit_out_of_memory(size, OOM_MALLOC_ERROR, "CRC constants: no enough space"); 103 } 104 juint* ptr = (juint*)consts; 105 106 // Simple table used for single byte folding 107 for (int i = 0; i < 256; ++i) { 108 ptr[i] = fold_byte(i, reverse_poly); 109 } 110 111 // >= Power8: vector constants 112 juint* ptr1 = (juint*)(consts + CRC32_TABLE_SIZE); 113 guarantee(((intptr_t)ptr1 & 0xF) == 0, "16-byte alignment needed"); 114 115 // Generate constants for outer loop 116 juint v0, v1, v2, v3 = 1; 117 for (int i = 0; i < CRC32_UNROLL_FACTOR2 - 1; ++i) { 118 v0 = fold_word(v3, reverse_poly); 119 v1 = fold_word(v0, reverse_poly); 120 v2 = fold_word(v1, reverse_poly); 121 v3 = fold_word(v2, reverse_poly); 122 #ifdef VM_LITTLE_ENDIAN 123 ptr1[4*i ] = v3; 124 ptr1[4*i+1] = v2; 125 ptr1[4*i+2] = v3; 126 ptr1[4*i+3] = v2; 127 #else 128 ptr1[4*i ] = v2; 129 ptr1[4*i+1] = v3; 130 ptr1[4*i+2] = v2; 131 ptr1[4*i+3] = v3; 132 #endif 133 } 134 135 // Generate constants for inner loop 136 juint* ptr2 = ptr1 + 4 * (CRC32_UNROLL_FACTOR2 - 1); 137 v3 = 1; // Restart from scratch. 138 for (int i = 0; i < CRC32_UNROLL_FACTOR; ++i) { 139 v0 = fold_word(v3, reverse_poly); 140 v1 = fold_word(v0, reverse_poly); 141 v2 = fold_word(v1, reverse_poly); 142 v3 = fold_word(v2, reverse_poly); 143 if (i % CRC32_UNROLL_FACTOR2 == 0) { 144 int idx = CRC32_UNROLL_FACTOR / CRC32_UNROLL_FACTOR2 - 1 - i / CRC32_UNROLL_FACTOR2; 145 for (int j = 0; j < 4; ++j) { 146 #ifdef VM_LITTLE_ENDIAN 147 ptr2[4*idx ] = v3; 148 ptr2[4*idx+1] = v2; 149 ptr2[4*idx+2] = v1; 150 ptr2[4*idx+3] = v0; 151 #else 152 ptr2[4*idx ] = v0; 153 ptr2[4*idx+1] = v1; 154 ptr2[4*idx+2] = v2; 155 ptr2[4*idx+3] = v3; 156 #endif 157 } 158 } 159 } 160 161 // Constants to reduce 64 to 32 bit as needed by macroAssembler. 162 juint* ptr3 = ptr2 + 4 * (CRC32_UNROLL_FACTOR / CRC32_UNROLL_FACTOR2); 163 julong* c = (julong*)ptr3; 164 julong long_poly = (((julong)reverse_poly) << 1) | 1; 165 julong inverse_long_poly = compute_inverse_poly(long_poly); 166 #ifdef VM_LITTLE_ENDIAN 167 c[0] = inverse_long_poly; 168 c[1] = long_poly; 169 #else 170 c[0] = long_poly; 171 c[1] = inverse_long_poly; 172 #endif 173 174 #ifdef ASSERT 175 if (reverse_poly == REVERSE_CRC32_POLY) { 176 assert(INVERSE_REVERSE_CRC32_POLY == inverse_long_poly, "sanity"); 177 } else if (reverse_poly == REVERSE_CRC32C_POLY) { 178 assert(INVERSE_REVERSE_CRC32C_POLY == inverse_long_poly, "sanity"); 179 } 180 #endif 181 182 //printf("inv poly: 0x%016llx\n", (long long unsigned int)inverse_long_poly); 183 184 return consts; 185 }