1// Copyright 2021 the V8 project authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#if V8_TARGET_ARCH_LOONG64
6
7#include "src/regexp/loong64/regexp-macro-assembler-loong64.h"
8
9#include "src/codegen/macro-assembler.h"
10#include "src/heap/factory.h"
11#include "src/logging/log.h"
12#include "src/objects/code-inl.h"
13#include "src/regexp/regexp-stack.h"
14#include "src/snapshot/embedded/embedded-data-inl.h"
15
16namespace v8 {
17namespace internal {
18
19/* clang-format off
20 *
21 * This assembler uses the following register assignment convention
22 * - s0 : Unused.
23 * - s1 : Pointer to current Code object including heap object tag.
24 * - s2 : Current position in input, as negative offset from end of string.
25 *        Please notice that this is the byte offset, not the character offset!
26 * - s5 : Currently loaded character. Must be loaded using
27 *        LoadCurrentCharacter before using any of the dispatch methods.
28 * - s6 : Points to tip of backtrack stack
29 * - s7 : End of input (points to byte after last character in input).
30 * - fp : Frame pointer. Used to access arguments, local variables and
31 *        RegExp registers.
32 * - sp : Points to tip of C stack.
33 *
34 * The remaining registers are free for computations.
35 * Each call to a public method should retain this convention.
36 *
37 * The stack will have the following structure:
38 *
39 *  - fp[80]  Isolate* isolate   (address of the current isolate)               kIsolate
40 *                                                                              kStackFrameHeader
41 *  --- sp when called ---
42 *  - fp[72]  ra                 Return from RegExp code (ra).                  kReturnAddress
43 *  - fp[64]  old-fp             Old fp, callee saved.
44 *  - fp[0..63]  s0..s7          Callee-saved registers s0..s7.
45 *  --- frame pointer ----
46 *  - fp[-8]  direct_call        (1 = direct call from JS, 0 = from runtime)    kDirectCall
47 *  - fp[-16] capture array size (may fit multiple sets of matches)             kNumOutputRegisters
48 *  - fp[-24] int* capture_array (int[num_saved_registers_], for output).       kRegisterOutput
49 *  - fp[-32] end of input       (address of end of string).                    kInputEnd
50 *  - fp[-40] start of input     (address of first character in string).        kInputStart
51 *  - fp[-48] start index        (character index of start).                    kStartIndex
52 *  - fp[-56] void* input_string (location of a handle containing the string).  kInputString
53 *  - fp[-64] success counter    (only for global regexps to count matches).    kSuccessfulCaptures
54 *  - fp[-72] Offset of location before start of input (effectively character   kStringStartMinusOne
55 *            position -1). Used to initialize capture registers to a
56 *            non-position.
57 *  --------- The following output registers are 32-bit values. ---------
58 *  - fp[-80] register 0         (Only positions must be stored in the first    kRegisterZero
59 *  -         register 1          num_saved_registers_ registers)
60 *  -         ...
61 *  -         register num_registers-1
62 *  --- sp ---
63 *
64 * The first num_saved_registers_ registers are initialized to point to
65 * "character -1" in the string (i.e., char_size() bytes before the first
66 * character of the string). The remaining registers start out as garbage.
67 *
68 * The data up to the return address must be placed there by the calling
69 * code and the remaining arguments are passed in registers, e.g. by calling the
70 * code entry as cast to a function with the signature:
71 * int (*match)(String input_string,
72 *              int start_index,
73 *              Address start,
74 *              Address end,
75 *              int* capture_output_array,
76 *              int num_capture_registers,
77 *              bool direct_call = false,
78 *              Isolate* isolate);
79 * The call is performed by NativeRegExpMacroAssembler::Execute()
80 * (in regexp-macro-assembler.cc) via the GeneratedCode wrapper.
81 *
82 * clang-format on
83 */
84
85#define __ ACCESS_MASM(masm_)
86
87const int RegExpMacroAssemblerLOONG64::kRegExpCodeSize;
88
89RegExpMacroAssemblerLOONG64::RegExpMacroAssemblerLOONG64(Isolate* isolate,
90                                                         Zone* zone, Mode mode,
91                                                         int registers_to_save)
92    : NativeRegExpMacroAssembler(isolate, zone),
93      masm_(std::make_unique<MacroAssembler>(
94          isolate, CodeObjectRequired::kYes,
95          NewAssemblerBuffer(kRegExpCodeSize))),
96      no_root_array_scope_(masm_.get()),
97      mode_(mode),
98      num_registers_(registers_to_save),
99      num_saved_registers_(registers_to_save),
100      entry_label_(),
101      start_label_(),
102      success_label_(),
103      backtrack_label_(),
104      exit_label_(),
105      internal_failure_label_() {
106  DCHECK_EQ(0, registers_to_save % 2);
107  __ jmp(&entry_label_);  // We'll write the entry code later.
108  // If the code gets too big or corrupted, an internal exception will be
109  // raised, and we will exit right away.
110  __ bind(&internal_failure_label_);
111  __ li(a0, Operand(FAILURE));
112  __ Ret();
113  __ bind(&start_label_);  // And then continue from here.
114}
115
116RegExpMacroAssemblerLOONG64::~RegExpMacroAssemblerLOONG64() {
117  // Unuse labels in case we throw away the assembler without calling GetCode.
118  entry_label_.Unuse();
119  start_label_.Unuse();
120  success_label_.Unuse();
121  backtrack_label_.Unuse();
122  exit_label_.Unuse();
123  check_preempt_label_.Unuse();
124  stack_overflow_label_.Unuse();
125  internal_failure_label_.Unuse();
126  fallback_label_.Unuse();
127}
128
129int RegExpMacroAssemblerLOONG64::stack_limit_slack() {
130  return RegExpStack::kStackLimitSlack;
131}
132
133void RegExpMacroAssemblerLOONG64::AdvanceCurrentPosition(int by) {
134  if (by != 0) {
135    __ Add_d(current_input_offset(), current_input_offset(),
136             Operand(by * char_size()));
137  }
138}
139
140void RegExpMacroAssemblerLOONG64::AdvanceRegister(int reg, int by) {
141  DCHECK_LE(0, reg);
142  DCHECK_GT(num_registers_, reg);
143  if (by != 0) {
144    __ Ld_d(a0, register_location(reg));
145    __ Add_d(a0, a0, Operand(by));
146    __ St_d(a0, register_location(reg));
147  }
148}
149
150void RegExpMacroAssemblerLOONG64::Backtrack() {
151  CheckPreemption();
152  if (has_backtrack_limit()) {
153    Label next;
154    __ Ld_d(a0, MemOperand(frame_pointer(), kBacktrackCount));
155    __ Add_d(a0, a0, Operand(1));
156    __ St_d(a0, MemOperand(frame_pointer(), kBacktrackCount));
157    __ Branch(&next, ne, a0, Operand(backtrack_limit()));
158
159    // Backtrack limit exceeded.
160    if (can_fallback()) {
161      __ jmp(&fallback_label_);
162    } else {
163      // Can't fallback, so we treat it as a failed match.
164      Fail();
165    }
166
167    __ bind(&next);
168  }
169  // Pop Code offset from backtrack stack, add Code and jump to location.
170  Pop(a0);
171  __ Add_d(a0, a0, code_pointer());
172  __ Jump(a0);
173}
174
175void RegExpMacroAssemblerLOONG64::Bind(Label* label) { __ bind(label); }
176
177void RegExpMacroAssemblerLOONG64::CheckCharacter(uint32_t c, Label* on_equal) {
178  BranchOrBacktrack(on_equal, eq, current_character(), Operand(c));
179}
180
181void RegExpMacroAssemblerLOONG64::CheckCharacterGT(base::uc16 limit,
182                                                   Label* on_greater) {
183  BranchOrBacktrack(on_greater, gt, current_character(), Operand(limit));
184}
185
186void RegExpMacroAssemblerLOONG64::CheckAtStart(int cp_offset,
187                                               Label* on_at_start) {
188  __ Ld_d(a1, MemOperand(frame_pointer(), kStringStartMinusOne));
189  __ Add_d(a0, current_input_offset(),
190           Operand(-char_size() + cp_offset * char_size()));
191  BranchOrBacktrack(on_at_start, eq, a0, Operand(a1));
192}
193
194void RegExpMacroAssemblerLOONG64::CheckNotAtStart(int cp_offset,
195                                                  Label* on_not_at_start) {
196  __ Ld_d(a1, MemOperand(frame_pointer(), kStringStartMinusOne));
197  __ Add_d(a0, current_input_offset(),
198           Operand(-char_size() + cp_offset * char_size()));
199  BranchOrBacktrack(on_not_at_start, ne, a0, Operand(a1));
200}
201
202void RegExpMacroAssemblerLOONG64::CheckCharacterLT(base::uc16 limit,
203                                                   Label* on_less) {
204  BranchOrBacktrack(on_less, lt, current_character(), Operand(limit));
205}
206
207void RegExpMacroAssemblerLOONG64::CheckGreedyLoop(Label* on_equal) {
208  Label backtrack_non_equal;
209  __ Ld_w(a0, MemOperand(backtrack_stackpointer(), 0));
210  __ Branch(&backtrack_non_equal, ne, current_input_offset(), Operand(a0));
211  __ Add_d(backtrack_stackpointer(), backtrack_stackpointer(),
212           Operand(kIntSize));
213  __ bind(&backtrack_non_equal);
214  BranchOrBacktrack(on_equal, eq, current_input_offset(), Operand(a0));
215}
216
217void RegExpMacroAssemblerLOONG64::CheckNotBackReferenceIgnoreCase(
218    int start_reg, bool read_backward, bool unicode, Label* on_no_match) {
219  Label fallthrough;
220  __ Ld_d(a0, register_location(start_reg));      // Index of start of capture.
221  __ Ld_d(a1, register_location(start_reg + 1));  // Index of end of capture.
222  __ Sub_d(a1, a1, a0);                           // Length of capture.
223
224  // At this point, the capture registers are either both set or both cleared.
225  // If the capture length is zero, then the capture is either empty or cleared.
226  // Fall through in both cases.
227  __ Branch(&fallthrough, eq, a1, Operand(zero_reg));
228
229  if (read_backward) {
230    __ Ld_d(t1, MemOperand(frame_pointer(), kStringStartMinusOne));
231    __ Add_d(t1, t1, a1);
232    BranchOrBacktrack(on_no_match, le, current_input_offset(), Operand(t1));
233  } else {
234    __ Add_d(t1, a1, current_input_offset());
235    // Check that there are enough characters left in the input.
236    BranchOrBacktrack(on_no_match, gt, t1, Operand(zero_reg));
237  }
238
239  if (mode_ == LATIN1) {
240    Label success;
241    Label fail;
242    Label loop_check;
243
244    // a0 - offset of start of capture.
245    // a1 - length of capture.
246    __ Add_d(a0, a0, Operand(end_of_input_address()));
247    __ Add_d(a2, end_of_input_address(), Operand(current_input_offset()));
248    if (read_backward) {
249      __ Sub_d(a2, a2, Operand(a1));
250    }
251    __ Add_d(a1, a0, Operand(a1));
252
253    // a0 - Address of start of capture.
254    // a1 - Address of end of capture.
255    // a2 - Address of current input position.
256
257    Label loop;
258    __ bind(&loop);
259    __ Ld_bu(a3, MemOperand(a0, 0));
260    __ addi_d(a0, a0, char_size());
261    __ Ld_bu(a4, MemOperand(a2, 0));
262    __ addi_d(a2, a2, char_size());
263
264    __ Branch(&loop_check, eq, a4, Operand(a3));
265
266    // Mismatch, try case-insensitive match (converting letters to lower-case).
267    __ Or(a3, a3, Operand(0x20));  // Convert capture character to lower-case.
268    __ Or(a4, a4, Operand(0x20));  // Also convert input character.
269    __ Branch(&fail, ne, a4, Operand(a3));
270    __ Sub_d(a3, a3, Operand('a'));
271    __ Branch(&loop_check, ls, a3, Operand('z' - 'a'));
272    // Latin-1: Check for values in range [224,254] but not 247.
273    __ Sub_d(a3, a3, Operand(224 - 'a'));
274    // Weren't Latin-1 letters.
275    __ Branch(&fail, hi, a3, Operand(254 - 224));
276    // Check for 247.
277    __ Branch(&fail, eq, a3, Operand(247 - 224));
278
279    __ bind(&loop_check);
280    __ Branch(&loop, lt, a0, Operand(a1));
281    __ jmp(&success);
282
283    __ bind(&fail);
284    GoTo(on_no_match);
285
286    __ bind(&success);
287    // Compute new value of character position after the matched part.
288    __ Sub_d(current_input_offset(), a2, end_of_input_address());
289    if (read_backward) {
290      __ Ld_d(t1, register_location(start_reg));  // Index of start of capture.
291      __ Ld_d(a2,
292              register_location(start_reg + 1));  // Index of end of capture.
293      __ Add_d(current_input_offset(), current_input_offset(), Operand(t1));
294      __ Sub_d(current_input_offset(), current_input_offset(), Operand(a2));
295    }
296  } else {
297    DCHECK(mode_ == UC16);
298
299    int argument_count = 4;
300    __ PrepareCallCFunction(argument_count, a2);
301
302    // a0 - offset of start of capture.
303    // a1 - length of capture.
304
305    // Put arguments into arguments registers.
306    // Parameters are
307    //   a0: Address byte_offset1 - Address captured substring's start.
308    //   a1: Address byte_offset2 - Address of current character position.
309    //   a2: size_t byte_length - length of capture in bytes(!).
310    //   a3: Isolate* isolate.
311
312    // Address of start of capture.
313    __ Add_d(a0, a0, Operand(end_of_input_address()));
314    // Length of capture.
315    __ mov(a2, a1);
316    // Save length in callee-save register for use on return.
317    __ mov(s3, a1);
318    // Address of current input position.
319    __ Add_d(a1, current_input_offset(), Operand(end_of_input_address()));
320    if (read_backward) {
321      __ Sub_d(a1, a1, Operand(s3));
322    }
323    // Isolate.
324    __ li(a3, Operand(ExternalReference::isolate_address(masm_->isolate())));
325
326    {
327      AllowExternalCallThatCantCauseGC scope(masm_.get());
328      ExternalReference function =
329          unicode
330              ? ExternalReference::re_case_insensitive_compare_unicode()
331              : ExternalReference::re_case_insensitive_compare_non_unicode();
332      __ CallCFunction(function, argument_count);
333    }
334
335    // Check if function returned non-zero for success or zero for failure.
336    BranchOrBacktrack(on_no_match, eq, a0, Operand(zero_reg));
337    // On success, increment position by length of capture.
338    if (read_backward) {
339      __ Sub_d(current_input_offset(), current_input_offset(), Operand(s3));
340    } else {
341      __ Add_d(current_input_offset(), current_input_offset(), Operand(s3));
342    }
343  }
344
345  __ bind(&fallthrough);
346}
347
348void RegExpMacroAssemblerLOONG64::CheckNotBackReference(int start_reg,
349                                                        bool read_backward,
350                                                        Label* on_no_match) {
351  Label fallthrough;
352
353  // Find length of back-referenced capture.
354  __ Ld_d(a0, register_location(start_reg));
355  __ Ld_d(a1, register_location(start_reg + 1));
356  __ Sub_d(a1, a1, a0);  // Length to check.
357
358  // At this point, the capture registers are either both set or both cleared.
359  // If the capture length is zero, then the capture is either empty or cleared.
360  // Fall through in both cases.
361  __ Branch(&fallthrough, eq, a1, Operand(zero_reg));
362
363  if (read_backward) {
364    __ Ld_d(t1, MemOperand(frame_pointer(), kStringStartMinusOne));
365    __ Add_d(t1, t1, a1);
366    BranchOrBacktrack(on_no_match, le, current_input_offset(), Operand(t1));
367  } else {
368    __ Add_d(t1, a1, current_input_offset());
369    // Check that there are enough characters left in the input.
370    BranchOrBacktrack(on_no_match, gt, t1, Operand(zero_reg));
371  }
372
373  // Compute pointers to match string and capture string.
374  __ Add_d(a0, a0, Operand(end_of_input_address()));
375  __ Add_d(a2, end_of_input_address(), Operand(current_input_offset()));
376  if (read_backward) {
377    __ Sub_d(a2, a2, Operand(a1));
378  }
379  __ Add_d(a1, a1, Operand(a0));
380
381  Label loop;
382  __ bind(&loop);
383  if (mode_ == LATIN1) {
384    __ Ld_bu(a3, MemOperand(a0, 0));
385    __ addi_d(a0, a0, char_size());
386    __ Ld_bu(a4, MemOperand(a2, 0));
387    __ addi_d(a2, a2, char_size());
388  } else {
389    DCHECK(mode_ == UC16);
390    __ Ld_hu(a3, MemOperand(a0, 0));
391    __ addi_d(a0, a0, char_size());
392    __ Ld_hu(a4, MemOperand(a2, 0));
393    __ addi_d(a2, a2, char_size());
394  }
395  BranchOrBacktrack(on_no_match, ne, a3, Operand(a4));
396  __ Branch(&loop, lt, a0, Operand(a1));
397
398  // Move current character position to position after match.
399  __ Sub_d(current_input_offset(), a2, end_of_input_address());
400  if (read_backward) {
401    __ Ld_d(t1, register_location(start_reg));  // Index of start of capture.
402    __ Ld_d(a2, register_location(start_reg + 1));  // Index of end of capture.
403    __ Add_d(current_input_offset(), current_input_offset(), Operand(t1));
404    __ Sub_d(current_input_offset(), current_input_offset(), Operand(a2));
405  }
406  __ bind(&fallthrough);
407}
408
409void RegExpMacroAssemblerLOONG64::CheckNotCharacter(uint32_t c,
410                                                    Label* on_not_equal) {
411  BranchOrBacktrack(on_not_equal, ne, current_character(), Operand(c));
412}
413
414void RegExpMacroAssemblerLOONG64::CheckCharacterAfterAnd(uint32_t c,
415                                                         uint32_t mask,
416                                                         Label* on_equal) {
417  __ And(a0, current_character(), Operand(mask));
418  Operand rhs = (c == 0) ? Operand(zero_reg) : Operand(c);
419  BranchOrBacktrack(on_equal, eq, a0, rhs);
420}
421
422void RegExpMacroAssemblerLOONG64::CheckNotCharacterAfterAnd(
423    uint32_t c, uint32_t mask, Label* on_not_equal) {
424  __ And(a0, current_character(), Operand(mask));
425  Operand rhs = (c == 0) ? Operand(zero_reg) : Operand(c);
426  BranchOrBacktrack(on_not_equal, ne, a0, rhs);
427}
428
429void RegExpMacroAssemblerLOONG64::CheckNotCharacterAfterMinusAnd(
430    base::uc16 c, base::uc16 minus, base::uc16 mask, Label* on_not_equal) {
431  DCHECK_GT(String::kMaxUtf16CodeUnit, minus);
432  __ Sub_d(a0, current_character(), Operand(minus));
433  __ And(a0, a0, Operand(mask));
434  BranchOrBacktrack(on_not_equal, ne, a0, Operand(c));
435}
436
437void RegExpMacroAssemblerLOONG64::CheckCharacterInRange(base::uc16 from,
438                                                        base::uc16 to,
439                                                        Label* on_in_range) {
440  __ Sub_d(a0, current_character(), Operand(from));
441  // Unsigned lower-or-same condition.
442  BranchOrBacktrack(on_in_range, ls, a0, Operand(to - from));
443}
444
445void RegExpMacroAssemblerLOONG64::CheckCharacterNotInRange(
446    base::uc16 from, base::uc16 to, Label* on_not_in_range) {
447  __ Sub_d(a0, current_character(), Operand(from));
448  // Unsigned higher condition.
449  BranchOrBacktrack(on_not_in_range, hi, a0, Operand(to - from));
450}
451
452void RegExpMacroAssemblerLOONG64::CallIsCharacterInRangeArray(
453    const ZoneList<CharacterRange>* ranges) {
454  static const int kNumArguments = 3;
455  __ PrepareCallCFunction(kNumArguments, a0);
456
457  __ mov(a0, current_character());
458  __ li(a1, Operand(GetOrAddRangeArray(ranges)));
459  __ li(a2, Operand(ExternalReference::isolate_address(isolate())));
460
461  {
462    // We have a frame (set up in GetCode), but the assembler doesn't know.
463    FrameScope scope(masm_.get(), StackFrame::MANUAL);
464    __ CallCFunction(ExternalReference::re_is_character_in_range_array(),
465                     kNumArguments);
466  }
467
468  __ li(code_pointer(), Operand(masm_->CodeObject()));
469}
470
471bool RegExpMacroAssemblerLOONG64::CheckCharacterInRangeArray(
472    const ZoneList<CharacterRange>* ranges, Label* on_in_range) {
473  CallIsCharacterInRangeArray(ranges);
474  BranchOrBacktrack(on_in_range, ne, a0, Operand(zero_reg));
475  return true;
476}
477
478bool RegExpMacroAssemblerLOONG64::CheckCharacterNotInRangeArray(
479    const ZoneList<CharacterRange>* ranges, Label* on_not_in_range) {
480  CallIsCharacterInRangeArray(ranges);
481  BranchOrBacktrack(on_not_in_range, eq, a0, Operand(zero_reg));
482  return true;
483}
484
485void RegExpMacroAssemblerLOONG64::CheckBitInTable(Handle<ByteArray> table,
486                                                  Label* on_bit_set) {
487  __ li(a0, Operand(table));
488  if (mode_ != LATIN1 || kTableMask != String::kMaxOneByteCharCode) {
489    __ And(a1, current_character(), Operand(kTableSize - 1));
490    __ Add_d(a0, a0, a1);
491  } else {
492    __ Add_d(a0, a0, current_character());
493  }
494
495  __ Ld_bu(a0, FieldMemOperand(a0, ByteArray::kHeaderSize));
496  BranchOrBacktrack(on_bit_set, ne, a0, Operand(zero_reg));
497}
498
499bool RegExpMacroAssemblerLOONG64::CheckSpecialCharacterClass(
500    StandardCharacterSet type, Label* on_no_match) {
501  // Range checks (c in min..max) are generally implemented by an unsigned
502  // (c - min) <= (max - min) check.
503  // TODO(jgruber): No custom implementation (yet): s(UC16), S(UC16).
504  switch (type) {
505    case StandardCharacterSet::kWhitespace:
506      // Match space-characters.
507      if (mode_ == LATIN1) {
508        // One byte space characters are '\t'..'\r', ' ' and \u00a0.
509        Label success;
510        __ Branch(&success, eq, current_character(), Operand(' '));
511        // Check range 0x09..0x0D.
512        __ Sub_d(a0, current_character(), Operand('\t'));
513        __ Branch(&success, ls, a0, Operand('\r' - '\t'));
514        // \u00a0 (NBSP).
515        BranchOrBacktrack(on_no_match, ne, a0, Operand(0x00A0 - '\t'));
516        __ bind(&success);
517        return true;
518      }
519      return false;
520    case StandardCharacterSet::kNotWhitespace:
521      // The emitted code for generic character classes is good enough.
522      return false;
523    case StandardCharacterSet::kDigit:
524      // Match Latin1 digits ('0'..'9').
525      __ Sub_d(a0, current_character(), Operand('0'));
526      BranchOrBacktrack(on_no_match, hi, a0, Operand('9' - '0'));
527      return true;
528    case StandardCharacterSet::kNotDigit:
529      // Match non Latin1-digits.
530      __ Sub_d(a0, current_character(), Operand('0'));
531      BranchOrBacktrack(on_no_match, ls, a0, Operand('9' - '0'));
532      return true;
533    case StandardCharacterSet::kNotLineTerminator: {
534      // Match non-newlines (not 0x0A('\n'), 0x0D('\r'), 0x2028 and 0x2029).
535      __ Xor(a0, current_character(), Operand(0x01));
536      // See if current character is '\n'^1 or '\r'^1, i.e., 0x0B or 0x0C.
537      __ Sub_d(a0, a0, Operand(0x0B));
538      BranchOrBacktrack(on_no_match, ls, a0, Operand(0x0C - 0x0B));
539      if (mode_ == UC16) {
540        // Compare original value to 0x2028 and 0x2029, using the already
541        // computed (current_char ^ 0x01 - 0x0B). I.e., check for
542        // 0x201D (0x2028 - 0x0B) or 0x201E.
543        __ Sub_d(a0, a0, Operand(0x2028 - 0x0B));
544        BranchOrBacktrack(on_no_match, ls, a0, Operand(1));
545      }
546      return true;
547    }
548    case StandardCharacterSet::kLineTerminator: {
549      // Match newlines (0x0A('\n'), 0x0D('\r'), 0x2028 and 0x2029).
550      __ Xor(a0, current_character(), Operand(0x01));
551      // See if current character is '\n'^1 or '\r'^1, i.e., 0x0B or 0x0C.
552      __ Sub_d(a0, a0, Operand(0x0B));
553      if (mode_ == LATIN1) {
554        BranchOrBacktrack(on_no_match, hi, a0, Operand(0x0C - 0x0B));
555      } else {
556        Label done;
557        BranchOrBacktrack(&done, ls, a0, Operand(0x0C - 0x0B));
558        // Compare original value to 0x2028 and 0x2029, using the already
559        // computed (current_char ^ 0x01 - 0x0B). I.e., check for
560        // 0x201D (0x2028 - 0x0B) or 0x201E.
561        __ Sub_d(a0, a0, Operand(0x2028 - 0x0B));
562        BranchOrBacktrack(on_no_match, hi, a0, Operand(1));
563        __ bind(&done);
564      }
565      return true;
566    }
567    case StandardCharacterSet::kWord: {
568      if (mode_ != LATIN1) {
569        // Table is 256 entries, so all Latin1 characters can be tested.
570        BranchOrBacktrack(on_no_match, hi, current_character(), Operand('z'));
571      }
572      ExternalReference map = ExternalReference::re_word_character_map();
573      __ li(a0, Operand(map));
574      __ Add_d(a0, a0, current_character());
575      __ Ld_bu(a0, MemOperand(a0, 0));
576      BranchOrBacktrack(on_no_match, eq, a0, Operand(zero_reg));
577      return true;
578    }
579    case StandardCharacterSet::kNotWord: {
580      Label done;
581      if (mode_ != LATIN1) {
582        // Table is 256 entries, so all Latin1 characters can be tested.
583        __ Branch(&done, hi, current_character(), Operand('z'));
584      }
585      ExternalReference map = ExternalReference::re_word_character_map();
586      __ li(a0, Operand(map));
587      __ Add_d(a0, a0, current_character());
588      __ Ld_bu(a0, MemOperand(a0, 0));
589      BranchOrBacktrack(on_no_match, ne, a0, Operand(zero_reg));
590      if (mode_ != LATIN1) {
591        __ bind(&done);
592      }
593      return true;
594    }
595    case StandardCharacterSet::kEverything:
596      // Match any character.
597      return true;
598  }
599}
600
601void RegExpMacroAssemblerLOONG64::Fail() {
602  __ li(a0, Operand(FAILURE));
603  __ jmp(&exit_label_);
604}
605
606void RegExpMacroAssemblerLOONG64::LoadRegExpStackPointerFromMemory(
607    Register dst) {
608  ExternalReference ref =
609      ExternalReference::address_of_regexp_stack_stack_pointer(isolate());
610  __ li(dst, ref);
611  __ Ld_d(dst, MemOperand(dst, 0));
612}
613
614void RegExpMacroAssemblerLOONG64::StoreRegExpStackPointerToMemory(
615    Register src, Register scratch) {
616  ExternalReference ref =
617      ExternalReference::address_of_regexp_stack_stack_pointer(isolate());
618  __ li(scratch, ref);
619  __ St_d(src, MemOperand(scratch, 0));
620}
621
622void RegExpMacroAssemblerLOONG64::PushRegExpBasePointer(Register stack_pointer,
623                                                        Register scratch) {
624  ExternalReference ref =
625      ExternalReference::address_of_regexp_stack_memory_top_address(isolate());
626  __ li(scratch, ref);
627  __ Ld_d(scratch, MemOperand(scratch, 0));
628  __ Sub_d(scratch, stack_pointer, scratch);
629  __ St_d(scratch, MemOperand(frame_pointer(), kRegExpStackBasePointer));
630}
631
632void RegExpMacroAssemblerLOONG64::PopRegExpBasePointer(
633    Register stack_pointer_out, Register scratch) {
634  ExternalReference ref =
635      ExternalReference::address_of_regexp_stack_memory_top_address(isolate());
636  __ Ld_d(stack_pointer_out,
637          MemOperand(frame_pointer(), kRegExpStackBasePointer));
638  __ li(scratch, ref);
639  __ Ld_d(scratch, MemOperand(scratch, 0));
640  __ Add_d(stack_pointer_out, stack_pointer_out, scratch);
641  StoreRegExpStackPointerToMemory(stack_pointer_out, scratch);
642}
643
644Handle<HeapObject> RegExpMacroAssemblerLOONG64::GetCode(Handle<String> source) {
645  Label return_v0;
646  if (0 /* todo masm_->has_exception()*/) {
647    // If the code gets corrupted due to long regular expressions and lack of
648    // space on trampolines, an internal exception flag is set. If this case
649    // is detected, we will jump into exit sequence right away.
650    //__ bind_to(&entry_label_, internal_failure_label_.pos());
651  } else {
652    // Finalize code - write the entry point code now we know how many
653    // registers we need.
654
655    // Entry code:
656    __ bind(&entry_label_);
657
658    // Tell the system that we have a stack frame.  Because the type is MANUAL,
659    // no is generated.
660    FrameScope scope(masm_.get(), StackFrame::MANUAL);
661
662    // Actually emit code to start a new stack frame.
663    // Push arguments
664    // Save callee-save registers.
665    // Start new stack frame.
666    // Store link register in existing stack-cell.
667    // Order here should correspond to order of offset constants in header file.
668    // TODO(plind): we save s0..s7, but ONLY use s3 here - use the regs
669    // or dont save.
670    RegList registers_to_retain = {s0, s1, s2, s3, s4, s5, s6, s7};
671    RegList argument_registers = {a0, a1, a2, a3};
672
673    argument_registers |= {a4, a5, a6, a7};
674
675    __ MultiPush({ra}, {fp}, argument_registers | registers_to_retain);
676    // Set frame pointer in space for it if this is not a direct call
677    // from generated code.
678    // TODO(plind): this 8 is the # of argument regs, should have definition.
679    __ Add_d(frame_pointer(), sp, Operand(8 * kPointerSize));
680    STATIC_ASSERT(kSuccessfulCaptures == kInputString - kSystemPointerSize);
681    __ mov(a0, zero_reg);
682    __ Push(a0);  // Make room for success counter and initialize it to 0.
683    STATIC_ASSERT(kStringStartMinusOne ==
684                  kSuccessfulCaptures - kSystemPointerSize);
685    __ Push(a0);  // Make room for "string start - 1" constant.
686    STATIC_ASSERT(kBacktrackCount == kStringStartMinusOne - kSystemPointerSize);
687    __ Push(a0);  // The backtrack counter
688    STATIC_ASSERT(kRegExpStackBasePointer ==
689                  kBacktrackCount - kSystemPointerSize);
690    __ Push(a0);  // The regexp stack base ptr.
691
692    // Initialize backtrack stack pointer. It must not be clobbered from here
693    // on. Note the backtrack_stackpointer is callee-saved.
694    STATIC_ASSERT(backtrack_stackpointer() == s7);
695    LoadRegExpStackPointerFromMemory(backtrack_stackpointer());
696
697    // Store the regexp base pointer - we'll later restore it / write it to
698    // memory when returning from this irregexp code object.
699    PushRegExpBasePointer(backtrack_stackpointer(), a1);
700
701    {
702      // Check if we have space on the stack for registers.
703      Label stack_limit_hit, stack_ok;
704
705      ExternalReference stack_limit =
706          ExternalReference::address_of_jslimit(masm_->isolate());
707      __ li(a0, Operand(stack_limit));
708      __ Ld_d(a0, MemOperand(a0, 0));
709      __ Sub_d(a0, sp, a0);
710      // Handle it if the stack pointer is already below the stack limit.
711      __ Branch(&stack_limit_hit, le, a0, Operand(zero_reg));
712      // Check if there is room for the variable number of registers above
713      // the stack limit.
714      __ Branch(&stack_ok, hs, a0, Operand(num_registers_ * kPointerSize));
715      // Exit with OutOfMemory exception. There is not enough space on the stack
716      // for our working registers.
717      __ li(a0, Operand(EXCEPTION));
718      __ jmp(&return_v0);
719
720      __ bind(&stack_limit_hit);
721      CallCheckStackGuardState(a0);
722      // If returned value is non-zero, we exit with the returned value as
723      // result.
724      __ Branch(&return_v0, ne, a0, Operand(zero_reg));
725
726      __ bind(&stack_ok);
727    }
728
729    // Allocate space on stack for registers.
730    __ Sub_d(sp, sp, Operand(num_registers_ * kPointerSize));
731    // Load string end.
732    __ Ld_d(end_of_input_address(), MemOperand(frame_pointer(), kInputEnd));
733    // Load input start.
734    __ Ld_d(a0, MemOperand(frame_pointer(), kInputStart));
735    // Find negative length (offset of start relative to end).
736    __ Sub_d(current_input_offset(), a0, end_of_input_address());
737    // Set a0 to address of char before start of the input string
738    // (effectively string position -1).
739    __ Ld_d(a1, MemOperand(frame_pointer(), kStartIndex));
740    __ Sub_d(a0, current_input_offset(), Operand(char_size()));
741    __ slli_d(t1, a1, (mode_ == UC16) ? 1 : 0);
742    __ Sub_d(a0, a0, t1);
743    // Store this value in a local variable, for use when clearing
744    // position registers.
745    __ St_d(a0, MemOperand(frame_pointer(), kStringStartMinusOne));
746
747    // Initialize code pointer register
748    __ li(code_pointer(), Operand(masm_->CodeObject()), CONSTANT_SIZE);
749
750    Label load_char_start_regexp;
751    {
752      Label start_regexp;
753      // Load newline if index is at start, previous character otherwise.
754      __ Branch(&load_char_start_regexp, ne, a1, Operand(zero_reg));
755      __ li(current_character(), Operand('\n'));
756      __ jmp(&start_regexp);
757
758      // Global regexp restarts matching here.
759      __ bind(&load_char_start_regexp);
760      // Load previous char as initial value of current character register.
761      LoadCurrentCharacterUnchecked(-1, 1);
762      __ bind(&start_regexp);
763    }
764
765    // Initialize on-stack registers.
766    if (num_saved_registers_ > 0) {  // Always is, if generated from a regexp.
767      // Fill saved registers with initial value = start offset - 1.
768      if (num_saved_registers_ > 8) {
769        // Address of register 0.
770        __ Add_d(a1, frame_pointer(), Operand(kRegisterZero));
771        __ li(a2, Operand(num_saved_registers_));
772        Label init_loop;
773        __ bind(&init_loop);
774        __ St_d(a0, MemOperand(a1, 0));
775        __ Add_d(a1, a1, Operand(-kPointerSize));
776        __ Sub_d(a2, a2, Operand(1));
777        __ Branch(&init_loop, ne, a2, Operand(zero_reg));
778      } else {
779        for (int i = 0; i < num_saved_registers_; i++) {
780          __ St_d(a0, register_location(i));
781        }
782      }
783    }
784
785    __ jmp(&start_label_);
786
787    // Exit code:
788    if (success_label_.is_linked()) {
789      // Save captures when successful.
790      __ bind(&success_label_);
791      if (num_saved_registers_ > 0) {
792        // Copy captures to output.
793        __ Ld_d(a1, MemOperand(frame_pointer(), kInputStart));
794        __ Ld_d(a0, MemOperand(frame_pointer(), kRegisterOutput));
795        __ Ld_d(a2, MemOperand(frame_pointer(), kStartIndex));
796        __ Sub_d(a1, end_of_input_address(), a1);
797        // a1 is length of input in bytes.
798        if (mode_ == UC16) {
799          __ srli_d(a1, a1, 1);
800        }
801        // a1 is length of input in characters.
802        __ Add_d(a1, a1, Operand(a2));
803        // a1 is length of string in characters.
804
805        DCHECK_EQ(0, num_saved_registers_ % 2);
806        // Always an even number of capture registers. This allows us to
807        // unroll the loop once to add an operation between a load of a register
808        // and the following use of that register.
809        for (int i = 0; i < num_saved_registers_; i += 2) {
810          __ Ld_d(a2, register_location(i));
811          __ Ld_d(a3, register_location(i + 1));
812          if (i == 0 && global_with_zero_length_check()) {
813            // Keep capture start in a4 for the zero-length check later.
814            __ mov(t3, a2);
815          }
816          if (mode_ == UC16) {
817            __ srai_d(a2, a2, 1);
818            __ Add_d(a2, a2, a1);
819            __ srai_d(a3, a3, 1);
820            __ Add_d(a3, a3, a1);
821          } else {
822            __ Add_d(a2, a1, Operand(a2));
823            __ Add_d(a3, a1, Operand(a3));
824          }
825          // V8 expects the output to be an int32_t array.
826          __ St_w(a2, MemOperand(a0, 0));
827          __ Add_d(a0, a0, kIntSize);
828          __ St_w(a3, MemOperand(a0, 0));
829          __ Add_d(a0, a0, kIntSize);
830        }
831      }
832
833      if (global()) {
834        // Restart matching if the regular expression is flagged as global.
835        __ Ld_d(a0, MemOperand(frame_pointer(), kSuccessfulCaptures));
836        __ Ld_d(a1, MemOperand(frame_pointer(), kNumOutputRegisters));
837        __ Ld_d(a2, MemOperand(frame_pointer(), kRegisterOutput));
838        // Increment success counter.
839        __ Add_d(a0, a0, 1);
840        __ St_d(a0, MemOperand(frame_pointer(), kSuccessfulCaptures));
841        // Capture results have been stored, so the number of remaining global
842        // output registers is reduced by the number of stored captures.
843        __ Sub_d(a1, a1, num_saved_registers_);
844        // Check whether we have enough room for another set of capture results.
845        //__ mov(v0, a0);
846        __ Branch(&return_v0, lt, a1, Operand(num_saved_registers_));
847
848        __ St_d(a1, MemOperand(frame_pointer(), kNumOutputRegisters));
849        // Advance the location for output.
850        __ Add_d(a2, a2, num_saved_registers_ * kIntSize);
851        __ St_d(a2, MemOperand(frame_pointer(), kRegisterOutput));
852
853        // Prepare a0 to initialize registers with its value in the next run.
854        __ Ld_d(a0, MemOperand(frame_pointer(), kStringStartMinusOne));
855
856        // Restore the original regexp stack pointer value (effectively, pop the
857        // stored base pointer).
858        PopRegExpBasePointer(backtrack_stackpointer(), a2);
859
860        if (global_with_zero_length_check()) {
861          // Special case for zero-length matches.
862          // t3: capture start index
863          // Not a zero-length match, restart.
864          __ Branch(&load_char_start_regexp, ne, current_input_offset(),
865                    Operand(t3));
866          // Offset from the end is zero if we already reached the end.
867          __ Branch(&exit_label_, eq, current_input_offset(),
868                    Operand(zero_reg));
869          // Advance current position after a zero-length match.
870          Label advance;
871          __ bind(&advance);
872          __ Add_d(current_input_offset(), current_input_offset(),
873                   Operand((mode_ == UC16) ? 2 : 1));
874          if (global_unicode()) CheckNotInSurrogatePair(0, &advance);
875        }
876
877        __ Branch(&load_char_start_regexp);
878      } else {
879        __ li(a0, Operand(SUCCESS));
880      }
881    }
882    // Exit and return v0.
883    __ bind(&exit_label_);
884    if (global()) {
885      __ Ld_d(a0, MemOperand(frame_pointer(), kSuccessfulCaptures));
886    }
887
888    __ bind(&return_v0);
889    // Restore the original regexp stack pointer value (effectively, pop the
890    // stored base pointer).
891    PopRegExpBasePointer(backtrack_stackpointer(), a2);
892
893    // Skip sp past regexp registers and local variables..
894    __ mov(sp, frame_pointer());
895    // Restore registers s0..s7 and return (restoring ra to pc).
896    __ MultiPop({ra}, {fp}, registers_to_retain);
897    __ Ret();
898
899    // Backtrack code (branch target for conditional backtracks).
900    if (backtrack_label_.is_linked()) {
901      __ bind(&backtrack_label_);
902      Backtrack();
903    }
904
905    Label exit_with_exception;
906
907    // Preempt-code.
908    if (check_preempt_label_.is_linked()) {
909      SafeCallTarget(&check_preempt_label_);
910      // Put regexp engine registers on stack.
911      StoreRegExpStackPointerToMemory(backtrack_stackpointer(), a1);
912
913      CallCheckStackGuardState(a0);
914      // If returning non-zero, we should end execution with the given
915      // result as return value.
916      __ Branch(&return_v0, ne, a0, Operand(zero_reg));
917
918      LoadRegExpStackPointerFromMemory(backtrack_stackpointer());
919
920      // String might have moved: Reload end of string from frame.
921      __ Ld_d(end_of_input_address(), MemOperand(frame_pointer(), kInputEnd));
922
923      SafeReturn();
924    }
925
926    // Backtrack stack overflow code.
927    if (stack_overflow_label_.is_linked()) {
928      SafeCallTarget(&stack_overflow_label_);
929      StoreRegExpStackPointerToMemory(backtrack_stackpointer(), a1);
930      // Reached if the backtrack-stack limit has been hit.
931
932      // Call GrowStack(isolate).
933      static const int kNumArguments = 1;
934      __ PrepareCallCFunction(kNumArguments, a0);
935      __ li(a0, Operand(ExternalReference::isolate_address(masm_->isolate())));
936      ExternalReference grow_stack = ExternalReference::re_grow_stack();
937      __ CallCFunction(grow_stack, kNumArguments);
938      // If nullptr is returned, we have failed to grow the stack, and must exit
939      // with a stack-overflow exception.
940      __ Branch(&exit_with_exception, eq, a0, Operand(zero_reg));
941      // Otherwise use return value as new stack pointer.
942      __ mov(backtrack_stackpointer(), a0);
943      SafeReturn();
944    }
945
946    if (exit_with_exception.is_linked()) {
947      // If any of the code above needed to exit with an exception.
948      __ bind(&exit_with_exception);
949      // Exit with Result EXCEPTION(-1) to signal thrown exception.
950      __ li(a0, Operand(EXCEPTION));
951      __ jmp(&return_v0);
952    }
953
954    if (fallback_label_.is_linked()) {
955      __ bind(&fallback_label_);
956      __ li(a0, Operand(FALLBACK_TO_EXPERIMENTAL));
957      __ jmp(&return_v0);
958    }
959  }
960
961  CodeDesc code_desc;
962  masm_->GetCode(isolate(), &code_desc);
963  Handle<Code> code =
964      Factory::CodeBuilder(isolate(), code_desc, CodeKind::REGEXP)
965          .set_self_reference(masm_->CodeObject())
966          .Build();
967  LOG(masm_->isolate(),
968      RegExpCodeCreateEvent(Handle<AbstractCode>::cast(code), source));
969  return Handle<HeapObject>::cast(code);
970}
971
972void RegExpMacroAssemblerLOONG64::GoTo(Label* to) {
973  if (to == nullptr) {
974    Backtrack();
975    return;
976  }
977  __ jmp(to);
978  return;
979}
980
981void RegExpMacroAssemblerLOONG64::IfRegisterGE(int reg, int comparand,
982                                               Label* if_ge) {
983  __ Ld_d(a0, register_location(reg));
984  BranchOrBacktrack(if_ge, ge, a0, Operand(comparand));
985}
986
987void RegExpMacroAssemblerLOONG64::IfRegisterLT(int reg, int comparand,
988                                               Label* if_lt) {
989  __ Ld_d(a0, register_location(reg));
990  BranchOrBacktrack(if_lt, lt, a0, Operand(comparand));
991}
992
993void RegExpMacroAssemblerLOONG64::IfRegisterEqPos(int reg, Label* if_eq) {
994  __ Ld_d(a0, register_location(reg));
995  BranchOrBacktrack(if_eq, eq, a0, Operand(current_input_offset()));
996}
997
998RegExpMacroAssembler::IrregexpImplementation
999RegExpMacroAssemblerLOONG64::Implementation() {
1000  return kLOONG64Implementation;
1001}
1002
1003void RegExpMacroAssemblerLOONG64::PopCurrentPosition() {
1004  Pop(current_input_offset());
1005}
1006
1007void RegExpMacroAssemblerLOONG64::PopRegister(int register_index) {
1008  Pop(a0);
1009  __ St_d(a0, register_location(register_index));
1010}
1011
1012void RegExpMacroAssemblerLOONG64::PushBacktrack(Label* label) {
1013  if (label->is_bound()) {
1014    int target = label->pos();
1015    __ li(a0, Operand(target + Code::kHeaderSize - kHeapObjectTag));
1016  } else {
1017    Assembler::BlockTrampolinePoolScope block_trampoline_pool(masm_.get());
1018    Label after_constant;
1019    __ Branch(&after_constant);
1020    int offset = masm_->pc_offset();
1021    int cp_offset = offset + Code::kHeaderSize - kHeapObjectTag;
1022    //__ emit(0);
1023    __ nop();
1024    masm_->label_at_put(label, offset);
1025    __ bind(&after_constant);
1026    if (is_int12(cp_offset)) {
1027      __ Ld_wu(a0, MemOperand(code_pointer(), cp_offset));
1028    } else {
1029      __ Add_d(a0, code_pointer(), cp_offset);
1030      __ Ld_wu(a0, MemOperand(a0, 0));
1031    }
1032  }
1033  Push(a0);
1034  CheckStackLimit();
1035}
1036
1037void RegExpMacroAssemblerLOONG64::PushCurrentPosition() {
1038  Push(current_input_offset());
1039}
1040
1041void RegExpMacroAssemblerLOONG64::PushRegister(
1042    int register_index, StackCheckFlag check_stack_limit) {
1043  __ Ld_d(a0, register_location(register_index));
1044  Push(a0);
1045  if (check_stack_limit) CheckStackLimit();
1046}
1047
1048void RegExpMacroAssemblerLOONG64::ReadCurrentPositionFromRegister(int reg) {
1049  __ Ld_d(current_input_offset(), register_location(reg));
1050}
1051
1052void RegExpMacroAssemblerLOONG64::WriteStackPointerToRegister(int reg) {
1053  ExternalReference stack_top_address =
1054      ExternalReference::address_of_regexp_stack_memory_top_address(isolate());
1055  __ li(a0, stack_top_address);
1056  __ Ld_d(a0, MemOperand(a0, 0));
1057  __ Sub_d(a0, backtrack_stackpointer(), a0);
1058  __ St_d(a0, register_location(reg));
1059}
1060
1061void RegExpMacroAssemblerLOONG64::ReadStackPointerFromRegister(int reg) {
1062  ExternalReference stack_top_address =
1063      ExternalReference::address_of_regexp_stack_memory_top_address(isolate());
1064  __ li(backtrack_stackpointer(), stack_top_address);
1065  __ Ld_d(backtrack_stackpointer(), MemOperand(backtrack_stackpointer(), 0));
1066  __ Ld_d(a0, register_location(reg));
1067  __ Add_d(backtrack_stackpointer(), backtrack_stackpointer(), Operand(a0));
1068}
1069
1070void RegExpMacroAssemblerLOONG64::SetCurrentPositionFromEnd(int by) {
1071  Label after_position;
1072  __ Branch(&after_position, ge, current_input_offset(),
1073            Operand(-by * char_size()));
1074  __ li(current_input_offset(), -by * char_size());
1075  // On RegExp code entry (where this operation is used), the character before
1076  // the current position is expected to be already loaded.
1077  // We have advanced the position, so it's safe to read backwards.
1078  LoadCurrentCharacterUnchecked(-1, 1);
1079  __ bind(&after_position);
1080}
1081
1082void RegExpMacroAssemblerLOONG64::SetRegister(int register_index, int to) {
1083  DCHECK(register_index >= num_saved_registers_);  // Reserved for positions!
1084  __ li(a0, Operand(to));
1085  __ St_d(a0, register_location(register_index));
1086}
1087
1088bool RegExpMacroAssemblerLOONG64::Succeed() {
1089  __ jmp(&success_label_);
1090  return global();
1091}
1092
1093void RegExpMacroAssemblerLOONG64::WriteCurrentPositionToRegister(
1094    int reg, int cp_offset) {
1095  if (cp_offset == 0) {
1096    __ St_d(current_input_offset(), register_location(reg));
1097  } else {
1098    __ Add_d(a0, current_input_offset(), Operand(cp_offset * char_size()));
1099    __ St_d(a0, register_location(reg));
1100  }
1101}
1102
1103void RegExpMacroAssemblerLOONG64::ClearRegisters(int reg_from, int reg_to) {
1104  DCHECK(reg_from <= reg_to);
1105  __ Ld_d(a0, MemOperand(frame_pointer(), kStringStartMinusOne));
1106  for (int reg = reg_from; reg <= reg_to; reg++) {
1107    __ St_d(a0, register_location(reg));
1108  }
1109}
1110
1111// Private methods:
1112
1113void RegExpMacroAssemblerLOONG64::CallCheckStackGuardState(Register scratch) {
1114  DCHECK(!isolate()->IsGeneratingEmbeddedBuiltins());
1115  DCHECK(!masm_->options().isolate_independent_code);
1116
1117  int stack_alignment = base::OS::ActivationFrameAlignment();
1118
1119  // Align the stack pointer and save the original sp value on the stack.
1120  __ mov(scratch, sp);
1121  __ Sub_d(sp, sp, Operand(kPointerSize));
1122  DCHECK(base::bits::IsPowerOfTwo(stack_alignment));
1123  __ And(sp, sp, Operand(-stack_alignment));
1124  __ St_d(scratch, MemOperand(sp, 0));
1125
1126  __ mov(a2, frame_pointer());
1127  // Code of self.
1128  __ li(a1, Operand(masm_->CodeObject()), CONSTANT_SIZE);
1129
1130  // We need to make room for the return address on the stack.
1131  DCHECK(IsAligned(stack_alignment, kPointerSize));
1132  __ Sub_d(sp, sp, Operand(stack_alignment));
1133
1134  // The stack pointer now points to cell where the return address will be
1135  // written. Arguments are in registers, meaning we treat the return address as
1136  // argument 5. Since DirectCEntry will handle allocating space for the C
1137  // argument slots, we don't need to care about that here. This is how the
1138  // stack will look (sp meaning the value of sp at this moment):
1139  // [sp + 3] - empty slot if needed for alignment.
1140  // [sp + 2] - saved sp.
1141  // [sp + 1] - second word reserved for return value.
1142  // [sp + 0] - first word reserved for return value.
1143
1144  // a0 will point to the return address, placed by DirectCEntry.
1145  __ mov(a0, sp);
1146
1147  ExternalReference stack_guard_check =
1148      ExternalReference::re_check_stack_guard_state();
1149  __ li(t7, Operand(stack_guard_check));
1150
1151  EmbeddedData d = EmbeddedData::FromBlob();
1152  CHECK(Builtins::IsIsolateIndependent(Builtin::kDirectCEntry));
1153  Address entry = d.InstructionStartOfBuiltin(Builtin::kDirectCEntry);
1154  __ li(kScratchReg, Operand(entry, RelocInfo::OFF_HEAP_TARGET));
1155  __ Call(kScratchReg);
1156
1157  // DirectCEntry allocated space for the C argument slots so we have to
1158  // drop them with the return address from the stack with loading saved sp.
1159  // At this point stack must look:
1160  // [sp + 7] - empty slot if needed for alignment.
1161  // [sp + 6] - saved sp.
1162  // [sp + 5] - second word reserved for return value.
1163  // [sp + 4] - first word reserved for return value.
1164  // [sp + 3] - C argument slot.
1165  // [sp + 2] - C argument slot.
1166  // [sp + 1] - C argument slot.
1167  // [sp + 0] - C argument slot.
1168  __ Ld_d(sp, MemOperand(sp, stack_alignment));
1169
1170  __ li(code_pointer(), Operand(masm_->CodeObject()));
1171}
1172
1173// Helper function for reading a value out of a stack frame.
1174template <typename T>
1175static T& frame_entry(Address re_frame, int frame_offset) {
1176  return reinterpret_cast<T&>(Memory<int32_t>(re_frame + frame_offset));
1177}
1178
1179template <typename T>
1180static T* frame_entry_address(Address re_frame, int frame_offset) {
1181  return reinterpret_cast<T*>(re_frame + frame_offset);
1182}
1183
1184int64_t RegExpMacroAssemblerLOONG64::CheckStackGuardState(
1185    Address* return_address, Address raw_code, Address re_frame) {
1186  Code re_code = Code::cast(Object(raw_code));
1187  return NativeRegExpMacroAssembler::CheckStackGuardState(
1188      frame_entry<Isolate*>(re_frame, kIsolate),
1189      static_cast<int>(frame_entry<int64_t>(re_frame, kStartIndex)),
1190      static_cast<RegExp::CallOrigin>(
1191          frame_entry<int64_t>(re_frame, kDirectCall)),
1192      return_address, re_code,
1193      frame_entry_address<Address>(re_frame, kInputString),
1194      frame_entry_address<const byte*>(re_frame, kInputStart),
1195      frame_entry_address<const byte*>(re_frame, kInputEnd));
1196}
1197
1198MemOperand RegExpMacroAssemblerLOONG64::register_location(int register_index) {
1199  DCHECK(register_index < (1 << 30));
1200  if (num_registers_ <= register_index) {
1201    num_registers_ = register_index + 1;
1202  }
1203  return MemOperand(frame_pointer(),
1204                    kRegisterZero - register_index * kPointerSize);
1205}
1206
1207void RegExpMacroAssemblerLOONG64::CheckPosition(int cp_offset,
1208                                                Label* on_outside_input) {
1209  if (cp_offset >= 0) {
1210    BranchOrBacktrack(on_outside_input, ge, current_input_offset(),
1211                      Operand(-cp_offset * char_size()));
1212  } else {
1213    __ Ld_d(a1, MemOperand(frame_pointer(), kStringStartMinusOne));
1214    __ Add_d(a0, current_input_offset(), Operand(cp_offset * char_size()));
1215    BranchOrBacktrack(on_outside_input, le, a0, Operand(a1));
1216  }
1217}
1218
1219void RegExpMacroAssemblerLOONG64::BranchOrBacktrack(Label* to,
1220                                                    Condition condition,
1221                                                    Register rs,
1222                                                    const Operand& rt) {
1223  if (condition == al) {  // Unconditional.
1224    if (to == nullptr) {
1225      Backtrack();
1226      return;
1227    }
1228    __ jmp(to);
1229    return;
1230  }
1231  if (to == nullptr) {
1232    __ Branch(&backtrack_label_, condition, rs, rt);
1233    return;
1234  }
1235  __ Branch(to, condition, rs, rt);
1236}
1237
1238void RegExpMacroAssemblerLOONG64::SafeCall(Label* to, Condition cond,
1239                                           Register rs, const Operand& rt) {
1240  __ Branch(to, cond, rs, rt, true);
1241}
1242
1243void RegExpMacroAssemblerLOONG64::SafeReturn() {
1244  __ Pop(ra);
1245  __ Add_d(t1, ra, Operand(masm_->CodeObject()));
1246  __ Jump(t1);
1247}
1248
1249void RegExpMacroAssemblerLOONG64::SafeCallTarget(Label* name) {
1250  __ bind(name);
1251  __ Sub_d(ra, ra, Operand(masm_->CodeObject()));
1252  __ Push(ra);
1253}
1254
1255void RegExpMacroAssemblerLOONG64::Push(Register source) {
1256  DCHECK(source != backtrack_stackpointer());
1257  __ Add_d(backtrack_stackpointer(), backtrack_stackpointer(),
1258           Operand(-kIntSize));
1259  __ St_w(source, MemOperand(backtrack_stackpointer(), 0));
1260}
1261
1262void RegExpMacroAssemblerLOONG64::Pop(Register target) {
1263  DCHECK(target != backtrack_stackpointer());
1264  __ Ld_w(target, MemOperand(backtrack_stackpointer(), 0));
1265  __ Add_d(backtrack_stackpointer(), backtrack_stackpointer(), kIntSize);
1266}
1267
1268void RegExpMacroAssemblerLOONG64::CheckPreemption() {
1269  // Check for preemption.
1270  ExternalReference stack_limit =
1271      ExternalReference::address_of_jslimit(masm_->isolate());
1272  __ li(a0, Operand(stack_limit));
1273  __ Ld_d(a0, MemOperand(a0, 0));
1274  SafeCall(&check_preempt_label_, ls, sp, Operand(a0));
1275}
1276
1277void RegExpMacroAssemblerLOONG64::CheckStackLimit() {
1278  ExternalReference stack_limit =
1279      ExternalReference::address_of_regexp_stack_limit_address(
1280          masm_->isolate());
1281
1282  __ li(a0, Operand(stack_limit));
1283  __ Ld_d(a0, MemOperand(a0, 0));
1284  SafeCall(&stack_overflow_label_, ls, backtrack_stackpointer(), Operand(a0));
1285}
1286
1287void RegExpMacroAssemblerLOONG64::LoadCurrentCharacterUnchecked(
1288    int cp_offset, int characters) {
1289  Register offset = current_input_offset();
1290
1291  // If unaligned load/stores are not supported then this function must only
1292  // be used to load a single character at a time.
1293  if (!CanReadUnaligned()) {
1294    DCHECK_EQ(1, characters);
1295  }
1296
1297  if (cp_offset != 0) {
1298    // t3 is not being used to store the capture start index at this point.
1299    __ Add_d(t3, current_input_offset(), Operand(cp_offset * char_size()));
1300    offset = t3;
1301  }
1302
1303  if (mode_ == LATIN1) {
1304    if (characters == 4) {
1305      __ Ld_wu(current_character(), MemOperand(end_of_input_address(), offset));
1306    } else if (characters == 2) {
1307      __ Ld_hu(current_character(), MemOperand(end_of_input_address(), offset));
1308    } else {
1309      DCHECK_EQ(1, characters);
1310      __ Ld_bu(current_character(), MemOperand(end_of_input_address(), offset));
1311    }
1312  } else {
1313    DCHECK(mode_ == UC16);
1314    if (characters == 2) {
1315      __ Ld_wu(current_character(), MemOperand(end_of_input_address(), offset));
1316    } else {
1317      DCHECK_EQ(1, characters);
1318      __ Ld_hu(current_character(), MemOperand(end_of_input_address(), offset));
1319    }
1320  }
1321}
1322
1323#undef __
1324
1325}  // namespace internal
1326}  // namespace v8
1327
1328#endif  // V8_TARGET_ARCH_LOONG64
1329