Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mobile
Path: blob/master/src/hotspot/cpu/ppc/c2_MacroAssembler_ppc.cpp
40930 views
1
/*
2
* Copyright (c) 2020, 2021, Oracle and/or its affiliates. All rights reserved.
3
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4
*
5
* This code is free software; you can redistribute it and/or modify it
6
* under the terms of the GNU General Public License version 2 only, as
7
* published by the Free Software Foundation.
8
*
9
* This code is distributed in the hope that it will be useful, but WITHOUT
10
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12
* version 2 for more details (a copy is included in the LICENSE file that
13
* accompanied this code).
14
*
15
* You should have received a copy of the GNU General Public License version
16
* 2 along with this work; if not, write to the Free Software Foundation,
17
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18
*
19
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20
* or visit www.oracle.com if you need additional information or have any
21
* questions.
22
*
23
*/
24
25
#include "precompiled.hpp"
26
#include "asm/assembler.hpp"
27
#include "asm/assembler.inline.hpp"
28
#include "opto/c2_MacroAssembler.hpp"
29
#include "opto/intrinsicnode.hpp"
30
#include "runtime/vm_version.hpp"
31
32
#ifdef PRODUCT
33
#define BLOCK_COMMENT(str) // nothing
34
#else
35
#define BLOCK_COMMENT(str) block_comment(str)
36
#endif
37
#define BIND(label) bind(label); BLOCK_COMMENT(#label ":")
38
39
// Intrinsics for CompactStrings
40
41
// Compress char[] to byte[] by compressing 16 bytes at once.
42
void C2_MacroAssembler::string_compress_16(Register src, Register dst, Register cnt,
43
Register tmp1, Register tmp2, Register tmp3, Register tmp4, Register tmp5,
44
Label& Lfailure) {
45
46
const Register tmp0 = R0;
47
assert_different_registers(src, dst, cnt, tmp0, tmp1, tmp2, tmp3, tmp4, tmp5);
48
Label Lloop, Lslow;
49
50
// Check if cnt >= 8 (= 16 bytes)
51
lis(tmp1, 0xFF); // tmp1 = 0x00FF00FF00FF00FF
52
srwi_(tmp2, cnt, 3);
53
beq(CCR0, Lslow);
54
ori(tmp1, tmp1, 0xFF);
55
rldimi(tmp1, tmp1, 32, 0);
56
mtctr(tmp2);
57
58
// 2x unrolled loop
59
bind(Lloop);
60
ld(tmp2, 0, src); // _0_1_2_3 (Big Endian)
61
ld(tmp4, 8, src); // _4_5_6_7
62
63
orr(tmp0, tmp2, tmp4);
64
rldicl(tmp3, tmp2, 6*8, 64-24); // _____1_2
65
rldimi(tmp2, tmp2, 2*8, 2*8); // _0_2_3_3
66
rldicl(tmp5, tmp4, 6*8, 64-24); // _____5_6
67
rldimi(tmp4, tmp4, 2*8, 2*8); // _4_6_7_7
68
69
andc_(tmp0, tmp0, tmp1);
70
bne(CCR0, Lfailure); // Not latin1.
71
addi(src, src, 16);
72
73
rlwimi(tmp3, tmp2, 0*8, 24, 31);// _____1_3
74
srdi(tmp2, tmp2, 3*8); // ____0_2_
75
rlwimi(tmp5, tmp4, 0*8, 24, 31);// _____5_7
76
srdi(tmp4, tmp4, 3*8); // ____4_6_
77
78
orr(tmp2, tmp2, tmp3); // ____0123
79
orr(tmp4, tmp4, tmp5); // ____4567
80
81
stw(tmp2, 0, dst);
82
stw(tmp4, 4, dst);
83
addi(dst, dst, 8);
84
bdnz(Lloop);
85
86
bind(Lslow); // Fallback to slow version
87
}
88
89
// Compress char[] to byte[]. cnt must be positive int.
90
void C2_MacroAssembler::string_compress(Register src, Register dst, Register cnt, Register tmp, Label& Lfailure) {
91
Label Lloop;
92
mtctr(cnt);
93
94
bind(Lloop);
95
lhz(tmp, 0, src);
96
cmplwi(CCR0, tmp, 0xff);
97
bgt(CCR0, Lfailure); // Not latin1.
98
addi(src, src, 2);
99
stb(tmp, 0, dst);
100
addi(dst, dst, 1);
101
bdnz(Lloop);
102
}
103
104
// Inflate byte[] to char[] by inflating 16 bytes at once.
105
void C2_MacroAssembler::string_inflate_16(Register src, Register dst, Register cnt,
106
Register tmp1, Register tmp2, Register tmp3, Register tmp4, Register tmp5) {
107
const Register tmp0 = R0;
108
assert_different_registers(src, dst, cnt, tmp0, tmp1, tmp2, tmp3, tmp4, tmp5);
109
Label Lloop, Lslow;
110
111
// Check if cnt >= 8
112
srwi_(tmp2, cnt, 3);
113
beq(CCR0, Lslow);
114
lis(tmp1, 0xFF); // tmp1 = 0x00FF00FF
115
ori(tmp1, tmp1, 0xFF);
116
mtctr(tmp2);
117
118
// 2x unrolled loop
119
bind(Lloop);
120
lwz(tmp2, 0, src); // ____0123 (Big Endian)
121
lwz(tmp4, 4, src); // ____4567
122
addi(src, src, 8);
123
124
rldicl(tmp3, tmp2, 7*8, 64-8); // _______2
125
rlwimi(tmp2, tmp2, 3*8, 16, 23);// ____0113
126
rldicl(tmp5, tmp4, 7*8, 64-8); // _______6
127
rlwimi(tmp4, tmp4, 3*8, 16, 23);// ____4557
128
129
andc(tmp0, tmp2, tmp1); // ____0_1_
130
rlwimi(tmp2, tmp3, 2*8, 0, 23); // _____2_3
131
andc(tmp3, tmp4, tmp1); // ____4_5_
132
rlwimi(tmp4, tmp5, 2*8, 0, 23); // _____6_7
133
134
rldimi(tmp2, tmp0, 3*8, 0*8); // _0_1_2_3
135
rldimi(tmp4, tmp3, 3*8, 0*8); // _4_5_6_7
136
137
std(tmp2, 0, dst);
138
std(tmp4, 8, dst);
139
addi(dst, dst, 16);
140
bdnz(Lloop);
141
142
bind(Lslow); // Fallback to slow version
143
}
144
145
// Inflate byte[] to char[]. cnt must be positive int.
146
void C2_MacroAssembler::string_inflate(Register src, Register dst, Register cnt, Register tmp) {
147
Label Lloop;
148
mtctr(cnt);
149
150
bind(Lloop);
151
lbz(tmp, 0, src);
152
addi(src, src, 1);
153
sth(tmp, 0, dst);
154
addi(dst, dst, 2);
155
bdnz(Lloop);
156
}
157
158
void C2_MacroAssembler::string_compare(Register str1, Register str2,
159
Register cnt1, Register cnt2,
160
Register tmp1, Register result, int ae) {
161
const Register tmp0 = R0,
162
diff = tmp1;
163
164
assert_different_registers(str1, str2, cnt1, cnt2, tmp0, tmp1, result);
165
Label Ldone, Lslow, Lloop, Lreturn_diff;
166
167
// Note: Making use of the fact that compareTo(a, b) == -compareTo(b, a)
168
// we interchange str1 and str2 in the UL case and negate the result.
169
// Like this, str1 is always latin1 encoded, except for the UU case.
170
// In addition, we need 0 (or sign which is 0) extend.
171
172
if (ae == StrIntrinsicNode::UU) {
173
srwi(cnt1, cnt1, 1);
174
} else {
175
clrldi(cnt1, cnt1, 32);
176
}
177
178
if (ae != StrIntrinsicNode::LL) {
179
srwi(cnt2, cnt2, 1);
180
} else {
181
clrldi(cnt2, cnt2, 32);
182
}
183
184
// See if the lengths are different, and calculate min in cnt1.
185
// Save diff in case we need it for a tie-breaker.
186
subf_(diff, cnt2, cnt1); // diff = cnt1 - cnt2
187
// if (diff > 0) { cnt1 = cnt2; }
188
if (VM_Version::has_isel()) {
189
isel(cnt1, CCR0, Assembler::greater, /*invert*/ false, cnt2);
190
} else {
191
Label Lskip;
192
blt(CCR0, Lskip);
193
mr(cnt1, cnt2);
194
bind(Lskip);
195
}
196
197
// Rename registers
198
Register chr1 = result;
199
Register chr2 = tmp0;
200
201
// Compare multiple characters in fast loop (only implemented for same encoding).
202
int stride1 = 8, stride2 = 8;
203
if (ae == StrIntrinsicNode::LL || ae == StrIntrinsicNode::UU) {
204
int log2_chars_per_iter = (ae == StrIntrinsicNode::LL) ? 3 : 2;
205
Label Lfastloop, Lskipfast;
206
207
srwi_(tmp0, cnt1, log2_chars_per_iter);
208
beq(CCR0, Lskipfast);
209
rldicl(cnt2, cnt1, 0, 64 - log2_chars_per_iter); // Remaining characters.
210
li(cnt1, 1 << log2_chars_per_iter); // Initialize for failure case: Rescan characters from current iteration.
211
mtctr(tmp0);
212
213
bind(Lfastloop);
214
ld(chr1, 0, str1);
215
ld(chr2, 0, str2);
216
cmpd(CCR0, chr1, chr2);
217
bne(CCR0, Lslow);
218
addi(str1, str1, stride1);
219
addi(str2, str2, stride2);
220
bdnz(Lfastloop);
221
mr(cnt1, cnt2); // Remaining characters.
222
bind(Lskipfast);
223
}
224
225
// Loop which searches the first difference character by character.
226
cmpwi(CCR0, cnt1, 0);
227
beq(CCR0, Lreturn_diff);
228
bind(Lslow);
229
mtctr(cnt1);
230
231
switch (ae) {
232
case StrIntrinsicNode::LL: stride1 = 1; stride2 = 1; break;
233
case StrIntrinsicNode::UL: // fallthru (see comment above)
234
case StrIntrinsicNode::LU: stride1 = 1; stride2 = 2; break;
235
case StrIntrinsicNode::UU: stride1 = 2; stride2 = 2; break;
236
default: ShouldNotReachHere(); break;
237
}
238
239
bind(Lloop);
240
if (stride1 == 1) { lbz(chr1, 0, str1); } else { lhz(chr1, 0, str1); }
241
if (stride2 == 1) { lbz(chr2, 0, str2); } else { lhz(chr2, 0, str2); }
242
subf_(result, chr2, chr1); // result = chr1 - chr2
243
bne(CCR0, Ldone);
244
addi(str1, str1, stride1);
245
addi(str2, str2, stride2);
246
bdnz(Lloop);
247
248
// If strings are equal up to min length, return the length difference.
249
bind(Lreturn_diff);
250
mr(result, diff);
251
252
// Otherwise, return the difference between the first mismatched chars.
253
bind(Ldone);
254
if (ae == StrIntrinsicNode::UL) {
255
neg(result, result); // Negate result (see note above).
256
}
257
}
258
259
void C2_MacroAssembler::array_equals(bool is_array_equ, Register ary1, Register ary2,
260
Register limit, Register tmp1, Register result, bool is_byte) {
261
const Register tmp0 = R0;
262
assert_different_registers(ary1, ary2, limit, tmp0, tmp1, result);
263
Label Ldone, Lskiploop, Lloop, Lfastloop, Lskipfast;
264
bool limit_needs_shift = false;
265
266
if (is_array_equ) {
267
const int length_offset = arrayOopDesc::length_offset_in_bytes();
268
const int base_offset = arrayOopDesc::base_offset_in_bytes(is_byte ? T_BYTE : T_CHAR);
269
270
// Return true if the same array.
271
cmpd(CCR0, ary1, ary2);
272
beq(CCR0, Lskiploop);
273
274
// Return false if one of them is NULL.
275
cmpdi(CCR0, ary1, 0);
276
cmpdi(CCR1, ary2, 0);
277
li(result, 0);
278
cror(CCR0, Assembler::equal, CCR1, Assembler::equal);
279
beq(CCR0, Ldone);
280
281
// Load the lengths of arrays.
282
lwz(limit, length_offset, ary1);
283
lwz(tmp0, length_offset, ary2);
284
285
// Return false if the two arrays are not equal length.
286
cmpw(CCR0, limit, tmp0);
287
bne(CCR0, Ldone);
288
289
// Load array addresses.
290
addi(ary1, ary1, base_offset);
291
addi(ary2, ary2, base_offset);
292
} else {
293
limit_needs_shift = !is_byte;
294
li(result, 0); // Assume not equal.
295
}
296
297
// Rename registers
298
Register chr1 = tmp0;
299
Register chr2 = tmp1;
300
301
// Compare 8 bytes per iteration in fast loop.
302
const int log2_chars_per_iter = is_byte ? 3 : 2;
303
304
srwi_(tmp0, limit, log2_chars_per_iter + (limit_needs_shift ? 1 : 0));
305
beq(CCR0, Lskipfast);
306
mtctr(tmp0);
307
308
bind(Lfastloop);
309
ld(chr1, 0, ary1);
310
ld(chr2, 0, ary2);
311
addi(ary1, ary1, 8);
312
addi(ary2, ary2, 8);
313
cmpd(CCR0, chr1, chr2);
314
bne(CCR0, Ldone);
315
bdnz(Lfastloop);
316
317
bind(Lskipfast);
318
rldicl_(limit, limit, limit_needs_shift ? 64 - 1 : 0, 64 - log2_chars_per_iter); // Remaining characters.
319
beq(CCR0, Lskiploop);
320
mtctr(limit);
321
322
// Character by character.
323
bind(Lloop);
324
if (is_byte) {
325
lbz(chr1, 0, ary1);
326
lbz(chr2, 0, ary2);
327
addi(ary1, ary1, 1);
328
addi(ary2, ary2, 1);
329
} else {
330
lhz(chr1, 0, ary1);
331
lhz(chr2, 0, ary2);
332
addi(ary1, ary1, 2);
333
addi(ary2, ary2, 2);
334
}
335
cmpw(CCR0, chr1, chr2);
336
bne(CCR0, Ldone);
337
bdnz(Lloop);
338
339
bind(Lskiploop);
340
li(result, 1); // All characters are equal.
341
bind(Ldone);
342
}
343
344
void C2_MacroAssembler::string_indexof(Register result, Register haystack, Register haycnt,
345
Register needle, ciTypeArray* needle_values, Register needlecnt, int needlecntval,
346
Register tmp1, Register tmp2, Register tmp3, Register tmp4, int ae) {
347
348
// Ensure 0<needlecnt<=haycnt in ideal graph as prerequisite!
349
Label L_TooShort, L_Found, L_NotFound, L_End;
350
Register last_addr = haycnt, // Kill haycnt at the beginning.
351
addr = tmp1,
352
n_start = tmp2,
353
ch1 = tmp3,
354
ch2 = R0;
355
356
assert(ae != StrIntrinsicNode::LU, "Invalid encoding");
357
const int h_csize = (ae == StrIntrinsicNode::LL) ? 1 : 2;
358
const int n_csize = (ae == StrIntrinsicNode::UU) ? 2 : 1;
359
360
// **************************************************************************************************
361
// Prepare for main loop: optimized for needle count >=2, bail out otherwise.
362
// **************************************************************************************************
363
364
// Compute last haystack addr to use if no match gets found.
365
clrldi(haycnt, haycnt, 32); // Ensure positive int is valid as 64 bit value.
366
addi(addr, haystack, -h_csize); // Accesses use pre-increment.
367
if (needlecntval == 0) { // variable needlecnt
368
cmpwi(CCR6, needlecnt, 2);
369
clrldi(needlecnt, needlecnt, 32); // Ensure positive int is valid as 64 bit value.
370
blt(CCR6, L_TooShort); // Variable needlecnt: handle short needle separately.
371
}
372
373
if (n_csize == 2) { lwz(n_start, 0, needle); } else { lhz(n_start, 0, needle); } // Load first 2 characters of needle.
374
375
if (needlecntval == 0) { // variable needlecnt
376
subf(ch1, needlecnt, haycnt); // Last character index to compare is haycnt-needlecnt.
377
addi(needlecnt, needlecnt, -2); // Rest of needle.
378
} else { // constant needlecnt
379
guarantee(needlecntval != 1, "IndexOf with single-character needle must be handled separately");
380
assert((needlecntval & 0x7fff) == needlecntval, "wrong immediate");
381
addi(ch1, haycnt, -needlecntval); // Last character index to compare is haycnt-needlecnt.
382
if (needlecntval > 3) { li(needlecnt, needlecntval - 2); } // Rest of needle.
383
}
384
385
if (h_csize == 2) { slwi(ch1, ch1, 1); } // Scale to number of bytes.
386
387
if (ae ==StrIntrinsicNode::UL) {
388
srwi(tmp4, n_start, 1*8); // ___0
389
rlwimi(n_start, tmp4, 2*8, 0, 23); // _0_1
390
}
391
392
add(last_addr, haystack, ch1); // Point to last address to compare (haystack+2*(haycnt-needlecnt)).
393
394
// Main Loop (now we have at least 2 characters).
395
Label L_OuterLoop, L_InnerLoop, L_FinalCheck, L_Comp1, L_Comp2;
396
bind(L_OuterLoop); // Search for 1st 2 characters.
397
Register addr_diff = tmp4;
398
subf(addr_diff, addr, last_addr); // Difference between already checked address and last address to check.
399
addi(addr, addr, h_csize); // This is the new address we want to use for comparing.
400
srdi_(ch2, addr_diff, h_csize);
401
beq(CCR0, L_FinalCheck); // 2 characters left?
402
mtctr(ch2); // num of characters / 2
403
bind(L_InnerLoop); // Main work horse (2x unrolled search loop)
404
if (h_csize == 2) { // Load 2 characters of haystack (ignore alignment).
405
lwz(ch1, 0, addr);
406
lwz(ch2, 2, addr);
407
} else {
408
lhz(ch1, 0, addr);
409
lhz(ch2, 1, addr);
410
}
411
cmpw(CCR0, ch1, n_start); // Compare 2 characters (1 would be sufficient but try to reduce branches to CompLoop).
412
cmpw(CCR1, ch2, n_start);
413
beq(CCR0, L_Comp1); // Did we find the needle start?
414
beq(CCR1, L_Comp2);
415
addi(addr, addr, 2 * h_csize);
416
bdnz(L_InnerLoop);
417
bind(L_FinalCheck);
418
andi_(addr_diff, addr_diff, h_csize); // Remaining characters not covered by InnerLoop: (num of characters) & 1.
419
beq(CCR0, L_NotFound);
420
if (h_csize == 2) { lwz(ch1, 0, addr); } else { lhz(ch1, 0, addr); } // One position left at which we have to compare.
421
cmpw(CCR1, ch1, n_start);
422
beq(CCR1, L_Comp1);
423
bind(L_NotFound);
424
li(result, -1); // not found
425
b(L_End);
426
427
// **************************************************************************************************
428
// Special Case: unfortunately, the variable needle case can be called with needlecnt<2
429
// **************************************************************************************************
430
if (needlecntval == 0) { // We have to handle these cases separately.
431
Label L_OneCharLoop;
432
bind(L_TooShort);
433
mtctr(haycnt);
434
if (n_csize == 2) { lhz(n_start, 0, needle); } else { lbz(n_start, 0, needle); } // First character of needle
435
bind(L_OneCharLoop);
436
if (h_csize == 2) { lhzu(ch1, 2, addr); } else { lbzu(ch1, 1, addr); }
437
cmpw(CCR1, ch1, n_start);
438
beq(CCR1, L_Found); // Did we find the one character needle?
439
bdnz(L_OneCharLoop);
440
li(result, -1); // Not found.
441
b(L_End);
442
}
443
444
// **************************************************************************************************
445
// Regular Case Part II: compare rest of needle (first 2 characters have been compared already)
446
// **************************************************************************************************
447
448
// Compare the rest
449
bind(L_Comp2);
450
addi(addr, addr, h_csize); // First comparison has failed, 2nd one hit.
451
bind(L_Comp1); // Addr points to possible needle start.
452
if (needlecntval != 2) { // Const needlecnt==2?
453
if (needlecntval != 3) {
454
if (needlecntval == 0) { beq(CCR6, L_Found); } // Variable needlecnt==2?
455
Register n_ind = tmp4,
456
h_ind = n_ind;
457
li(n_ind, 2 * n_csize); // First 2 characters are already compared, use index 2.
458
mtctr(needlecnt); // Decremented by 2, still > 0.
459
Label L_CompLoop;
460
bind(L_CompLoop);
461
if (ae ==StrIntrinsicNode::UL) {
462
h_ind = ch1;
463
sldi(h_ind, n_ind, 1);
464
}
465
if (n_csize == 2) { lhzx(ch2, needle, n_ind); } else { lbzx(ch2, needle, n_ind); }
466
if (h_csize == 2) { lhzx(ch1, addr, h_ind); } else { lbzx(ch1, addr, h_ind); }
467
cmpw(CCR1, ch1, ch2);
468
bne(CCR1, L_OuterLoop);
469
addi(n_ind, n_ind, n_csize);
470
bdnz(L_CompLoop);
471
} else { // No loop required if there's only one needle character left.
472
if (n_csize == 2) { lhz(ch2, 2 * 2, needle); } else { lbz(ch2, 2 * 1, needle); }
473
if (h_csize == 2) { lhz(ch1, 2 * 2, addr); } else { lbz(ch1, 2 * 1, addr); }
474
cmpw(CCR1, ch1, ch2);
475
bne(CCR1, L_OuterLoop);
476
}
477
}
478
// Return index ...
479
bind(L_Found);
480
subf(result, haystack, addr); // relative to haystack, ...
481
if (h_csize == 2) { srdi(result, result, 1); } // in characters.
482
bind(L_End);
483
} // string_indexof
484
485
void C2_MacroAssembler::string_indexof_char(Register result, Register haystack, Register haycnt,
486
Register needle, jchar needleChar, Register tmp1, Register tmp2, bool is_byte) {
487
assert_different_registers(haystack, haycnt, needle, tmp1, tmp2);
488
489
Label L_InnerLoop, L_FinalCheck, L_Found1, L_Found2, L_NotFound, L_End;
490
Register addr = tmp1,
491
ch1 = tmp2,
492
ch2 = R0;
493
494
const int h_csize = is_byte ? 1 : 2;
495
496
//4:
497
srwi_(tmp2, haycnt, 1); // Shift right by exact_log2(UNROLL_FACTOR).
498
mr(addr, haystack);
499
beq(CCR0, L_FinalCheck);
500
mtctr(tmp2); // Move to count register.
501
//8:
502
bind(L_InnerLoop); // Main work horse (2x unrolled search loop).
503
if (!is_byte) {
504
lhz(ch1, 0, addr);
505
lhz(ch2, 2, addr);
506
} else {
507
lbz(ch1, 0, addr);
508
lbz(ch2, 1, addr);
509
}
510
(needle != R0) ? cmpw(CCR0, ch1, needle) : cmplwi(CCR0, ch1, (unsigned int)needleChar);
511
(needle != R0) ? cmpw(CCR1, ch2, needle) : cmplwi(CCR1, ch2, (unsigned int)needleChar);
512
beq(CCR0, L_Found1); // Did we find the needle?
513
beq(CCR1, L_Found2);
514
addi(addr, addr, 2 * h_csize);
515
bdnz(L_InnerLoop);
516
//16:
517
bind(L_FinalCheck);
518
andi_(R0, haycnt, 1);
519
beq(CCR0, L_NotFound);
520
if (!is_byte) { lhz(ch1, 0, addr); } else { lbz(ch1, 0, addr); } // One position left at which we have to compare.
521
(needle != R0) ? cmpw(CCR1, ch1, needle) : cmplwi(CCR1, ch1, (unsigned int)needleChar);
522
beq(CCR1, L_Found1);
523
//21:
524
bind(L_NotFound);
525
li(result, -1); // Not found.
526
b(L_End);
527
528
bind(L_Found2);
529
addi(addr, addr, h_csize);
530
//24:
531
bind(L_Found1); // Return index ...
532
subf(result, haystack, addr); // relative to haystack, ...
533
if (!is_byte) { srdi(result, result, 1); } // in characters.
534
bind(L_End);
535
} // string_indexof_char
536
537
538
void C2_MacroAssembler::has_negatives(Register src, Register cnt, Register result,
539
Register tmp1, Register tmp2) {
540
const Register tmp0 = R0;
541
assert_different_registers(src, result, cnt, tmp0, tmp1, tmp2);
542
Label Lfastloop, Lslow, Lloop, Lnoneg, Ldone;
543
544
// Check if cnt >= 8 (= 16 bytes)
545
lis(tmp1, (int)(short)0x8080); // tmp1 = 0x8080808080808080
546
srwi_(tmp2, cnt, 4);
547
li(result, 1); // Assume there's a negative byte.
548
beq(CCR0, Lslow);
549
ori(tmp1, tmp1, 0x8080);
550
rldimi(tmp1, tmp1, 32, 0);
551
mtctr(tmp2);
552
553
// 2x unrolled loop
554
bind(Lfastloop);
555
ld(tmp2, 0, src);
556
ld(tmp0, 8, src);
557
558
orr(tmp0, tmp2, tmp0);
559
560
and_(tmp0, tmp0, tmp1);
561
bne(CCR0, Ldone); // Found negative byte.
562
addi(src, src, 16);
563
564
bdnz(Lfastloop);
565
566
bind(Lslow); // Fallback to slow version
567
rldicl_(tmp0, cnt, 0, 64-4);
568
beq(CCR0, Lnoneg);
569
mtctr(tmp0);
570
bind(Lloop);
571
lbz(tmp0, 0, src);
572
addi(src, src, 1);
573
andi_(tmp0, tmp0, 0x80);
574
bne(CCR0, Ldone); // Found negative byte.
575
bdnz(Lloop);
576
bind(Lnoneg);
577
li(result, 0);
578
579
bind(Ldone);
580
}
581
582
583