• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #include "src/codegen/assembler-inl.h"
6 #include "src/codegen/callable.h"
7 #include "src/codegen/loong64/constants-loong64.h"
8 #include "src/codegen/macro-assembler.h"
9 #include "src/codegen/optimized-compilation-info.h"
10 #include "src/compiler/backend/code-generator-impl.h"
11 #include "src/compiler/backend/code-generator.h"
12 #include "src/compiler/backend/gap-resolver.h"
13 #include "src/compiler/node-matchers.h"
14 #include "src/compiler/osr.h"
15 #include "src/heap/memory-chunk.h"
16 
17 #if V8_ENABLE_WEBASSEMBLY
18 #include "src/wasm/wasm-code-manager.h"
19 #endif  // V8_ENABLE_WEBASSEMBLY
20 
21 namespace v8 {
22 namespace internal {
23 namespace compiler {
24 
25 #define __ tasm()->
26 
27 // TODO(LOONG_dev): consider renaming these macros.
28 #define TRACE_MSG(msg)                                                      \
29   PrintF("code_gen: \'%s\' in function %s at line %d\n", msg, __FUNCTION__, \
30          __LINE__)
31 
32 #define TRACE_UNIMPL()                                            \
33   PrintF("UNIMPLEMENTED code_generator_loong64: %s at line %d\n", \
34          __FUNCTION__, __LINE__)
35 
36 // Adds Loong64-specific methods to convert InstructionOperands.
37 class Loong64OperandConverter final : public InstructionOperandConverter {
38  public:
Loong64OperandConverter(CodeGenerator * gen,Instruction * instr)39   Loong64OperandConverter(CodeGenerator* gen, Instruction* instr)
40       : InstructionOperandConverter(gen, instr) {}
41 
OutputSingleRegister(size_t index=0)42   FloatRegister OutputSingleRegister(size_t index = 0) {
43     return ToSingleRegister(instr_->OutputAt(index));
44   }
45 
InputSingleRegister(size_t index)46   FloatRegister InputSingleRegister(size_t index) {
47     return ToSingleRegister(instr_->InputAt(index));
48   }
49 
ToSingleRegister(InstructionOperand * op)50   FloatRegister ToSingleRegister(InstructionOperand* op) {
51     // Single (Float) and Double register namespace is same on LOONG64,
52     // both are typedefs of FPURegister.
53     return ToDoubleRegister(op);
54   }
55 
InputOrZeroRegister(size_t index)56   Register InputOrZeroRegister(size_t index) {
57     if (instr_->InputAt(index)->IsImmediate()) {
58       DCHECK_EQ(0, InputInt32(index));
59       return zero_reg;
60     }
61     return InputRegister(index);
62   }
63 
InputOrZeroDoubleRegister(size_t index)64   DoubleRegister InputOrZeroDoubleRegister(size_t index) {
65     if (instr_->InputAt(index)->IsImmediate()) return kDoubleRegZero;
66 
67     return InputDoubleRegister(index);
68   }
69 
InputOrZeroSingleRegister(size_t index)70   DoubleRegister InputOrZeroSingleRegister(size_t index) {
71     if (instr_->InputAt(index)->IsImmediate()) return kDoubleRegZero;
72 
73     return InputSingleRegister(index);
74   }
75 
InputImmediate(size_t index)76   Operand InputImmediate(size_t index) {
77     Constant constant = ToConstant(instr_->InputAt(index));
78     switch (constant.type()) {
79       case Constant::kInt32:
80         return Operand(constant.ToInt32());
81       case Constant::kInt64:
82         return Operand(constant.ToInt64());
83       case Constant::kFloat32:
84         return Operand::EmbeddedNumber(constant.ToFloat32());
85       case Constant::kFloat64:
86         return Operand::EmbeddedNumber(constant.ToFloat64().value());
87       case Constant::kExternalReference:
88       case Constant::kCompressedHeapObject:
89       case Constant::kHeapObject:
90         break;
91       case Constant::kDelayedStringConstant:
92         return Operand::EmbeddedStringConstant(
93             constant.ToDelayedStringConstant());
94       case Constant::kRpoNumber:
95         UNREACHABLE();  // TODO(titzer): RPO immediates on loong64?
96     }
97     UNREACHABLE();
98   }
99 
InputOperand(size_t index)100   Operand InputOperand(size_t index) {
101     InstructionOperand* op = instr_->InputAt(index);
102     if (op->IsRegister()) {
103       return Operand(ToRegister(op));
104     }
105     return InputImmediate(index);
106   }
107 
MemoryOperand(size_t * first_index)108   MemOperand MemoryOperand(size_t* first_index) {
109     const size_t index = *first_index;
110     switch (AddressingModeField::decode(instr_->opcode())) {
111       case kMode_None:
112         break;
113       case kMode_Root:
114         *first_index += 1;
115         return MemOperand(kRootRegister, InputInt32(index));
116       case kMode_MRI:
117         *first_index += 2;
118         return MemOperand(InputRegister(index + 0), InputInt32(index + 1));
119       case kMode_MRR:
120         *first_index += 2;
121         return MemOperand(InputRegister(index + 0), InputRegister(index + 1));
122     }
123     UNREACHABLE();
124   }
125 
MemoryOperand(size_t index=0)126   MemOperand MemoryOperand(size_t index = 0) { return MemoryOperand(&index); }
127 
ToMemOperand(InstructionOperand * op) const128   MemOperand ToMemOperand(InstructionOperand* op) const {
129     DCHECK_NOT_NULL(op);
130     DCHECK(op->IsStackSlot() || op->IsFPStackSlot());
131     return SlotToMemOperand(AllocatedOperand::cast(op)->index());
132   }
133 
SlotToMemOperand(int slot) const134   MemOperand SlotToMemOperand(int slot) const {
135     FrameOffset offset = frame_access_state()->GetFrameOffset(slot);
136     return MemOperand(offset.from_stack_pointer() ? sp : fp, offset.offset());
137   }
138 };
139 
HasRegisterInput(Instruction * instr,size_t index)140 static inline bool HasRegisterInput(Instruction* instr, size_t index) {
141   return instr->InputAt(index)->IsRegister();
142 }
143 
144 namespace {
145 
146 class OutOfLineRecordWrite final : public OutOfLineCode {
147  public:
OutOfLineRecordWrite(CodeGenerator * gen,Register object,Operand offset,Register value,RecordWriteMode mode,StubCallMode stub_mode)148   OutOfLineRecordWrite(CodeGenerator* gen, Register object, Operand offset,
149                        Register value, RecordWriteMode mode,
150                        StubCallMode stub_mode)
151       : OutOfLineCode(gen),
152         object_(object),
153         offset_(offset),
154         value_(value),
155         mode_(mode),
156 #if V8_ENABLE_WEBASSEMBLY
157         stub_mode_(stub_mode),
158 #endif  // V8_ENABLE_WEBASSEMBLY
159         must_save_lr_(!gen->frame_access_state()->has_frame()),
160         zone_(gen->zone()) {
161   }
162 
Generate()163   void Generate() final {
164     __ CheckPageFlag(value_, MemoryChunk::kPointersToHereAreInterestingMask, eq,
165                      exit());
166     RememberedSetAction const remembered_set_action =
167         mode_ > RecordWriteMode::kValueIsMap ||
168                 FLAG_use_full_record_write_builtin
169             ? RememberedSetAction::kEmit
170             : RememberedSetAction::kOmit;
171     SaveFPRegsMode const save_fp_mode = frame()->DidAllocateDoubleRegisters()
172                                             ? SaveFPRegsMode::kSave
173                                             : SaveFPRegsMode::kIgnore;
174     if (must_save_lr_) {
175       // We need to save and restore ra if the frame was elided.
176       __ Push(ra);
177     }
178     if (mode_ == RecordWriteMode::kValueIsEphemeronKey) {
179       __ CallEphemeronKeyBarrier(object_, offset_, save_fp_mode);
180 #if V8_ENABLE_WEBASSEMBLY
181     } else if (stub_mode_ == StubCallMode::kCallWasmRuntimeStub) {
182       // A direct call to a wasm runtime stub defined in this module.
183       // Just encode the stub index. This will be patched when the code
184       // is added to the native module and copied into wasm code space.
185       __ CallRecordWriteStubSaveRegisters(object_, offset_,
186                                           remembered_set_action, save_fp_mode,
187                                           StubCallMode::kCallWasmRuntimeStub);
188 #endif  // V8_ENABLE_WEBASSEMBLY
189     } else {
190       __ CallRecordWriteStubSaveRegisters(object_, offset_,
191                                           remembered_set_action, save_fp_mode);
192     }
193     if (must_save_lr_) {
194       __ Pop(ra);
195     }
196   }
197 
198  private:
199   Register const object_;
200   Operand const offset_;
201   Register const value_;
202   RecordWriteMode const mode_;
203 #if V8_ENABLE_WEBASSEMBLY
204   StubCallMode const stub_mode_;
205 #endif  // V8_ENABLE_WEBASSEMBLY
206   bool must_save_lr_;
207   Zone* zone_;
208 };
209 
210 #define CREATE_OOL_CLASS(ool_name, tasm_ool_name, T)                 \
211   class ool_name final : public OutOfLineCode {                      \
212    public:                                                           \
213     ool_name(CodeGenerator* gen, T dst, T src1, T src2)              \
214         : OutOfLineCode(gen), dst_(dst), src1_(src1), src2_(src2) {} \
215                                                                      \
216     void Generate() final { __ tasm_ool_name(dst_, src1_, src2_); }  \
217                                                                      \
218    private:                                                          \
219     T const dst_;                                                    \
220     T const src1_;                                                   \
221     T const src2_;                                                   \
222   }
223 
224 CREATE_OOL_CLASS(OutOfLineFloat32Max, Float32MaxOutOfLine, FPURegister);
225 CREATE_OOL_CLASS(OutOfLineFloat32Min, Float32MinOutOfLine, FPURegister);
226 CREATE_OOL_CLASS(OutOfLineFloat64Max, Float64MaxOutOfLine, FPURegister);
227 CREATE_OOL_CLASS(OutOfLineFloat64Min, Float64MinOutOfLine, FPURegister);
228 
229 #undef CREATE_OOL_CLASS
230 
FlagsConditionToConditionCmp(FlagsCondition condition)231 Condition FlagsConditionToConditionCmp(FlagsCondition condition) {
232   switch (condition) {
233     case kEqual:
234       return eq;
235     case kNotEqual:
236       return ne;
237     case kSignedLessThan:
238       return lt;
239     case kSignedGreaterThanOrEqual:
240       return ge;
241     case kSignedLessThanOrEqual:
242       return le;
243     case kSignedGreaterThan:
244       return gt;
245     case kUnsignedLessThan:
246       return lo;
247     case kUnsignedGreaterThanOrEqual:
248       return hs;
249     case kUnsignedLessThanOrEqual:
250       return ls;
251     case kUnsignedGreaterThan:
252       return hi;
253     case kUnorderedEqual:
254     case kUnorderedNotEqual:
255       break;
256     default:
257       break;
258   }
259   UNREACHABLE();
260 }
261 
FlagsConditionToConditionTst(FlagsCondition condition)262 Condition FlagsConditionToConditionTst(FlagsCondition condition) {
263   switch (condition) {
264     case kNotEqual:
265       return ne;
266     case kEqual:
267       return eq;
268     default:
269       break;
270   }
271   UNREACHABLE();
272 }
273 
FlagsConditionToConditionOvf(FlagsCondition condition)274 Condition FlagsConditionToConditionOvf(FlagsCondition condition) {
275   switch (condition) {
276     case kOverflow:
277       return ne;
278     case kNotOverflow:
279       return eq;
280     default:
281       break;
282   }
283   UNREACHABLE();
284 }
285 
FlagsConditionToConditionCmpFPU(bool * predicate,FlagsCondition condition)286 FPUCondition FlagsConditionToConditionCmpFPU(bool* predicate,
287                                              FlagsCondition condition) {
288   switch (condition) {
289     case kEqual:
290       *predicate = true;
291       return CEQ;
292     case kNotEqual:
293       *predicate = false;
294       return CEQ;
295     case kUnsignedLessThan:
296       *predicate = true;
297       return CLT;
298     case kUnsignedGreaterThanOrEqual:
299       *predicate = false;
300       return CLT;
301     case kUnsignedLessThanOrEqual:
302       *predicate = true;
303       return CLE;
304     case kUnsignedGreaterThan:
305       *predicate = false;
306       return CLE;
307     case kUnorderedEqual:
308     case kUnorderedNotEqual:
309       *predicate = true;
310       break;
311     default:
312       *predicate = true;
313       break;
314   }
315   UNREACHABLE();
316 }
317 
318 }  // namespace
319 
320 #define ASSEMBLE_ATOMIC_LOAD_INTEGER(asm_instr)          \
321   do {                                                   \
322     __ asm_instr(i.OutputRegister(), i.MemoryOperand()); \
323     __ dbar(0);                                          \
324   } while (0)
325 
326 // TODO(LOONG_dev): remove second dbar?
327 #define ASSEMBLE_ATOMIC_STORE_INTEGER(asm_instr)               \
328   do {                                                         \
329     __ dbar(0);                                                \
330     __ asm_instr(i.InputOrZeroRegister(2), i.MemoryOperand()); \
331     __ dbar(0);                                                \
332   } while (0)
333 
334 // only use for sub_w and sub_d
335 #define ASSEMBLE_ATOMIC_BINOP(load_linked, store_conditional, bin_instr)       \
336   do {                                                                         \
337     Label binop;                                                               \
338     __ Add_d(i.TempRegister(0), i.InputRegister(0), i.InputRegister(1));       \
339     __ dbar(0);                                                                \
340     __ bind(&binop);                                                           \
341     __ load_linked(i.OutputRegister(0), MemOperand(i.TempRegister(0), 0));     \
342     __ bin_instr(i.TempRegister(1), i.OutputRegister(0),                       \
343                  Operand(i.InputRegister(2)));                                 \
344     __ store_conditional(i.TempRegister(1), MemOperand(i.TempRegister(0), 0)); \
345     __ BranchShort(&binop, eq, i.TempRegister(1), Operand(zero_reg));          \
346     __ dbar(0);                                                                \
347   } while (0)
348 
349 // TODO(LOONG_dev): remove second dbar?
350 #define ASSEMBLE_ATOMIC_BINOP_EXT(load_linked, store_conditional, sign_extend, \
351                                   size, bin_instr, representation)             \
352   do {                                                                         \
353     Label binop;                                                               \
354     __ add_d(i.TempRegister(0), i.InputRegister(0), i.InputRegister(1));       \
355     if (representation == 32) {                                                \
356       __ andi(i.TempRegister(3), i.TempRegister(0), 0x3);                      \
357     } else {                                                                   \
358       DCHECK_EQ(representation, 64);                                           \
359       __ andi(i.TempRegister(3), i.TempRegister(0), 0x7);                      \
360     }                                                                          \
361     __ Sub_d(i.TempRegister(0), i.TempRegister(0),                             \
362              Operand(i.TempRegister(3)));                                      \
363     __ slli_w(i.TempRegister(3), i.TempRegister(3), 3);                        \
364     __ dbar(0);                                                                \
365     __ bind(&binop);                                                           \
366     __ load_linked(i.TempRegister(1), MemOperand(i.TempRegister(0), 0));       \
367     __ ExtractBits(i.OutputRegister(0), i.TempRegister(1), i.TempRegister(3),  \
368                    size, sign_extend);                                         \
369     __ bin_instr(i.TempRegister(2), i.OutputRegister(0),                       \
370                  Operand(i.InputRegister(2)));                                 \
371     __ InsertBits(i.TempRegister(1), i.TempRegister(2), i.TempRegister(3),     \
372                   size);                                                       \
373     __ store_conditional(i.TempRegister(1), MemOperand(i.TempRegister(0), 0)); \
374     __ BranchShort(&binop, eq, i.TempRegister(1), Operand(zero_reg));          \
375     __ dbar(0);                                                                \
376   } while (0)
377 
378 // TODO(LOONG_dev): remove second dbar?
379 #define ASSEMBLE_ATOMIC_EXCHANGE_INTEGER_EXT(                                  \
380     load_linked, store_conditional, sign_extend, size, representation)         \
381   do {                                                                         \
382     Label exchange;                                                            \
383     __ add_d(i.TempRegister(0), i.InputRegister(0), i.InputRegister(1));       \
384     if (representation == 32) {                                                \
385       __ andi(i.TempRegister(1), i.TempRegister(0), 0x3);                      \
386     } else {                                                                   \
387       DCHECK_EQ(representation, 64);                                           \
388       __ andi(i.TempRegister(1), i.TempRegister(0), 0x7);                      \
389     }                                                                          \
390     __ Sub_d(i.TempRegister(0), i.TempRegister(0),                             \
391              Operand(i.TempRegister(1)));                                      \
392     __ slli_w(i.TempRegister(1), i.TempRegister(1), 3);                        \
393     __ dbar(0);                                                                \
394     __ bind(&exchange);                                                        \
395     __ load_linked(i.TempRegister(2), MemOperand(i.TempRegister(0), 0));       \
396     __ ExtractBits(i.OutputRegister(0), i.TempRegister(2), i.TempRegister(1),  \
397                    size, sign_extend);                                         \
398     __ InsertBits(i.TempRegister(2), i.InputRegister(2), i.TempRegister(1),    \
399                   size);                                                       \
400     __ store_conditional(i.TempRegister(2), MemOperand(i.TempRegister(0), 0)); \
401     __ BranchShort(&exchange, eq, i.TempRegister(2), Operand(zero_reg));       \
402     __ dbar(0);                                                                \
403   } while (0)
404 
405 // TODO(LOONG_dev): remove second dbar?
406 #define ASSEMBLE_ATOMIC_COMPARE_EXCHANGE_INTEGER(load_linked,                  \
407                                                  store_conditional)            \
408   do {                                                                         \
409     Label compareExchange;                                                     \
410     Label exit;                                                                \
411     __ add_d(i.TempRegister(0), i.InputRegister(0), i.InputRegister(1));       \
412     __ dbar(0);                                                                \
413     __ bind(&compareExchange);                                                 \
414     __ load_linked(i.OutputRegister(0), MemOperand(i.TempRegister(0), 0));     \
415     __ BranchShort(&exit, ne, i.InputRegister(2),                              \
416                    Operand(i.OutputRegister(0)));                              \
417     __ mov(i.TempRegister(2), i.InputRegister(3));                             \
418     __ store_conditional(i.TempRegister(2), MemOperand(i.TempRegister(0), 0)); \
419     __ BranchShort(&compareExchange, eq, i.TempRegister(2),                    \
420                    Operand(zero_reg));                                         \
421     __ bind(&exit);                                                            \
422     __ dbar(0);                                                                \
423   } while (0)
424 
425 // TODO(LOONG_dev): remove second dbar?
426 #define ASSEMBLE_ATOMIC_COMPARE_EXCHANGE_INTEGER_EXT(                          \
427     load_linked, store_conditional, sign_extend, size, representation)         \
428   do {                                                                         \
429     Label compareExchange;                                                     \
430     Label exit;                                                                \
431     __ add_d(i.TempRegister(0), i.InputRegister(0), i.InputRegister(1));       \
432     if (representation == 32) {                                                \
433       __ andi(i.TempRegister(1), i.TempRegister(0), 0x3);                      \
434     } else {                                                                   \
435       DCHECK_EQ(representation, 64);                                           \
436       __ andi(i.TempRegister(1), i.TempRegister(0), 0x7);                      \
437     }                                                                          \
438     __ Sub_d(i.TempRegister(0), i.TempRegister(0),                             \
439              Operand(i.TempRegister(1)));                                      \
440     __ slli_w(i.TempRegister(1), i.TempRegister(1), 3);                        \
441     __ dbar(0);                                                                \
442     __ bind(&compareExchange);                                                 \
443     __ load_linked(i.TempRegister(2), MemOperand(i.TempRegister(0), 0));       \
444     __ ExtractBits(i.OutputRegister(0), i.TempRegister(2), i.TempRegister(1),  \
445                    size, sign_extend);                                         \
446     __ ExtractBits(i.TempRegister(2), i.InputRegister(2), zero_reg, size,      \
447                    sign_extend);                                               \
448     __ BranchShort(&exit, ne, i.TempRegister(2),                               \
449                    Operand(i.OutputRegister(0)));                              \
450     __ InsertBits(i.TempRegister(2), i.InputRegister(3), i.TempRegister(1),    \
451                   size);                                                       \
452     __ store_conditional(i.TempRegister(2), MemOperand(i.TempRegister(0), 0)); \
453     __ BranchShort(&compareExchange, eq, i.TempRegister(2),                    \
454                    Operand(zero_reg));                                         \
455     __ bind(&exit);                                                            \
456     __ dbar(0);                                                                \
457   } while (0)
458 
459 #define ASSEMBLE_IEEE754_BINOP(name)                                        \
460   do {                                                                      \
461     FrameScope scope(tasm(), StackFrame::MANUAL);                           \
462     UseScratchRegisterScope temps(tasm());                                  \
463     Register scratch = temps.Acquire();                                     \
464     __ PrepareCallCFunction(0, 2, scratch);                                 \
465     __ CallCFunction(ExternalReference::ieee754_##name##_function(), 0, 2); \
466   } while (0)
467 
468 #define ASSEMBLE_IEEE754_UNOP(name)                                         \
469   do {                                                                      \
470     FrameScope scope(tasm(), StackFrame::MANUAL);                           \
471     UseScratchRegisterScope temps(tasm());                                  \
472     Register scratch = temps.Acquire();                                     \
473     __ PrepareCallCFunction(0, 1, scratch);                                 \
474     __ CallCFunction(ExternalReference::ieee754_##name##_function(), 0, 1); \
475   } while (0)
476 
477 #define ASSEMBLE_F64X2_ARITHMETIC_BINOP(op)                     \
478   do {                                                          \
479     __ op(i.OutputSimd128Register(), i.InputSimd128Register(0), \
480           i.InputSimd128Register(1));                           \
481   } while (0)
482 
AssembleDeconstructFrame()483 void CodeGenerator::AssembleDeconstructFrame() {
484   __ mov(sp, fp);
485   __ Pop(ra, fp);
486 }
487 
AssemblePrepareTailCall()488 void CodeGenerator::AssemblePrepareTailCall() {
489   if (frame_access_state()->has_frame()) {
490     __ Ld_d(ra, MemOperand(fp, StandardFrameConstants::kCallerPCOffset));
491     __ Ld_d(fp, MemOperand(fp, StandardFrameConstants::kCallerFPOffset));
492   }
493   frame_access_state()->SetFrameAccessToSP();
494 }
495 
496 namespace {
497 
AdjustStackPointerForTailCall(TurboAssembler * tasm,FrameAccessState * state,int new_slot_above_sp,bool allow_shrinkage=true)498 void AdjustStackPointerForTailCall(TurboAssembler* tasm,
499                                    FrameAccessState* state,
500                                    int new_slot_above_sp,
501                                    bool allow_shrinkage = true) {
502   int current_sp_offset = state->GetSPToFPSlotCount() +
503                           StandardFrameConstants::kFixedSlotCountAboveFp;
504   int stack_slot_delta = new_slot_above_sp - current_sp_offset;
505   if (stack_slot_delta > 0) {
506     tasm->Sub_d(sp, sp, stack_slot_delta * kSystemPointerSize);
507     state->IncreaseSPDelta(stack_slot_delta);
508   } else if (allow_shrinkage && stack_slot_delta < 0) {
509     tasm->Add_d(sp, sp, -stack_slot_delta * kSystemPointerSize);
510     state->IncreaseSPDelta(stack_slot_delta);
511   }
512 }
513 
514 }  // namespace
515 
AssembleTailCallBeforeGap(Instruction * instr,int first_unused_slot_offset)516 void CodeGenerator::AssembleTailCallBeforeGap(Instruction* instr,
517                                               int first_unused_slot_offset) {
518   AdjustStackPointerForTailCall(tasm(), frame_access_state(),
519                                 first_unused_slot_offset, false);
520 }
521 
AssembleTailCallAfterGap(Instruction * instr,int first_unused_slot_offset)522 void CodeGenerator::AssembleTailCallAfterGap(Instruction* instr,
523                                              int first_unused_slot_offset) {
524   AdjustStackPointerForTailCall(tasm(), frame_access_state(),
525                                 first_unused_slot_offset);
526 }
527 
528 // Check that {kJavaScriptCallCodeStartRegister} is correct.
AssembleCodeStartRegisterCheck()529 void CodeGenerator::AssembleCodeStartRegisterCheck() {
530   UseScratchRegisterScope temps(tasm());
531   Register scratch = temps.Acquire();
532   __ ComputeCodeStartAddress(scratch);
533   __ Assert(eq, AbortReason::kWrongFunctionCodeStart,
534             kJavaScriptCallCodeStartRegister, Operand(scratch));
535 }
536 
537 // Check if the code object is marked for deoptimization. If it is, then it
538 // jumps to the CompileLazyDeoptimizedCode builtin. In order to do this we need
539 // to:
540 //    1. read from memory the word that contains that bit, which can be found in
541 //       the flags in the referenced {CodeDataContainer} object;
542 //    2. test kMarkedForDeoptimizationBit in those flags; and
543 //    3. if it is not zero then it jumps to the builtin.
BailoutIfDeoptimized()544 void CodeGenerator::BailoutIfDeoptimized() {
545   UseScratchRegisterScope temps(tasm());
546   Register scratch = temps.Acquire();
547   int offset = Code::kCodeDataContainerOffset - Code::kHeaderSize;
548   __ Ld_d(scratch, MemOperand(kJavaScriptCallCodeStartRegister, offset));
549   __ Ld_w(scratch, FieldMemOperand(
550                        scratch, CodeDataContainer::kKindSpecificFlagsOffset));
551   __ And(scratch, scratch, Operand(1 << Code::kMarkedForDeoptimizationBit));
552   __ Jump(BUILTIN_CODE(isolate(), CompileLazyDeoptimizedCode),
553           RelocInfo::CODE_TARGET, ne, scratch, Operand(zero_reg));
554 }
555 
556 // Assembles an instruction after register allocation, producing machine code.
AssembleArchInstruction(Instruction * instr)557 CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
558     Instruction* instr) {
559   Loong64OperandConverter i(this, instr);
560   InstructionCode opcode = instr->opcode();
561   ArchOpcode arch_opcode = ArchOpcodeField::decode(opcode);
562   switch (arch_opcode) {
563     case kArchCallCodeObject: {
564       if (instr->InputAt(0)->IsImmediate()) {
565         __ Call(i.InputCode(0), RelocInfo::CODE_TARGET);
566       } else {
567         Register reg = i.InputRegister(0);
568         DCHECK_IMPLIES(
569             instr->HasCallDescriptorFlag(CallDescriptor::kFixedTargetRegister),
570             reg == kJavaScriptCallCodeStartRegister);
571         __ CallCodeObject(reg);
572       }
573       RecordCallPosition(instr);
574       frame_access_state()->ClearSPDelta();
575       break;
576     }
577     case kArchCallBuiltinPointer: {
578       DCHECK(!instr->InputAt(0)->IsImmediate());
579       Register builtin_index = i.InputRegister(0);
580       __ CallBuiltinByIndex(builtin_index);
581       RecordCallPosition(instr);
582       frame_access_state()->ClearSPDelta();
583       break;
584     }
585 #if V8_ENABLE_WEBASSEMBLY
586     case kArchCallWasmFunction: {
587       if (instr->InputAt(0)->IsImmediate()) {
588         Constant constant = i.ToConstant(instr->InputAt(0));
589         Address wasm_code = static_cast<Address>(constant.ToInt64());
590         __ Call(wasm_code, constant.rmode());
591       } else {
592         __ Call(i.InputRegister(0));
593       }
594       RecordCallPosition(instr);
595       frame_access_state()->ClearSPDelta();
596       break;
597     }
598     case kArchTailCallWasm: {
599       if (instr->InputAt(0)->IsImmediate()) {
600         Constant constant = i.ToConstant(instr->InputAt(0));
601         Address wasm_code = static_cast<Address>(constant.ToInt64());
602         __ Jump(wasm_code, constant.rmode());
603       } else {
604         __ Jump(i.InputRegister(0));
605       }
606       frame_access_state()->ClearSPDelta();
607       frame_access_state()->SetFrameAccessToDefault();
608       break;
609     }
610 #endif  // V8_ENABLE_WEBASSEMBLY
611     case kArchTailCallCodeObject: {
612       if (instr->InputAt(0)->IsImmediate()) {
613         __ Jump(i.InputCode(0), RelocInfo::CODE_TARGET);
614       } else {
615         Register reg = i.InputRegister(0);
616         DCHECK_IMPLIES(
617             instr->HasCallDescriptorFlag(CallDescriptor::kFixedTargetRegister),
618             reg == kJavaScriptCallCodeStartRegister);
619         __ JumpCodeObject(reg);
620       }
621       frame_access_state()->ClearSPDelta();
622       frame_access_state()->SetFrameAccessToDefault();
623       break;
624     }
625     case kArchTailCallAddress: {
626       CHECK(!instr->InputAt(0)->IsImmediate());
627       Register reg = i.InputRegister(0);
628       DCHECK_IMPLIES(
629           instr->HasCallDescriptorFlag(CallDescriptor::kFixedTargetRegister),
630           reg == kJavaScriptCallCodeStartRegister);
631       __ Jump(reg);
632       frame_access_state()->ClearSPDelta();
633       frame_access_state()->SetFrameAccessToDefault();
634       break;
635     }
636     case kArchCallJSFunction: {
637       Register func = i.InputRegister(0);
638       if (FLAG_debug_code) {
639         UseScratchRegisterScope temps(tasm());
640         Register scratch = temps.Acquire();
641         // Check the function's context matches the context argument.
642         __ Ld_d(scratch, FieldMemOperand(func, JSFunction::kContextOffset));
643         __ Assert(eq, AbortReason::kWrongFunctionContext, cp, Operand(scratch));
644       }
645       static_assert(kJavaScriptCallCodeStartRegister == a2, "ABI mismatch");
646       __ Ld_d(a2, FieldMemOperand(func, JSFunction::kCodeOffset));
647       __ CallCodeObject(a2);
648       RecordCallPosition(instr);
649       frame_access_state()->ClearSPDelta();
650       break;
651     }
652     case kArchPrepareCallCFunction: {
653       UseScratchRegisterScope temps(tasm());
654       Register scratch = temps.Acquire();
655       int const num_parameters = MiscField::decode(instr->opcode());
656       __ PrepareCallCFunction(num_parameters, scratch);
657       // Frame alignment requires using FP-relative frame addressing.
658       frame_access_state()->SetFrameAccessToFP();
659       break;
660     }
661     case kArchSaveCallerRegisters: {
662       fp_mode_ =
663           static_cast<SaveFPRegsMode>(MiscField::decode(instr->opcode()));
664       DCHECK(fp_mode_ == SaveFPRegsMode::kIgnore ||
665              fp_mode_ == SaveFPRegsMode::kSave);
666       // kReturnRegister0 should have been saved before entering the stub.
667       int bytes = __ PushCallerSaved(fp_mode_, kReturnRegister0);
668       DCHECK(IsAligned(bytes, kSystemPointerSize));
669       DCHECK_EQ(0, frame_access_state()->sp_delta());
670       frame_access_state()->IncreaseSPDelta(bytes / kSystemPointerSize);
671       DCHECK(!caller_registers_saved_);
672       caller_registers_saved_ = true;
673       break;
674     }
675     case kArchRestoreCallerRegisters: {
676       DCHECK(fp_mode_ ==
677              static_cast<SaveFPRegsMode>(MiscField::decode(instr->opcode())));
678       DCHECK(fp_mode_ == SaveFPRegsMode::kIgnore ||
679              fp_mode_ == SaveFPRegsMode::kSave);
680       // Don't overwrite the returned value.
681       int bytes = __ PopCallerSaved(fp_mode_, kReturnRegister0);
682       frame_access_state()->IncreaseSPDelta(-(bytes / kSystemPointerSize));
683       DCHECK_EQ(0, frame_access_state()->sp_delta());
684       DCHECK(caller_registers_saved_);
685       caller_registers_saved_ = false;
686       break;
687     }
688     case kArchPrepareTailCall:
689       AssemblePrepareTailCall();
690       break;
691     case kArchCallCFunction: {
692       int const num_parameters = MiscField::decode(instr->opcode());
693 #if V8_ENABLE_WEBASSEMBLY
694       Label start_call;
695       bool isWasmCapiFunction =
696           linkage()->GetIncomingDescriptor()->IsWasmCapiFunction();
697       // from start_call to return address.
698       int offset = __ root_array_available() ? 36 : 80;  // 9 or 20 instrs
699 #endif  // V8_ENABLE_WEBASSEMBLY
700 #if V8_HOST_ARCH_LOONG64
701       if (FLAG_debug_code) {
702         offset += 12;  // see CallCFunction
703       }
704 #endif
705 #if V8_ENABLE_WEBASSEMBLY
706       if (isWasmCapiFunction) {
707         __ bind(&start_call);
708         __ pcaddi(t7, offset >> kInstrSizeLog2);
709         __ St_d(t7, MemOperand(fp, WasmExitFrameConstants::kCallingPCOffset));
710       }
711 #endif  // V8_ENABLE_WEBASSEMBLY
712       if (instr->InputAt(0)->IsImmediate()) {
713         ExternalReference ref = i.InputExternalReference(0);
714         __ CallCFunction(ref, num_parameters);
715       } else {
716         Register func = i.InputRegister(0);
717         __ CallCFunction(func, num_parameters);
718       }
719 #if V8_ENABLE_WEBASSEMBLY
720       if (isWasmCapiFunction) {
721         CHECK_EQ(offset, __ SizeOfCodeGeneratedSince(&start_call));
722         RecordSafepoint(instr->reference_map());
723       }
724 #endif  // V8_ENABLE_WEBASSEMBLY
725       frame_access_state()->SetFrameAccessToDefault();
726       // Ideally, we should decrement SP delta to match the change of stack
727       // pointer in CallCFunction. However, for certain architectures (e.g.
728       // ARM), there may be more strict alignment requirement, causing old SP
729       // to be saved on the stack. In those cases, we can not calculate the SP
730       // delta statically.
731       frame_access_state()->ClearSPDelta();
732       if (caller_registers_saved_) {
733         // Need to re-sync SP delta introduced in kArchSaveCallerRegisters.
734         // Here, we assume the sequence to be:
735         //   kArchSaveCallerRegisters;
736         //   kArchCallCFunction;
737         //   kArchRestoreCallerRegisters;
738         int bytes =
739             __ RequiredStackSizeForCallerSaved(fp_mode_, kReturnRegister0);
740         frame_access_state()->IncreaseSPDelta(bytes / kSystemPointerSize);
741       }
742       break;
743     }
744     case kArchJmp:
745       AssembleArchJump(i.InputRpo(0));
746       break;
747     case kArchBinarySearchSwitch:
748       AssembleArchBinarySearchSwitch(instr);
749       break;
750     case kArchTableSwitch:
751       AssembleArchTableSwitch(instr);
752       break;
753     case kArchAbortCSADcheck:
754       DCHECK(i.InputRegister(0) == a0);
755       {
756         // We don't actually want to generate a pile of code for this, so just
757         // claim there is a stack frame, without generating one.
758         FrameScope scope(tasm(), StackFrame::NO_FRAME_TYPE);
759         __ Call(isolate()->builtins()->code_handle(Builtin::kAbortCSADcheck),
760                 RelocInfo::CODE_TARGET);
761       }
762       __ stop();
763       break;
764     case kArchDebugBreak:
765       __ DebugBreak();
766       break;
767     case kArchComment:
768       __ RecordComment(reinterpret_cast<const char*>(i.InputInt64(0)));
769       break;
770     case kArchNop:
771     case kArchThrowTerminator:
772       // don't emit code for nops.
773       break;
774     case kArchDeoptimize: {
775       DeoptimizationExit* exit =
776           BuildTranslation(instr, -1, 0, 0, OutputFrameStateCombine::Ignore());
777       __ Branch(exit->label());
778       break;
779     }
780     case kArchRet:
781       AssembleReturn(instr->InputAt(0));
782       break;
783     case kArchStackPointerGreaterThan: {
784       Register lhs_register = sp;
785       uint32_t offset;
786       if (ShouldApplyOffsetToStackCheck(instr, &offset)) {
787         lhs_register = i.TempRegister(1);
788         __ Sub_d(lhs_register, sp, offset);
789       }
790       __ Sltu(i.TempRegister(0), i.InputRegister(0), lhs_register);
791       break;
792     }
793     case kArchStackCheckOffset:
794       __ Move(i.OutputRegister(), Smi::FromInt(GetStackCheckOffset()));
795       break;
796     case kArchFramePointer:
797       __ mov(i.OutputRegister(), fp);
798       break;
799     case kArchParentFramePointer:
800       if (frame_access_state()->has_frame()) {
801         __ Ld_d(i.OutputRegister(), MemOperand(fp, 0));
802       } else {
803         __ mov(i.OutputRegister(), fp);
804       }
805       break;
806     case kArchTruncateDoubleToI:
807       __ TruncateDoubleToI(isolate(), zone(), i.OutputRegister(),
808                            i.InputDoubleRegister(0), DetermineStubCallMode());
809       break;
810     case kArchStoreWithWriteBarrier:  // Fall through.
811     case kArchAtomicStoreWithWriteBarrier: {
812       RecordWriteMode mode =
813           static_cast<RecordWriteMode>(MiscField::decode(instr->opcode()));
814       AddressingMode addressing_mode =
815           AddressingModeField::decode(instr->opcode());
816       Register object = i.InputRegister(0);
817       Operand offset(zero_reg);
818       if (addressing_mode == kMode_MRI) {
819         offset = Operand(i.InputInt64(1));
820       } else {
821         DCHECK_EQ(addressing_mode, kMode_MRR);
822         offset = Operand(i.InputRegister(1));
823       }
824       Register value = i.InputRegister(2);
825 
826       auto ool = zone()->New<OutOfLineRecordWrite>(
827           this, object, offset, value, mode, DetermineStubCallMode());
828       if (arch_opcode == kArchStoreWithWriteBarrier) {
829         if (addressing_mode == kMode_MRI) {
830           __ St_d(value, MemOperand(object, i.InputInt64(1)));
831         } else {
832           DCHECK_EQ(addressing_mode, kMode_MRR);
833           __ St_d(value, MemOperand(object, i.InputRegister(1)));
834         }
835       } else {
836         DCHECK_EQ(kArchAtomicStoreWithWriteBarrier, arch_opcode);
837         DCHECK_EQ(addressing_mode, kMode_MRI);
838         UseScratchRegisterScope temps(tasm());
839         Register scratch = temps.Acquire();
840         __ Add_d(scratch, object, Operand(i.InputInt64(1)));
841         __ amswap_db_d(zero_reg, value, scratch);
842       }
843       if (mode > RecordWriteMode::kValueIsPointer) {
844         __ JumpIfSmi(value, ool->exit());
845       }
846       __ CheckPageFlag(object, MemoryChunk::kPointersFromHereAreInterestingMask,
847                        ne, ool->entry());
848       __ bind(ool->exit());
849       break;
850     }
851     case kArchStackSlot: {
852       UseScratchRegisterScope temps(tasm());
853       Register scratch = temps.Acquire();
854       FrameOffset offset =
855           frame_access_state()->GetFrameOffset(i.InputInt32(0));
856       Register base_reg = offset.from_stack_pointer() ? sp : fp;
857       __ Add_d(i.OutputRegister(), base_reg, Operand(offset.offset()));
858       if (FLAG_debug_code) {
859         // Verify that the output_register is properly aligned
860         __ And(scratch, i.OutputRegister(), Operand(kSystemPointerSize - 1));
861         __ Assert(eq, AbortReason::kAllocationIsNotDoubleAligned, scratch,
862                   Operand(zero_reg));
863       }
864       break;
865     }
866     case kIeee754Float64Acos:
867       ASSEMBLE_IEEE754_UNOP(acos);
868       break;
869     case kIeee754Float64Acosh:
870       ASSEMBLE_IEEE754_UNOP(acosh);
871       break;
872     case kIeee754Float64Asin:
873       ASSEMBLE_IEEE754_UNOP(asin);
874       break;
875     case kIeee754Float64Asinh:
876       ASSEMBLE_IEEE754_UNOP(asinh);
877       break;
878     case kIeee754Float64Atan:
879       ASSEMBLE_IEEE754_UNOP(atan);
880       break;
881     case kIeee754Float64Atanh:
882       ASSEMBLE_IEEE754_UNOP(atanh);
883       break;
884     case kIeee754Float64Atan2:
885       ASSEMBLE_IEEE754_BINOP(atan2);
886       break;
887     case kIeee754Float64Cos:
888       ASSEMBLE_IEEE754_UNOP(cos);
889       break;
890     case kIeee754Float64Cosh:
891       ASSEMBLE_IEEE754_UNOP(cosh);
892       break;
893     case kIeee754Float64Cbrt:
894       ASSEMBLE_IEEE754_UNOP(cbrt);
895       break;
896     case kIeee754Float64Exp:
897       ASSEMBLE_IEEE754_UNOP(exp);
898       break;
899     case kIeee754Float64Expm1:
900       ASSEMBLE_IEEE754_UNOP(expm1);
901       break;
902     case kIeee754Float64Log:
903       ASSEMBLE_IEEE754_UNOP(log);
904       break;
905     case kIeee754Float64Log1p:
906       ASSEMBLE_IEEE754_UNOP(log1p);
907       break;
908     case kIeee754Float64Log2:
909       ASSEMBLE_IEEE754_UNOP(log2);
910       break;
911     case kIeee754Float64Log10:
912       ASSEMBLE_IEEE754_UNOP(log10);
913       break;
914     case kIeee754Float64Pow:
915       ASSEMBLE_IEEE754_BINOP(pow);
916       break;
917     case kIeee754Float64Sin:
918       ASSEMBLE_IEEE754_UNOP(sin);
919       break;
920     case kIeee754Float64Sinh:
921       ASSEMBLE_IEEE754_UNOP(sinh);
922       break;
923     case kIeee754Float64Tan:
924       ASSEMBLE_IEEE754_UNOP(tan);
925       break;
926     case kIeee754Float64Tanh:
927       ASSEMBLE_IEEE754_UNOP(tanh);
928       break;
929     case kLoong64Add_w:
930       __ Add_w(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
931       break;
932     case kLoong64Add_d:
933       __ Add_d(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
934       break;
935     case kLoong64AddOvf_d:
936       __ AddOverflow_d(i.OutputRegister(), i.InputRegister(0),
937                        i.InputOperand(1), t8);
938       break;
939     case kLoong64Sub_w:
940       __ Sub_w(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
941       break;
942     case kLoong64Sub_d:
943       __ Sub_d(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
944       break;
945     case kLoong64SubOvf_d:
946       __ SubOverflow_d(i.OutputRegister(), i.InputRegister(0),
947                        i.InputOperand(1), t8);
948       break;
949     case kLoong64Mul_w:
950       __ Mul_w(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
951       break;
952     case kLoong64MulOvf_w:
953       __ MulOverflow_w(i.OutputRegister(), i.InputRegister(0),
954                        i.InputOperand(1), t8);
955       break;
956     case kLoong64Mulh_w:
957       __ Mulh_w(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
958       break;
959     case kLoong64Mulh_wu:
960       __ Mulh_wu(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
961       break;
962     case kLoong64Mulh_d:
963       __ Mulh_d(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
964       break;
965     case kLoong64Div_w:
966       __ Div_w(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
967       __ maskeqz(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1));
968       break;
969     case kLoong64Div_wu:
970       __ Div_wu(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
971       __ maskeqz(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1));
972       break;
973     case kLoong64Mod_w:
974       __ Mod_w(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
975       break;
976     case kLoong64Mod_wu:
977       __ Mod_wu(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
978       break;
979     case kLoong64Mul_d:
980       __ Mul_d(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
981       break;
982     case kLoong64Div_d:
983       __ Div_d(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
984       __ maskeqz(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1));
985       break;
986     case kLoong64Div_du:
987       __ Div_du(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
988       __ maskeqz(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1));
989       break;
990     case kLoong64Mod_d:
991       __ Mod_d(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
992       break;
993     case kLoong64Mod_du:
994       __ Mod_du(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
995       break;
996     case kLoong64Alsl_d:
997       DCHECK(instr->InputAt(2)->IsImmediate());
998       __ Alsl_d(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1),
999                 i.InputInt8(2), t7);
1000       break;
1001     case kLoong64Alsl_w:
1002       DCHECK(instr->InputAt(2)->IsImmediate());
1003       __ Alsl_w(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1),
1004                 i.InputInt8(2), t7);
1005       break;
1006     case kLoong64And:
1007     case kLoong64And32:
1008       __ And(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
1009       break;
1010     case kLoong64Or:
1011     case kLoong64Or32:
1012       __ Or(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
1013       break;
1014     case kLoong64Nor:
1015     case kLoong64Nor32:
1016       if (instr->InputAt(1)->IsRegister()) {
1017         __ Nor(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
1018       } else {
1019         DCHECK_EQ(0, i.InputOperand(1).immediate());
1020         __ Nor(i.OutputRegister(), i.InputRegister(0), zero_reg);
1021       }
1022       break;
1023     case kLoong64Xor:
1024     case kLoong64Xor32:
1025       __ Xor(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
1026       break;
1027     case kLoong64Clz_w:
1028       __ clz_w(i.OutputRegister(), i.InputRegister(0));
1029       break;
1030     case kLoong64Clz_d:
1031       __ clz_d(i.OutputRegister(), i.InputRegister(0));
1032       break;
1033     case kLoong64Sll_w:
1034       if (instr->InputAt(1)->IsRegister()) {
1035         __ sll_w(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1));
1036       } else {
1037         int64_t imm = i.InputOperand(1).immediate();
1038         __ slli_w(i.OutputRegister(), i.InputRegister(0),
1039                   static_cast<uint16_t>(imm));
1040       }
1041       break;
1042     case kLoong64Srl_w:
1043       if (instr->InputAt(1)->IsRegister()) {
1044         __ srl_w(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1));
1045       } else {
1046         int64_t imm = i.InputOperand(1).immediate();
1047         __ srli_w(i.OutputRegister(), i.InputRegister(0),
1048                   static_cast<uint16_t>(imm));
1049       }
1050       break;
1051     case kLoong64Sra_w:
1052       if (instr->InputAt(1)->IsRegister()) {
1053         __ sra_w(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1));
1054       } else {
1055         int64_t imm = i.InputOperand(1).immediate();
1056         __ srai_w(i.OutputRegister(), i.InputRegister(0),
1057                   static_cast<uint16_t>(imm));
1058       }
1059       break;
1060     case kLoong64Bstrpick_w:
1061       __ bstrpick_w(i.OutputRegister(), i.InputRegister(0),
1062                     i.InputInt8(1) + i.InputInt8(2) - 1, i.InputInt8(1));
1063       break;
1064     case kLoong64Bstrins_w:
1065       if (instr->InputAt(1)->IsImmediate() && i.InputInt8(1) == 0) {
1066         __ bstrins_w(i.OutputRegister(), zero_reg,
1067                      i.InputInt8(1) + i.InputInt8(2) - 1, i.InputInt8(1));
1068       } else {
1069         __ bstrins_w(i.OutputRegister(), i.InputRegister(0),
1070                      i.InputInt8(1) + i.InputInt8(2) - 1, i.InputInt8(1));
1071       }
1072       break;
1073     case kLoong64Bstrpick_d: {
1074       __ bstrpick_d(i.OutputRegister(), i.InputRegister(0),
1075                     i.InputInt8(1) + i.InputInt8(2) - 1, i.InputInt8(1));
1076       break;
1077     }
1078     case kLoong64Bstrins_d:
1079       if (instr->InputAt(1)->IsImmediate() && i.InputInt8(1) == 0) {
1080         __ bstrins_d(i.OutputRegister(), zero_reg,
1081                      i.InputInt8(1) + i.InputInt8(2) - 1, i.InputInt8(1));
1082       } else {
1083         __ bstrins_d(i.OutputRegister(), i.InputRegister(0),
1084                      i.InputInt8(1) + i.InputInt8(2) - 1, i.InputInt8(1));
1085       }
1086       break;
1087     case kLoong64Sll_d:
1088       if (instr->InputAt(1)->IsRegister()) {
1089         __ sll_d(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1));
1090       } else {
1091         int64_t imm = i.InputOperand(1).immediate();
1092         __ slli_d(i.OutputRegister(), i.InputRegister(0),
1093                   static_cast<uint16_t>(imm));
1094       }
1095       break;
1096     case kLoong64Srl_d:
1097       if (instr->InputAt(1)->IsRegister()) {
1098         __ srl_d(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1));
1099       } else {
1100         int64_t imm = i.InputOperand(1).immediate();
1101         __ srli_d(i.OutputRegister(), i.InputRegister(0),
1102                   static_cast<uint16_t>(imm));
1103       }
1104       break;
1105     case kLoong64Sra_d:
1106       if (instr->InputAt(1)->IsRegister()) {
1107         __ sra_d(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1));
1108       } else {
1109         int64_t imm = i.InputOperand(1).immediate();
1110         __ srai_d(i.OutputRegister(), i.InputRegister(0), imm);
1111       }
1112       break;
1113     case kLoong64Rotr_w:
1114       __ Rotr_w(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
1115       break;
1116     case kLoong64Rotr_d:
1117       __ Rotr_d(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
1118       break;
1119     case kLoong64Tst:
1120       __ And(t8, i.InputRegister(0), i.InputOperand(1));
1121       // Pseudo-instruction used for cmp/branch. No opcode emitted here.
1122       break;
1123     case kLoong64Cmp:
1124       // Pseudo-instruction used for cmp/branch. No opcode emitted here.
1125       break;
1126     case kLoong64Mov:
1127       // TODO(LOONG_dev): Should we combine mov/li, or use separate instr?
1128       //    - Also see x64 ASSEMBLE_BINOP & RegisterOrOperandType
1129       if (HasRegisterInput(instr, 0)) {
1130         __ mov(i.OutputRegister(), i.InputRegister(0));
1131       } else {
1132         __ li(i.OutputRegister(), i.InputOperand(0));
1133       }
1134       break;
1135 
1136     case kLoong64Float32Cmp: {
1137       FPURegister left = i.InputOrZeroSingleRegister(0);
1138       FPURegister right = i.InputOrZeroSingleRegister(1);
1139       bool predicate;
1140       FPUCondition cc =
1141           FlagsConditionToConditionCmpFPU(&predicate, instr->flags_condition());
1142 
1143       if ((left == kDoubleRegZero || right == kDoubleRegZero) &&
1144           !__ IsDoubleZeroRegSet()) {
1145         __ Move(kDoubleRegZero, 0.0);
1146       }
1147 
1148       __ CompareF32(left, right, cc);
1149     } break;
1150     case kLoong64Float32Add:
1151       __ fadd_s(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
1152                 i.InputDoubleRegister(1));
1153       break;
1154     case kLoong64Float32Sub:
1155       __ fsub_s(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
1156                 i.InputDoubleRegister(1));
1157       break;
1158     case kLoong64Float32Mul:
1159       __ fmul_s(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
1160                 i.InputDoubleRegister(1));
1161       break;
1162     case kLoong64Float32Div:
1163       __ fdiv_s(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
1164                 i.InputDoubleRegister(1));
1165       break;
1166     case kLoong64Float32Abs:
1167       __ fabs_s(i.OutputSingleRegister(), i.InputSingleRegister(0));
1168       break;
1169     case kLoong64Float32Neg:
1170       __ Neg_s(i.OutputSingleRegister(), i.InputSingleRegister(0));
1171       break;
1172     case kLoong64Float32Sqrt: {
1173       __ fsqrt_s(i.OutputDoubleRegister(), i.InputDoubleRegister(0));
1174       break;
1175     }
1176     case kLoong64Float32Min: {
1177       FPURegister dst = i.OutputSingleRegister();
1178       FPURegister src1 = i.InputSingleRegister(0);
1179       FPURegister src2 = i.InputSingleRegister(1);
1180       auto ool = zone()->New<OutOfLineFloat32Min>(this, dst, src1, src2);
1181       __ Float32Min(dst, src1, src2, ool->entry());
1182       __ bind(ool->exit());
1183       break;
1184     }
1185     case kLoong64Float32Max: {
1186       FPURegister dst = i.OutputSingleRegister();
1187       FPURegister src1 = i.InputSingleRegister(0);
1188       FPURegister src2 = i.InputSingleRegister(1);
1189       auto ool = zone()->New<OutOfLineFloat32Max>(this, dst, src1, src2);
1190       __ Float32Max(dst, src1, src2, ool->entry());
1191       __ bind(ool->exit());
1192       break;
1193     }
1194     case kLoong64Float64Cmp: {
1195       FPURegister left = i.InputOrZeroDoubleRegister(0);
1196       FPURegister right = i.InputOrZeroDoubleRegister(1);
1197       bool predicate;
1198       FPUCondition cc =
1199           FlagsConditionToConditionCmpFPU(&predicate, instr->flags_condition());
1200       if ((left == kDoubleRegZero || right == kDoubleRegZero) &&
1201           !__ IsDoubleZeroRegSet()) {
1202         __ Move(kDoubleRegZero, 0.0);
1203       }
1204 
1205       __ CompareF64(left, right, cc);
1206     } break;
1207     case kLoong64Float64Add:
1208       __ fadd_d(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
1209                 i.InputDoubleRegister(1));
1210       break;
1211     case kLoong64Float64Sub:
1212       __ fsub_d(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
1213                 i.InputDoubleRegister(1));
1214       break;
1215     case kLoong64Float64Mul:
1216       // TODO(LOONG_dev): LOONG64 add special case: right op is -1.0, see arm
1217       // port.
1218       __ fmul_d(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
1219                 i.InputDoubleRegister(1));
1220       break;
1221     case kLoong64Float64Div:
1222       __ fdiv_d(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
1223                 i.InputDoubleRegister(1));
1224       break;
1225     case kLoong64Float64Mod: {
1226       // TODO(turbofan): implement directly.
1227       FrameScope scope(tasm(), StackFrame::MANUAL);
1228       UseScratchRegisterScope temps(tasm());
1229       Register scratch = temps.Acquire();
1230       __ PrepareCallCFunction(0, 2, scratch);
1231       __ CallCFunction(ExternalReference::mod_two_doubles_operation(), 0, 2);
1232       break;
1233     }
1234     case kLoong64Float64Abs:
1235       __ fabs_d(i.OutputDoubleRegister(), i.InputDoubleRegister(0));
1236       break;
1237     case kLoong64Float64Neg:
1238       __ Neg_d(i.OutputDoubleRegister(), i.InputDoubleRegister(0));
1239       break;
1240     case kLoong64Float64Sqrt: {
1241       __ fsqrt_d(i.OutputDoubleRegister(), i.InputDoubleRegister(0));
1242       break;
1243     }
1244     case kLoong64Float64Min: {
1245       FPURegister dst = i.OutputDoubleRegister();
1246       FPURegister src1 = i.InputDoubleRegister(0);
1247       FPURegister src2 = i.InputDoubleRegister(1);
1248       auto ool = zone()->New<OutOfLineFloat64Min>(this, dst, src1, src2);
1249       __ Float64Min(dst, src1, src2, ool->entry());
1250       __ bind(ool->exit());
1251       break;
1252     }
1253     case kLoong64Float64Max: {
1254       FPURegister dst = i.OutputDoubleRegister();
1255       FPURegister src1 = i.InputDoubleRegister(0);
1256       FPURegister src2 = i.InputDoubleRegister(1);
1257       auto ool = zone()->New<OutOfLineFloat64Max>(this, dst, src1, src2);
1258       __ Float64Max(dst, src1, src2, ool->entry());
1259       __ bind(ool->exit());
1260       break;
1261     }
1262     case kLoong64Float64RoundDown: {
1263       __ Floor_d(i.OutputDoubleRegister(), i.InputDoubleRegister(0));
1264       break;
1265     }
1266     case kLoong64Float32RoundDown: {
1267       __ Floor_s(i.OutputSingleRegister(), i.InputSingleRegister(0));
1268       break;
1269     }
1270     case kLoong64Float64RoundTruncate: {
1271       __ Trunc_d(i.OutputDoubleRegister(), i.InputDoubleRegister(0));
1272       break;
1273     }
1274     case kLoong64Float32RoundTruncate: {
1275       __ Trunc_s(i.OutputSingleRegister(), i.InputSingleRegister(0));
1276       break;
1277     }
1278     case kLoong64Float64RoundUp: {
1279       __ Ceil_d(i.OutputDoubleRegister(), i.InputDoubleRegister(0));
1280       break;
1281     }
1282     case kLoong64Float32RoundUp: {
1283       __ Ceil_s(i.OutputSingleRegister(), i.InputSingleRegister(0));
1284       break;
1285     }
1286     case kLoong64Float64RoundTiesEven: {
1287       __ Round_d(i.OutputDoubleRegister(), i.InputDoubleRegister(0));
1288       break;
1289     }
1290     case kLoong64Float32RoundTiesEven: {
1291       __ Round_s(i.OutputSingleRegister(), i.InputSingleRegister(0));
1292       break;
1293     }
1294     case kLoong64Float64SilenceNaN:
1295       __ FPUCanonicalizeNaN(i.OutputDoubleRegister(), i.InputDoubleRegister(0));
1296       break;
1297     case kLoong64Float64ToFloat32:
1298       __ fcvt_s_d(i.OutputSingleRegister(), i.InputDoubleRegister(0));
1299       break;
1300     case kLoong64Float32ToFloat64:
1301       __ fcvt_d_s(i.OutputDoubleRegister(), i.InputSingleRegister(0));
1302       break;
1303     case kLoong64Int32ToFloat64: {
1304       FPURegister scratch = kScratchDoubleReg;
1305       __ movgr2fr_w(scratch, i.InputRegister(0));
1306       __ ffint_d_w(i.OutputDoubleRegister(), scratch);
1307       break;
1308     }
1309     case kLoong64Int32ToFloat32: {
1310       FPURegister scratch = kScratchDoubleReg;
1311       __ movgr2fr_w(scratch, i.InputRegister(0));
1312       __ ffint_s_w(i.OutputDoubleRegister(), scratch);
1313       break;
1314     }
1315     case kLoong64Uint32ToFloat32: {
1316       __ Ffint_s_uw(i.OutputDoubleRegister(), i.InputRegister(0));
1317       break;
1318     }
1319     case kLoong64Int64ToFloat32: {
1320       FPURegister scratch = kScratchDoubleReg;
1321       __ movgr2fr_d(scratch, i.InputRegister(0));
1322       __ ffint_s_l(i.OutputDoubleRegister(), scratch);
1323       break;
1324     }
1325     case kLoong64Int64ToFloat64: {
1326       FPURegister scratch = kScratchDoubleReg;
1327       __ movgr2fr_d(scratch, i.InputRegister(0));
1328       __ ffint_d_l(i.OutputDoubleRegister(), scratch);
1329       break;
1330     }
1331     case kLoong64Uint32ToFloat64: {
1332       __ Ffint_d_uw(i.OutputDoubleRegister(), i.InputRegister(0));
1333       break;
1334     }
1335     case kLoong64Uint64ToFloat64: {
1336       __ Ffint_d_ul(i.OutputDoubleRegister(), i.InputRegister(0));
1337       break;
1338     }
1339     case kLoong64Uint64ToFloat32: {
1340       __ Ffint_s_ul(i.OutputDoubleRegister(), i.InputRegister(0));
1341       break;
1342     }
1343     case kLoong64Float64ToInt32: {
1344       FPURegister scratch = kScratchDoubleReg;
1345       __ ftintrz_w_d(scratch, i.InputDoubleRegister(0));
1346       __ movfr2gr_s(i.OutputRegister(), scratch);
1347       break;
1348     }
1349     case kLoong64Float32ToInt32: {
1350       FPURegister scratch_d = kScratchDoubleReg;
1351       bool set_overflow_to_min_i32 = MiscField::decode(instr->opcode());
1352       __ ftintrz_w_s(scratch_d, i.InputDoubleRegister(0));
1353       __ movfr2gr_s(i.OutputRegister(), scratch_d);
1354       if (set_overflow_to_min_i32) {
1355         UseScratchRegisterScope temps(tasm());
1356         Register scratch = temps.Acquire();
1357         // Avoid INT32_MAX as an overflow indicator and use INT32_MIN instead,
1358         // because INT32_MIN allows easier out-of-bounds detection.
1359         __ addi_w(scratch, i.OutputRegister(), 1);
1360         __ slt(scratch, scratch, i.OutputRegister());
1361         __ add_w(i.OutputRegister(), i.OutputRegister(), scratch);
1362       }
1363       break;
1364     }
1365     case kLoong64Float32ToInt64: {
1366       FPURegister scratch_d = kScratchDoubleReg;
1367 
1368       bool load_status = instr->OutputCount() > 1;
1369       // Other arches use round to zero here, so we follow.
1370       __ ftintrz_l_s(scratch_d, i.InputDoubleRegister(0));
1371       __ movfr2gr_d(i.OutputRegister(), scratch_d);
1372       if (load_status) {
1373         Register output2 = i.OutputRegister(1);
1374         __ movfcsr2gr(output2, FCSR2);
1375         // Check for overflow and NaNs.
1376         __ And(output2, output2,
1377                kFCSROverflowCauseMask | kFCSRInvalidOpCauseMask);
1378         __ Slt(output2, zero_reg, output2);
1379         __ xori(output2, output2, 1);
1380       }
1381       break;
1382     }
1383     case kLoong64Float64ToInt64: {
1384       UseScratchRegisterScope temps(tasm());
1385       Register scratch = temps.Acquire();
1386       FPURegister scratch_d = kScratchDoubleReg;
1387 
1388       bool set_overflow_to_min_i64 = MiscField::decode(instr->opcode());
1389       bool load_status = instr->OutputCount() > 1;
1390       // Other arches use round to zero here, so we follow.
1391       __ ftintrz_l_d(scratch_d, i.InputDoubleRegister(0));
1392       __ movfr2gr_d(i.OutputRegister(0), scratch_d);
1393       if (load_status) {
1394         Register output2 = i.OutputRegister(1);
1395         __ movfcsr2gr(output2, FCSR2);
1396         // Check for overflow and NaNs.
1397         __ And(output2, output2,
1398                kFCSROverflowCauseMask | kFCSRInvalidOpCauseMask);
1399         __ Slt(output2, zero_reg, output2);
1400         __ xori(output2, output2, 1);
1401       }
1402       if (set_overflow_to_min_i64) {
1403         // Avoid INT64_MAX as an overflow indicator and use INT64_MIN instead,
1404         // because INT64_MIN allows easier out-of-bounds detection.
1405         __ addi_d(scratch, i.OutputRegister(), 1);
1406         __ slt(scratch, scratch, i.OutputRegister());
1407         __ add_d(i.OutputRegister(), i.OutputRegister(), scratch);
1408       }
1409       break;
1410     }
1411     case kLoong64Float64ToUint32: {
1412       FPURegister scratch = kScratchDoubleReg;
1413       __ Ftintrz_uw_d(i.OutputRegister(), i.InputDoubleRegister(0), scratch);
1414       break;
1415     }
1416     case kLoong64Float32ToUint32: {
1417       FPURegister scratch = kScratchDoubleReg;
1418       bool set_overflow_to_min_i32 = MiscField::decode(instr->opcode());
1419       __ Ftintrz_uw_s(i.OutputRegister(), i.InputDoubleRegister(0), scratch);
1420       if (set_overflow_to_min_i32) {
1421         UseScratchRegisterScope temps(tasm());
1422         Register scratch = temps.Acquire();
1423         // Avoid UINT32_MAX as an overflow indicator and use 0 instead,
1424         // because 0 allows easier out-of-bounds detection.
1425         __ addi_w(scratch, i.OutputRegister(), 1);
1426         __ Movz(i.OutputRegister(), zero_reg, scratch);
1427       }
1428       break;
1429     }
1430     case kLoong64Float32ToUint64: {
1431       FPURegister scratch = kScratchDoubleReg;
1432       Register result = instr->OutputCount() > 1 ? i.OutputRegister(1) : no_reg;
1433       __ Ftintrz_ul_s(i.OutputRegister(), i.InputDoubleRegister(0), scratch,
1434                       result);
1435       break;
1436     }
1437     case kLoong64Float64ToUint64: {
1438       FPURegister scratch = kScratchDoubleReg;
1439       Register result = instr->OutputCount() > 1 ? i.OutputRegister(1) : no_reg;
1440       __ Ftintrz_ul_d(i.OutputRegister(0), i.InputDoubleRegister(0), scratch,
1441                       result);
1442       break;
1443     }
1444     case kLoong64BitcastDL:
1445       __ movfr2gr_d(i.OutputRegister(), i.InputDoubleRegister(0));
1446       break;
1447     case kLoong64BitcastLD:
1448       __ movgr2fr_d(i.OutputDoubleRegister(), i.InputRegister(0));
1449       break;
1450     case kLoong64Float64ExtractLowWord32:
1451       __ FmoveLow(i.OutputRegister(), i.InputDoubleRegister(0));
1452       break;
1453     case kLoong64Float64ExtractHighWord32:
1454       __ movfrh2gr_s(i.OutputRegister(), i.InputDoubleRegister(0));
1455       break;
1456     case kLoong64Float64InsertLowWord32:
1457       __ FmoveLow(i.OutputDoubleRegister(), i.InputRegister(1));
1458       break;
1459     case kLoong64Float64InsertHighWord32:
1460       __ movgr2frh_w(i.OutputDoubleRegister(), i.InputRegister(1));
1461       break;
1462       // ... more basic instructions ...
1463 
1464     case kLoong64Ext_w_b:
1465       __ ext_w_b(i.OutputRegister(), i.InputRegister(0));
1466       break;
1467     case kLoong64Ext_w_h:
1468       __ ext_w_h(i.OutputRegister(), i.InputRegister(0));
1469       break;
1470     case kLoong64Ld_bu:
1471       __ Ld_bu(i.OutputRegister(), i.MemoryOperand());
1472       break;
1473     case kLoong64Ld_b:
1474       __ Ld_b(i.OutputRegister(), i.MemoryOperand());
1475       break;
1476     case kLoong64St_b:
1477       __ St_b(i.InputOrZeroRegister(2), i.MemoryOperand());
1478       break;
1479     case kLoong64Ld_hu:
1480       __ Ld_hu(i.OutputRegister(), i.MemoryOperand());
1481       break;
1482     case kLoong64Ld_h:
1483       __ Ld_h(i.OutputRegister(), i.MemoryOperand());
1484       break;
1485     case kLoong64St_h:
1486       __ St_h(i.InputOrZeroRegister(2), i.MemoryOperand());
1487       break;
1488     case kLoong64Ld_w:
1489       __ Ld_w(i.OutputRegister(), i.MemoryOperand());
1490       break;
1491     case kLoong64Ld_wu:
1492       __ Ld_wu(i.OutputRegister(), i.MemoryOperand());
1493       break;
1494     case kLoong64Ld_d:
1495       __ Ld_d(i.OutputRegister(), i.MemoryOperand());
1496       break;
1497     case kLoong64St_w:
1498       __ St_w(i.InputOrZeroRegister(2), i.MemoryOperand());
1499       break;
1500     case kLoong64St_d:
1501       __ St_d(i.InputOrZeroRegister(2), i.MemoryOperand());
1502       break;
1503     case kLoong64Fld_s: {
1504       __ Fld_s(i.OutputSingleRegister(), i.MemoryOperand());
1505       break;
1506     }
1507     case kLoong64Fst_s: {
1508       size_t index = 0;
1509       MemOperand operand = i.MemoryOperand(&index);
1510       FPURegister ft = i.InputOrZeroSingleRegister(index);
1511       if (ft == kDoubleRegZero && !__ IsDoubleZeroRegSet()) {
1512         __ Move(kDoubleRegZero, 0.0);
1513       }
1514 
1515       __ Fst_s(ft, operand);
1516       break;
1517     }
1518     case kLoong64Fld_d:
1519       __ Fld_d(i.OutputDoubleRegister(), i.MemoryOperand());
1520       break;
1521     case kLoong64Fst_d: {
1522       FPURegister ft = i.InputOrZeroDoubleRegister(2);
1523       if (ft == kDoubleRegZero && !__ IsDoubleZeroRegSet()) {
1524         __ Move(kDoubleRegZero, 0.0);
1525       }
1526 
1527       __ Fst_d(ft, i.MemoryOperand());
1528       break;
1529     }
1530     case kLoong64Dbar: {
1531       __ dbar(0);
1532       break;
1533     }
1534     case kLoong64Push:
1535       if (instr->InputAt(0)->IsFPRegister()) {
1536         __ Fst_d(i.InputDoubleRegister(0), MemOperand(sp, -kDoubleSize));
1537         __ Sub_d(sp, sp, Operand(kDoubleSize));
1538         frame_access_state()->IncreaseSPDelta(kDoubleSize / kSystemPointerSize);
1539       } else {
1540         __ Push(i.InputRegister(0));
1541         frame_access_state()->IncreaseSPDelta(1);
1542       }
1543       break;
1544     case kLoong64Peek: {
1545       int reverse_slot = i.InputInt32(0);
1546       int offset =
1547           FrameSlotToFPOffset(frame()->GetTotalFrameSlotCount() - reverse_slot);
1548       if (instr->OutputAt(0)->IsFPRegister()) {
1549         LocationOperand* op = LocationOperand::cast(instr->OutputAt(0));
1550         if (op->representation() == MachineRepresentation::kFloat64) {
1551           __ Fld_d(i.OutputDoubleRegister(), MemOperand(fp, offset));
1552         } else if (op->representation() == MachineRepresentation::kFloat32) {
1553           __ Fld_s(i.OutputSingleRegister(0), MemOperand(fp, offset));
1554         } else {
1555           DCHECK_EQ(MachineRepresentation::kSimd128, op->representation());
1556           abort();
1557         }
1558       } else {
1559         __ Ld_d(i.OutputRegister(0), MemOperand(fp, offset));
1560       }
1561       break;
1562     }
1563     case kLoong64StackClaim: {
1564       __ Sub_d(sp, sp, Operand(i.InputInt32(0)));
1565       frame_access_state()->IncreaseSPDelta(i.InputInt32(0) /
1566                                             kSystemPointerSize);
1567       break;
1568     }
1569     case kLoong64Poke: {
1570       if (instr->InputAt(0)->IsFPRegister()) {
1571         __ Fst_d(i.InputDoubleRegister(0), MemOperand(sp, i.InputInt32(1)));
1572       } else {
1573         __ St_d(i.InputRegister(0), MemOperand(sp, i.InputInt32(1)));
1574       }
1575       break;
1576     }
1577     case kLoong64ByteSwap64: {
1578       __ ByteSwapSigned(i.OutputRegister(0), i.InputRegister(0), 8);
1579       break;
1580     }
1581     case kLoong64ByteSwap32: {
1582       __ ByteSwapSigned(i.OutputRegister(0), i.InputRegister(0), 4);
1583       break;
1584     }
1585     case kAtomicLoadInt8:
1586       DCHECK_EQ(AtomicWidthField::decode(opcode), AtomicWidth::kWord32);
1587       ASSEMBLE_ATOMIC_LOAD_INTEGER(Ld_b);
1588       break;
1589     case kAtomicLoadUint8:
1590       ASSEMBLE_ATOMIC_LOAD_INTEGER(Ld_bu);
1591       break;
1592     case kAtomicLoadInt16:
1593       DCHECK_EQ(AtomicWidthField::decode(opcode), AtomicWidth::kWord32);
1594       ASSEMBLE_ATOMIC_LOAD_INTEGER(Ld_h);
1595       break;
1596     case kAtomicLoadUint16:
1597       ASSEMBLE_ATOMIC_LOAD_INTEGER(Ld_hu);
1598       break;
1599     case kAtomicLoadWord32:
1600       ASSEMBLE_ATOMIC_LOAD_INTEGER(Ld_w);
1601       break;
1602     case kLoong64Word64AtomicLoadUint32:
1603       ASSEMBLE_ATOMIC_LOAD_INTEGER(Ld_wu);
1604       break;
1605     case kLoong64Word64AtomicLoadUint64:
1606       ASSEMBLE_ATOMIC_LOAD_INTEGER(Ld_d);
1607       break;
1608     case kAtomicStoreWord8:
1609       ASSEMBLE_ATOMIC_STORE_INTEGER(St_b);
1610       break;
1611     case kAtomicStoreWord16:
1612       ASSEMBLE_ATOMIC_STORE_INTEGER(St_h);
1613       break;
1614     case kAtomicStoreWord32:
1615       ASSEMBLE_ATOMIC_STORE_INTEGER(St_w);
1616       break;
1617     case kLoong64StoreCompressTagged:
1618     case kLoong64Word64AtomicStoreWord64:
1619       ASSEMBLE_ATOMIC_STORE_INTEGER(St_d);
1620       break;
1621     case kAtomicExchangeInt8:
1622       DCHECK_EQ(AtomicWidthField::decode(opcode), AtomicWidth::kWord32);
1623       ASSEMBLE_ATOMIC_EXCHANGE_INTEGER_EXT(Ll_w, Sc_w, true, 8, 32);
1624       break;
1625     case kAtomicExchangeUint8:
1626       switch (AtomicWidthField::decode(opcode)) {
1627         case AtomicWidth::kWord32:
1628           ASSEMBLE_ATOMIC_EXCHANGE_INTEGER_EXT(Ll_w, Sc_w, false, 8, 32);
1629           break;
1630         case AtomicWidth::kWord64:
1631           ASSEMBLE_ATOMIC_EXCHANGE_INTEGER_EXT(Ll_d, Sc_d, false, 8, 64);
1632           break;
1633       }
1634       break;
1635     case kAtomicExchangeInt16:
1636       DCHECK_EQ(AtomicWidthField::decode(opcode), AtomicWidth::kWord32);
1637       ASSEMBLE_ATOMIC_EXCHANGE_INTEGER_EXT(Ll_w, Sc_w, true, 16, 32);
1638       break;
1639     case kAtomicExchangeUint16:
1640       switch (AtomicWidthField::decode(opcode)) {
1641         case AtomicWidth::kWord32:
1642           ASSEMBLE_ATOMIC_EXCHANGE_INTEGER_EXT(Ll_w, Sc_w, false, 16, 32);
1643           break;
1644         case AtomicWidth::kWord64:
1645           ASSEMBLE_ATOMIC_EXCHANGE_INTEGER_EXT(Ll_d, Sc_d, false, 16, 64);
1646           break;
1647       }
1648       break;
1649     case kAtomicExchangeWord32:
1650       switch (AtomicWidthField::decode(opcode)) {
1651         case AtomicWidth::kWord32:
1652           __ add_d(i.TempRegister(0), i.InputRegister(0), i.InputRegister(1));
1653           __ amswap_db_w(i.OutputRegister(0), i.InputRegister(2),
1654                          i.TempRegister(0));
1655           break;
1656         case AtomicWidth::kWord64:
1657           ASSEMBLE_ATOMIC_EXCHANGE_INTEGER_EXT(Ll_d, Sc_d, false, 32, 64);
1658           break;
1659       }
1660       break;
1661     case kLoong64Word64AtomicExchangeUint64:
1662       __ add_d(i.TempRegister(0), i.InputRegister(0), i.InputRegister(1));
1663       __ amswap_db_d(i.OutputRegister(0), i.InputRegister(2),
1664                      i.TempRegister(0));
1665       break;
1666     case kAtomicCompareExchangeInt8:
1667       DCHECK_EQ(AtomicWidthField::decode(opcode), AtomicWidth::kWord32);
1668       ASSEMBLE_ATOMIC_COMPARE_EXCHANGE_INTEGER_EXT(Ll_w, Sc_w, true, 8, 32);
1669       break;
1670     case kAtomicCompareExchangeUint8:
1671       switch (AtomicWidthField::decode(opcode)) {
1672         case AtomicWidth::kWord32:
1673           ASSEMBLE_ATOMIC_COMPARE_EXCHANGE_INTEGER_EXT(Ll_w, Sc_w, false, 8,
1674                                                        32);
1675           break;
1676         case AtomicWidth::kWord64:
1677           ASSEMBLE_ATOMIC_COMPARE_EXCHANGE_INTEGER_EXT(Ll_d, Sc_d, false, 8,
1678                                                        64);
1679           break;
1680       }
1681       break;
1682     case kAtomicCompareExchangeInt16:
1683       DCHECK_EQ(AtomicWidthField::decode(opcode), AtomicWidth::kWord32);
1684       ASSEMBLE_ATOMIC_COMPARE_EXCHANGE_INTEGER_EXT(Ll_w, Sc_w, true, 16, 32);
1685       break;
1686     case kAtomicCompareExchangeUint16:
1687       switch (AtomicWidthField::decode(opcode)) {
1688         case AtomicWidth::kWord32:
1689           ASSEMBLE_ATOMIC_COMPARE_EXCHANGE_INTEGER_EXT(Ll_w, Sc_w, false, 16,
1690                                                        32);
1691           break;
1692         case AtomicWidth::kWord64:
1693           ASSEMBLE_ATOMIC_COMPARE_EXCHANGE_INTEGER_EXT(Ll_d, Sc_d, false, 16,
1694                                                        64);
1695           break;
1696       }
1697       break;
1698     case kAtomicCompareExchangeWord32:
1699       switch (AtomicWidthField::decode(opcode)) {
1700         case AtomicWidth::kWord32:
1701           __ slli_w(i.InputRegister(2), i.InputRegister(2), 0);
1702           ASSEMBLE_ATOMIC_COMPARE_EXCHANGE_INTEGER(Ll_w, Sc_w);
1703           break;
1704         case AtomicWidth::kWord64:
1705           ASSEMBLE_ATOMIC_COMPARE_EXCHANGE_INTEGER_EXT(Ll_d, Sc_d, false, 32,
1706                                                        64);
1707           break;
1708       }
1709       break;
1710     case kLoong64Word64AtomicCompareExchangeUint64:
1711       ASSEMBLE_ATOMIC_COMPARE_EXCHANGE_INTEGER(Ll_d, Sc_d);
1712       break;
1713     case kAtomicAddWord32:
1714       switch (AtomicWidthField::decode(opcode)) {
1715         case AtomicWidth::kWord32:
1716           __ Add_d(i.TempRegister(0), i.InputRegister(0), i.InputRegister(1));
1717           __ amadd_db_w(i.OutputRegister(0), i.InputRegister(2),
1718                         i.TempRegister(0));
1719           break;
1720         case AtomicWidth::kWord64:
1721           ASSEMBLE_ATOMIC_BINOP_EXT(Ll_d, Sc_d, false, 32, Add_d, 64);
1722           break;
1723       }
1724       break;
1725     case kAtomicSubWord32:
1726       switch (AtomicWidthField::decode(opcode)) {
1727         case AtomicWidth::kWord32:
1728           ASSEMBLE_ATOMIC_BINOP(Ll_w, Sc_w, Sub_w);
1729           break;
1730         case AtomicWidth::kWord64:
1731           ASSEMBLE_ATOMIC_BINOP_EXT(Ll_d, Sc_d, false, 32, Sub_d, 64);
1732           break;
1733       }
1734       break;
1735     case kAtomicAndWord32:
1736       switch (AtomicWidthField::decode(opcode)) {
1737         case AtomicWidth::kWord32:
1738           __ Add_d(i.TempRegister(0), i.InputRegister(0), i.InputRegister(1));
1739           __ amand_db_w(i.OutputRegister(0), i.InputRegister(2),
1740                         i.TempRegister(0));
1741           break;
1742         case AtomicWidth::kWord64:
1743           ASSEMBLE_ATOMIC_BINOP_EXT(Ll_d, Sc_d, false, 32, And, 64);
1744           break;
1745       }
1746       break;
1747     case kAtomicOrWord32:
1748       switch (AtomicWidthField::decode(opcode)) {
1749         case AtomicWidth::kWord32:
1750           __ Add_d(i.TempRegister(0), i.InputRegister(0), i.InputRegister(1));
1751           __ amor_db_w(i.OutputRegister(0), i.InputRegister(2),
1752                        i.TempRegister(0));
1753           break;
1754         case AtomicWidth::kWord64:
1755           ASSEMBLE_ATOMIC_BINOP_EXT(Ll_d, Sc_d, false, 32, Or, 64);
1756           break;
1757       }
1758       break;
1759     case kAtomicXorWord32:
1760       switch (AtomicWidthField::decode(opcode)) {
1761         case AtomicWidth::kWord32:
1762           __ Add_d(i.TempRegister(0), i.InputRegister(0), i.InputRegister(1));
1763           __ amxor_db_w(i.OutputRegister(0), i.InputRegister(2),
1764                         i.TempRegister(0));
1765           break;
1766         case AtomicWidth::kWord64:
1767           ASSEMBLE_ATOMIC_BINOP_EXT(Ll_d, Sc_d, false, 32, Xor, 64);
1768           break;
1769       }
1770       break;
1771 #define ATOMIC_BINOP_CASE(op, inst32, inst64)                          \
1772   case kAtomic##op##Int8:                                              \
1773     DCHECK_EQ(AtomicWidthField::decode(opcode), AtomicWidth::kWord32); \
1774     ASSEMBLE_ATOMIC_BINOP_EXT(Ll_w, Sc_w, true, 8, inst32, 32);        \
1775     break;                                                             \
1776   case kAtomic##op##Uint8:                                             \
1777     switch (AtomicWidthField::decode(opcode)) {                        \
1778       case AtomicWidth::kWord32:                                       \
1779         ASSEMBLE_ATOMIC_BINOP_EXT(Ll_w, Sc_w, false, 8, inst32, 32);   \
1780         break;                                                         \
1781       case AtomicWidth::kWord64:                                       \
1782         ASSEMBLE_ATOMIC_BINOP_EXT(Ll_d, Sc_d, false, 8, inst64, 64);   \
1783         break;                                                         \
1784     }                                                                  \
1785     break;                                                             \
1786   case kAtomic##op##Int16:                                             \
1787     DCHECK_EQ(AtomicWidthField::decode(opcode), AtomicWidth::kWord32); \
1788     ASSEMBLE_ATOMIC_BINOP_EXT(Ll_w, Sc_w, true, 16, inst32, 32);       \
1789     break;                                                             \
1790   case kAtomic##op##Uint16:                                            \
1791     switch (AtomicWidthField::decode(opcode)) {                        \
1792       case AtomicWidth::kWord32:                                       \
1793         ASSEMBLE_ATOMIC_BINOP_EXT(Ll_w, Sc_w, false, 16, inst32, 32);  \
1794         break;                                                         \
1795       case AtomicWidth::kWord64:                                       \
1796         ASSEMBLE_ATOMIC_BINOP_EXT(Ll_d, Sc_d, false, 16, inst64, 64);  \
1797         break;                                                         \
1798     }                                                                  \
1799     break;
1800       ATOMIC_BINOP_CASE(Add, Add_w, Add_d)
1801       ATOMIC_BINOP_CASE(Sub, Sub_w, Sub_d)
1802       ATOMIC_BINOP_CASE(And, And, And)
1803       ATOMIC_BINOP_CASE(Or, Or, Or)
1804       ATOMIC_BINOP_CASE(Xor, Xor, Xor)
1805 #undef ATOMIC_BINOP_CASE
1806 
1807     case kLoong64Word64AtomicAddUint64:
1808       __ Add_d(i.TempRegister(0), i.InputRegister(0), i.InputRegister(1));
1809       __ amadd_db_d(i.OutputRegister(0), i.InputRegister(2), i.TempRegister(0));
1810       break;
1811     case kLoong64Word64AtomicSubUint64:
1812       ASSEMBLE_ATOMIC_BINOP(Ll_d, Sc_d, Sub_d);
1813       break;
1814     case kLoong64Word64AtomicAndUint64:
1815       __ Add_d(i.TempRegister(0), i.InputRegister(0), i.InputRegister(1));
1816       __ amand_db_d(i.OutputRegister(0), i.InputRegister(2), i.TempRegister(0));
1817       break;
1818     case kLoong64Word64AtomicOrUint64:
1819       __ Add_d(i.TempRegister(0), i.InputRegister(0), i.InputRegister(1));
1820       __ amor_db_d(i.OutputRegister(0), i.InputRegister(2), i.TempRegister(0));
1821       break;
1822     case kLoong64Word64AtomicXorUint64:
1823       __ Add_d(i.TempRegister(0), i.InputRegister(0), i.InputRegister(1));
1824       __ amxor_db_d(i.OutputRegister(0), i.InputRegister(2), i.TempRegister(0));
1825       break;
1826 #undef ATOMIC_BINOP_CASE
1827     case kLoong64S128Const:
1828     case kLoong64S128Zero:
1829     case kLoong64I32x4Splat:
1830     case kLoong64I32x4ExtractLane:
1831     case kLoong64I32x4Add:
1832     case kLoong64I32x4ReplaceLane:
1833     case kLoong64I32x4Sub:
1834     case kLoong64F64x2Abs:
1835     default:
1836       break;
1837   }
1838   return kSuccess;
1839 }
1840 
1841 #define UNSUPPORTED_COND(opcode, condition)                                    \
1842   StdoutStream{} << "Unsupported " << #opcode << " condition: \"" << condition \
1843                  << "\"";                                                      \
1844   UNIMPLEMENTED();
1845 
AssembleBranchToLabels(CodeGenerator * gen,TurboAssembler * tasm,Instruction * instr,FlagsCondition condition,Label * tlabel,Label * flabel,bool fallthru)1846 void AssembleBranchToLabels(CodeGenerator* gen, TurboAssembler* tasm,
1847                             Instruction* instr, FlagsCondition condition,
1848                             Label* tlabel, Label* flabel, bool fallthru) {
1849 #undef __
1850 #define __ tasm->
1851   Loong64OperandConverter i(gen, instr);
1852 
1853   Condition cc = kNoCondition;
1854   // LOONG64 does not have condition code flags, so compare and branch are
1855   // implemented differently than on the other arch's. The compare operations
1856   // emit loong64 pseudo-instructions, which are handled here by branch
1857   // instructions that do the actual comparison. Essential that the input
1858   // registers to compare pseudo-op are not modified before this branch op, as
1859   // they are tested here.
1860 
1861   if (instr->arch_opcode() == kLoong64Tst) {
1862     cc = FlagsConditionToConditionTst(condition);
1863     __ Branch(tlabel, cc, t8, Operand(zero_reg));
1864   } else if (instr->arch_opcode() == kLoong64Add_d ||
1865              instr->arch_opcode() == kLoong64Sub_d) {
1866     UseScratchRegisterScope temps(tasm);
1867     Register scratch = temps.Acquire();
1868     Register scratch2 = temps.Acquire();
1869     cc = FlagsConditionToConditionOvf(condition);
1870     __ srai_d(scratch, i.OutputRegister(), 32);
1871     __ srai_w(scratch2, i.OutputRegister(), 31);
1872     __ Branch(tlabel, cc, scratch2, Operand(scratch));
1873   } else if (instr->arch_opcode() == kLoong64AddOvf_d ||
1874              instr->arch_opcode() == kLoong64SubOvf_d) {
1875     switch (condition) {
1876       // Overflow occurs if overflow register is negative
1877       case kOverflow:
1878         __ Branch(tlabel, lt, t8, Operand(zero_reg));
1879         break;
1880       case kNotOverflow:
1881         __ Branch(tlabel, ge, t8, Operand(zero_reg));
1882         break;
1883       default:
1884         UNSUPPORTED_COND(instr->arch_opcode(), condition);
1885     }
1886   } else if (instr->arch_opcode() == kLoong64MulOvf_w) {
1887     // Overflow occurs if overflow register is not zero
1888     switch (condition) {
1889       case kOverflow:
1890         __ Branch(tlabel, ne, t8, Operand(zero_reg));
1891         break;
1892       case kNotOverflow:
1893         __ Branch(tlabel, eq, t8, Operand(zero_reg));
1894         break;
1895       default:
1896         UNSUPPORTED_COND(kLoong64MulOvf_w, condition);
1897     }
1898   } else if (instr->arch_opcode() == kLoong64Cmp) {
1899     cc = FlagsConditionToConditionCmp(condition);
1900     __ Branch(tlabel, cc, i.InputRegister(0), i.InputOperand(1));
1901   } else if (instr->arch_opcode() == kArchStackPointerGreaterThan) {
1902     cc = FlagsConditionToConditionCmp(condition);
1903     DCHECK((cc == ls) || (cc == hi));
1904     if (cc == ls) {
1905       __ xori(i.TempRegister(0), i.TempRegister(0), 1);
1906     }
1907     __ Branch(tlabel, ne, i.TempRegister(0), Operand(zero_reg));
1908   } else if (instr->arch_opcode() == kLoong64Float32Cmp ||
1909              instr->arch_opcode() == kLoong64Float64Cmp) {
1910     bool predicate;
1911     FlagsConditionToConditionCmpFPU(&predicate, condition);
1912     if (predicate) {
1913       __ BranchTrueF(tlabel);
1914     } else {
1915       __ BranchFalseF(tlabel);
1916     }
1917   } else {
1918     PrintF("AssembleArchBranch Unimplemented arch_opcode: %d\n",
1919            instr->arch_opcode());
1920     UNIMPLEMENTED();
1921   }
1922   if (!fallthru) __ Branch(flabel);  // no fallthru to flabel.
1923 #undef __
1924 #define __ tasm()->
1925 }
1926 
1927 // Assembles branches after an instruction.
AssembleArchBranch(Instruction * instr,BranchInfo * branch)1928 void CodeGenerator::AssembleArchBranch(Instruction* instr, BranchInfo* branch) {
1929   Label* tlabel = branch->true_label;
1930   Label* flabel = branch->false_label;
1931 
1932   AssembleBranchToLabels(this, tasm(), instr, branch->condition, tlabel, flabel,
1933                          branch->fallthru);
1934 }
1935 
1936 #undef UNSUPPORTED_COND
1937 
AssembleArchDeoptBranch(Instruction * instr,BranchInfo * branch)1938 void CodeGenerator::AssembleArchDeoptBranch(Instruction* instr,
1939                                             BranchInfo* branch) {
1940   AssembleArchBranch(instr, branch);
1941 }
1942 
AssembleArchJumpRegardlessOfAssemblyOrder(RpoNumber target)1943 void CodeGenerator::AssembleArchJumpRegardlessOfAssemblyOrder(
1944     RpoNumber target) {
1945   __ Branch(GetLabel(target));
1946 }
1947 
1948 #if V8_ENABLE_WEBASSEMBLY
AssembleArchTrap(Instruction * instr,FlagsCondition condition)1949 void CodeGenerator::AssembleArchTrap(Instruction* instr,
1950                                      FlagsCondition condition) {
1951   class OutOfLineTrap final : public OutOfLineCode {
1952    public:
1953     OutOfLineTrap(CodeGenerator* gen, Instruction* instr)
1954         : OutOfLineCode(gen), instr_(instr), gen_(gen) {}
1955     void Generate() final {
1956       Loong64OperandConverter i(gen_, instr_);
1957       TrapId trap_id =
1958           static_cast<TrapId>(i.InputInt32(instr_->InputCount() - 1));
1959       GenerateCallToTrap(trap_id);
1960     }
1961 
1962    private:
1963     void GenerateCallToTrap(TrapId trap_id) {
1964       if (trap_id == TrapId::kInvalid) {
1965         // We cannot test calls to the runtime in cctest/test-run-wasm.
1966         // Therefore we emit a call to C here instead of a call to the runtime.
1967         // We use the context register as the scratch register, because we do
1968         // not have a context here.
1969         __ PrepareCallCFunction(0, 0, cp);
1970         __ CallCFunction(
1971             ExternalReference::wasm_call_trap_callback_for_testing(), 0);
1972         __ LeaveFrame(StackFrame::WASM);
1973         auto call_descriptor = gen_->linkage()->GetIncomingDescriptor();
1974         int pop_count = static_cast<int>(call_descriptor->ParameterSlotCount());
1975         pop_count += (pop_count & 1);  // align
1976         __ Drop(pop_count);
1977         __ Ret();
1978       } else {
1979         gen_->AssembleSourcePosition(instr_);
1980         // A direct call to a wasm runtime stub defined in this module.
1981         // Just encode the stub index. This will be patched when the code
1982         // is added to the native module and copied into wasm code space.
1983         __ Call(static_cast<Address>(trap_id), RelocInfo::WASM_STUB_CALL);
1984         ReferenceMap* reference_map =
1985             gen_->zone()->New<ReferenceMap>(gen_->zone());
1986         gen_->RecordSafepoint(reference_map);
1987         if (FLAG_debug_code) {
1988           __ stop();
1989         }
1990       }
1991     }
1992     Instruction* instr_;
1993     CodeGenerator* gen_;
1994   };
1995   auto ool = zone()->New<OutOfLineTrap>(this, instr);
1996   Label* tlabel = ool->entry();
1997   AssembleBranchToLabels(this, tasm(), instr, condition, tlabel, nullptr, true);
1998 }
1999 #endif  // V8_ENABLE_WEBASSEMBLY
2000 
2001 // Assembles boolean materializations after an instruction.
AssembleArchBoolean(Instruction * instr,FlagsCondition condition)2002 void CodeGenerator::AssembleArchBoolean(Instruction* instr,
2003                                         FlagsCondition condition) {
2004   Loong64OperandConverter i(this, instr);
2005 
2006   // Materialize a full 32-bit 1 or 0 value. The result register is always the
2007   // last output of the instruction.
2008   DCHECK_NE(0u, instr->OutputCount());
2009   Register result = i.OutputRegister(instr->OutputCount() - 1);
2010   Condition cc = kNoCondition;
2011   // Loong64 does not have condition code flags, so compare and branch are
2012   // implemented differently than on the other arch's. The compare operations
2013   // emit loong64 pseudo-instructions, which are checked and handled here.
2014 
2015   if (instr->arch_opcode() == kLoong64Tst) {
2016     cc = FlagsConditionToConditionTst(condition);
2017     if (cc == eq) {
2018       __ Sltu(result, t8, 1);
2019     } else {
2020       __ Sltu(result, zero_reg, t8);
2021     }
2022     return;
2023   } else if (instr->arch_opcode() == kLoong64Add_d ||
2024              instr->arch_opcode() == kLoong64Sub_d) {
2025     UseScratchRegisterScope temps(tasm());
2026     Register scratch = temps.Acquire();
2027     cc = FlagsConditionToConditionOvf(condition);
2028     // Check for overflow creates 1 or 0 for result.
2029     __ srli_d(scratch, i.OutputRegister(), 63);
2030     __ srli_w(result, i.OutputRegister(), 31);
2031     __ xor_(result, scratch, result);
2032     if (cc == eq)  // Toggle result for not overflow.
2033       __ xori(result, result, 1);
2034     return;
2035   } else if (instr->arch_opcode() == kLoong64AddOvf_d ||
2036              instr->arch_opcode() == kLoong64SubOvf_d) {
2037     // Overflow occurs if overflow register is negative
2038     __ slt(result, t8, zero_reg);
2039   } else if (instr->arch_opcode() == kLoong64MulOvf_w) {
2040     // Overflow occurs if overflow register is not zero
2041     __ Sgtu(result, t8, zero_reg);
2042   } else if (instr->arch_opcode() == kLoong64Cmp) {
2043     cc = FlagsConditionToConditionCmp(condition);
2044     switch (cc) {
2045       case eq:
2046       case ne: {
2047         Register left = i.InputRegister(0);
2048         Operand right = i.InputOperand(1);
2049         if (instr->InputAt(1)->IsImmediate()) {
2050           if (is_int12(-right.immediate())) {
2051             if (right.immediate() == 0) {
2052               if (cc == eq) {
2053                 __ Sltu(result, left, 1);
2054               } else {
2055                 __ Sltu(result, zero_reg, left);
2056               }
2057             } else {
2058               __ Add_d(result, left, Operand(-right.immediate()));
2059               if (cc == eq) {
2060                 __ Sltu(result, result, 1);
2061               } else {
2062                 __ Sltu(result, zero_reg, result);
2063               }
2064             }
2065           } else {
2066             __ Xor(result, left, Operand(right));
2067             if (cc == eq) {
2068               __ Sltu(result, result, 1);
2069             } else {
2070               __ Sltu(result, zero_reg, result);
2071             }
2072           }
2073         } else {
2074           __ Xor(result, left, right);
2075           if (cc == eq) {
2076             __ Sltu(result, result, 1);
2077           } else {
2078             __ Sltu(result, zero_reg, result);
2079           }
2080         }
2081       } break;
2082       case lt:
2083       case ge: {
2084         Register left = i.InputRegister(0);
2085         Operand right = i.InputOperand(1);
2086         __ Slt(result, left, right);
2087         if (cc == ge) {
2088           __ xori(result, result, 1);
2089         }
2090       } break;
2091       case gt:
2092       case le: {
2093         Register left = i.InputRegister(1);
2094         Operand right = i.InputOperand(0);
2095         __ Slt(result, left, right);
2096         if (cc == le) {
2097           __ xori(result, result, 1);
2098         }
2099       } break;
2100       case lo:
2101       case hs: {
2102         Register left = i.InputRegister(0);
2103         Operand right = i.InputOperand(1);
2104         __ Sltu(result, left, right);
2105         if (cc == hs) {
2106           __ xori(result, result, 1);
2107         }
2108       } break;
2109       case hi:
2110       case ls: {
2111         Register left = i.InputRegister(1);
2112         Operand right = i.InputOperand(0);
2113         __ Sltu(result, left, right);
2114         if (cc == ls) {
2115           __ xori(result, result, 1);
2116         }
2117       } break;
2118       default:
2119         UNREACHABLE();
2120     }
2121     return;
2122   } else if (instr->arch_opcode() == kLoong64Float64Cmp ||
2123              instr->arch_opcode() == kLoong64Float32Cmp) {
2124     FPURegister left = i.InputOrZeroDoubleRegister(0);
2125     FPURegister right = i.InputOrZeroDoubleRegister(1);
2126     if ((left == kDoubleRegZero || right == kDoubleRegZero) &&
2127         !__ IsDoubleZeroRegSet()) {
2128       __ Move(kDoubleRegZero, 0.0);
2129     }
2130     bool predicate;
2131     FlagsConditionToConditionCmpFPU(&predicate, condition);
2132     {
2133       __ movcf2gr(result, FCC0);
2134       if (!predicate) {
2135         __ xori(result, result, 1);
2136       }
2137     }
2138     return;
2139   } else if (instr->arch_opcode() == kArchStackPointerGreaterThan) {
2140     cc = FlagsConditionToConditionCmp(condition);
2141     DCHECK((cc == ls) || (cc == hi));
2142     if (cc == ls) {
2143       __ xori(i.OutputRegister(), i.TempRegister(0), 1);
2144     }
2145     return;
2146   } else {
2147     PrintF("AssembleArchBranch Unimplemented arch_opcode is : %d\n",
2148            instr->arch_opcode());
2149     TRACE_UNIMPL();
2150     UNIMPLEMENTED();
2151   }
2152 }
2153 
AssembleArchBinarySearchSwitch(Instruction * instr)2154 void CodeGenerator::AssembleArchBinarySearchSwitch(Instruction* instr) {
2155   Loong64OperandConverter i(this, instr);
2156   Register input = i.InputRegister(0);
2157   std::vector<std::pair<int32_t, Label*>> cases;
2158   for (size_t index = 2; index < instr->InputCount(); index += 2) {
2159     cases.push_back({i.InputInt32(index + 0), GetLabel(i.InputRpo(index + 1))});
2160   }
2161   AssembleArchBinarySearchSwitchRange(input, i.InputRpo(1), cases.data(),
2162                                       cases.data() + cases.size());
2163 }
2164 
AssembleArchTableSwitch(Instruction * instr)2165 void CodeGenerator::AssembleArchTableSwitch(Instruction* instr) {
2166   Loong64OperandConverter i(this, instr);
2167   Register input = i.InputRegister(0);
2168   size_t const case_count = instr->InputCount() - 2;
2169 
2170   __ Branch(GetLabel(i.InputRpo(1)), hs, input, Operand(case_count));
2171   __ GenerateSwitchTable(input, case_count, [&i, this](size_t index) {
2172     return GetLabel(i.InputRpo(index + 2));
2173   });
2174 }
2175 
AssembleArchSelect(Instruction * instr,FlagsCondition condition)2176 void CodeGenerator::AssembleArchSelect(Instruction* instr,
2177                                        FlagsCondition condition) {
2178   UNIMPLEMENTED();
2179 }
2180 
FinishFrame(Frame * frame)2181 void CodeGenerator::FinishFrame(Frame* frame) {
2182   auto call_descriptor = linkage()->GetIncomingDescriptor();
2183 
2184   const DoubleRegList saves_fpu = call_descriptor->CalleeSavedFPRegisters();
2185   if (!saves_fpu.is_empty()) {
2186     int count = saves_fpu.Count();
2187     DCHECK_EQ(kNumCalleeSavedFPU, count);
2188     frame->AllocateSavedCalleeRegisterSlots(count *
2189                                             (kDoubleSize / kSystemPointerSize));
2190   }
2191 
2192   const RegList saves = call_descriptor->CalleeSavedRegisters();
2193   if (!saves.is_empty()) {
2194     int count = saves.Count();
2195     frame->AllocateSavedCalleeRegisterSlots(count);
2196   }
2197 }
2198 
AssembleConstructFrame()2199 void CodeGenerator::AssembleConstructFrame() {
2200   auto call_descriptor = linkage()->GetIncomingDescriptor();
2201 
2202   if (frame_access_state()->has_frame()) {
2203     if (call_descriptor->IsCFunctionCall()) {
2204 #if V8_ENABLE_WEBASSEMBLY
2205       if (info()->GetOutputStackFrameType() == StackFrame::C_WASM_ENTRY) {
2206         __ StubPrologue(StackFrame::C_WASM_ENTRY);
2207         // Reserve stack space for saving the c_entry_fp later.
2208         __ Sub_d(sp, sp, Operand(kSystemPointerSize));
2209 #else
2210       // For balance.
2211       if (false) {
2212 #endif  // V8_ENABLE_WEBASSEMBLY
2213       } else {
2214         __ Push(ra, fp);
2215         __ mov(fp, sp);
2216       }
2217     } else if (call_descriptor->IsJSFunctionCall()) {
2218       __ Prologue();
2219     } else {
2220       __ StubPrologue(info()->GetOutputStackFrameType());
2221 #if V8_ENABLE_WEBASSEMBLY
2222       if (call_descriptor->IsWasmFunctionCall() ||
2223           call_descriptor->IsWasmImportWrapper() ||
2224           call_descriptor->IsWasmCapiFunction()) {
2225         __ Push(kWasmInstanceRegister);
2226       }
2227       if (call_descriptor->IsWasmCapiFunction()) {
2228         // Reserve space for saving the PC later.
2229         __ Sub_d(sp, sp, Operand(kSystemPointerSize));
2230       }
2231 #endif  // V8_ENABLE_WEBASSEMBLY
2232     }
2233   }
2234 
2235   int required_slots =
2236       frame()->GetTotalFrameSlotCount() - frame()->GetFixedSlotCount();
2237 
2238   if (info()->is_osr()) {
2239     // TurboFan OSR-compiled functions cannot be entered directly.
2240     __ Abort(AbortReason::kShouldNotDirectlyEnterOsrFunction);
2241 
2242     // Unoptimized code jumps directly to this entrypoint while the unoptimized
2243     // frame is still on the stack. Optimized code uses OSR values directly from
2244     // the unoptimized frame. Thus, all that needs to be done is to allocate the
2245     // remaining stack slots.
2246     __ RecordComment("-- OSR entrypoint --");
2247     osr_pc_offset_ = __ pc_offset();
2248     required_slots -= osr_helper()->UnoptimizedFrameSlots();
2249   }
2250 
2251   const RegList saves = call_descriptor->CalleeSavedRegisters();
2252   const DoubleRegList saves_fpu = call_descriptor->CalleeSavedFPRegisters();
2253 
2254   if (required_slots > 0) {
2255     DCHECK(frame_access_state()->has_frame());
2256 #if V8_ENABLE_WEBASSEMBLY
2257     if (info()->IsWasm() && required_slots * kSystemPointerSize > 4 * KB) {
2258       // For WebAssembly functions with big frames we have to do the stack
2259       // overflow check before we construct the frame. Otherwise we may not
2260       // have enough space on the stack to call the runtime for the stack
2261       // overflow.
2262       Label done;
2263 
2264       // If the frame is bigger than the stack, we throw the stack overflow
2265       // exception unconditionally. Thereby we can avoid the integer overflow
2266       // check in the condition code.
2267       if (required_slots * kSystemPointerSize < FLAG_stack_size * KB) {
2268         UseScratchRegisterScope temps(tasm());
2269         Register scratch = temps.Acquire();
2270         __ Ld_d(scratch, FieldMemOperand(
2271                              kWasmInstanceRegister,
2272                              WasmInstanceObject::kRealStackLimitAddressOffset));
2273         __ Ld_d(scratch, MemOperand(scratch, 0));
2274         __ Add_d(scratch, scratch,
2275                  Operand(required_slots * kSystemPointerSize));
2276         __ Branch(&done, uge, sp, Operand(scratch));
2277       }
2278 
2279       __ Call(wasm::WasmCode::kWasmStackOverflow, RelocInfo::WASM_STUB_CALL);
2280       // The call does not return, hence we can ignore any references and just
2281       // define an empty safepoint.
2282       ReferenceMap* reference_map = zone()->New<ReferenceMap>(zone());
2283       RecordSafepoint(reference_map);
2284       if (FLAG_debug_code) {
2285         __ stop();
2286       }
2287 
2288       __ bind(&done);
2289     }
2290 #endif  // V8_ENABLE_WEBASSEMBLY
2291   }
2292 
2293   const int returns = frame()->GetReturnSlotCount();
2294 
2295   // Skip callee-saved and return slots, which are pushed below.
2296   required_slots -= saves.Count();
2297   required_slots -= saves_fpu.Count();
2298   required_slots -= returns;
2299   if (required_slots > 0) {
2300     __ Sub_d(sp, sp, Operand(required_slots * kSystemPointerSize));
2301   }
2302 
2303   if (!saves_fpu.is_empty()) {
2304     // Save callee-saved FPU registers.
2305     __ MultiPushFPU(saves_fpu);
2306     DCHECK_EQ(kNumCalleeSavedFPU, saves_fpu.Count());
2307   }
2308 
2309   if (!saves.is_empty()) {
2310     // Save callee-saved registers.
2311     __ MultiPush(saves);
2312   }
2313 
2314   if (returns != 0) {
2315     // Create space for returns.
2316     __ Sub_d(sp, sp, Operand(returns * kSystemPointerSize));
2317   }
2318 }
2319 
2320 void CodeGenerator::AssembleReturn(InstructionOperand* additional_pop_count) {
2321   auto call_descriptor = linkage()->GetIncomingDescriptor();
2322 
2323   const int returns = frame()->GetReturnSlotCount();
2324   if (returns != 0) {
2325     __ Add_d(sp, sp, Operand(returns * kSystemPointerSize));
2326   }
2327 
2328   // Restore GP registers.
2329   const RegList saves = call_descriptor->CalleeSavedRegisters();
2330   if (!saves.is_empty()) {
2331     __ MultiPop(saves);
2332   }
2333 
2334   // Restore FPU registers.
2335   const DoubleRegList saves_fpu = call_descriptor->CalleeSavedFPRegisters();
2336   if (!saves_fpu.is_empty()) {
2337     __ MultiPopFPU(saves_fpu);
2338   }
2339 
2340   Loong64OperandConverter g(this, nullptr);
2341 
2342   const int parameter_slots =
2343       static_cast<int>(call_descriptor->ParameterSlotCount());
2344 
2345   // {aditional_pop_count} is only greater than zero if {parameter_slots = 0}.
2346   // Check RawMachineAssembler::PopAndReturn.
2347   if (parameter_slots != 0) {
2348     if (additional_pop_count->IsImmediate()) {
2349       DCHECK_EQ(g.ToConstant(additional_pop_count).ToInt32(), 0);
2350     } else if (FLAG_debug_code) {
2351       __ Assert(eq, AbortReason::kUnexpectedAdditionalPopValue,
2352                 g.ToRegister(additional_pop_count),
2353                 Operand(static_cast<int64_t>(0)));
2354     }
2355   }
2356 
2357   // Functions with JS linkage have at least one parameter (the receiver).
2358   // If {parameter_slots} == 0, it means it is a builtin with
2359   // kDontAdaptArgumentsSentinel, which takes care of JS arguments popping
2360   // itself.
2361   const bool drop_jsargs = frame_access_state()->has_frame() &&
2362                            call_descriptor->IsJSFunctionCall() &&
2363                            parameter_slots != 0;
2364 
2365   if (call_descriptor->IsCFunctionCall()) {
2366     AssembleDeconstructFrame();
2367   } else if (frame_access_state()->has_frame()) {
2368     // Canonicalize JSFunction return sites for now unless they have an variable
2369     // number of stack slot pops.
2370     if (additional_pop_count->IsImmediate() &&
2371         g.ToConstant(additional_pop_count).ToInt32() == 0) {
2372       if (return_label_.is_bound()) {
2373         __ Branch(&return_label_);
2374         return;
2375       } else {
2376         __ bind(&return_label_);
2377       }
2378     }
2379     if (drop_jsargs) {
2380       // Get the actual argument count
2381       __ Ld_d(t0, MemOperand(fp, StandardFrameConstants::kArgCOffset));
2382     }
2383     AssembleDeconstructFrame();
2384   }
2385   if (drop_jsargs) {
2386     // We must pop all arguments from the stack (including the receiver). This
2387     // number of arguments is given by max(1 + argc_reg, parameter_count).
2388     if (parameter_slots > 1) {
2389       __ li(t1, parameter_slots);
2390       __ slt(t2, t0, t1);
2391       __ Movn(t0, t1, t2);
2392     }
2393     __ Alsl_d(sp, t0, sp, kSystemPointerSizeLog2);
2394   } else if (additional_pop_count->IsImmediate()) {
2395     int additional_count = g.ToConstant(additional_pop_count).ToInt32();
2396     __ Drop(parameter_slots + additional_count);
2397   } else {
2398     Register pop_reg = g.ToRegister(additional_pop_count);
2399     __ Drop(parameter_slots);
2400     __ Alsl_d(sp, pop_reg, sp, kSystemPointerSizeLog2);
2401   }
2402   __ Ret();
2403 }
2404 
2405 void CodeGenerator::FinishCode() {}
2406 
2407 void CodeGenerator::PrepareForDeoptimizationExits(
2408     ZoneDeque<DeoptimizationExit*>* exits) {}
2409 
2410 void CodeGenerator::AssembleMove(InstructionOperand* source,
2411                                  InstructionOperand* destination) {
2412   Loong64OperandConverter g(this, nullptr);
2413   // Dispatch on the source and destination operand kinds.  Not all
2414   // combinations are possible.
2415   if (source->IsRegister()) {
2416     DCHECK(destination->IsRegister() || destination->IsStackSlot());
2417     Register src = g.ToRegister(source);
2418     if (destination->IsRegister()) {
2419       __ mov(g.ToRegister(destination), src);
2420     } else {
2421       __ St_d(src, g.ToMemOperand(destination));
2422     }
2423   } else if (source->IsStackSlot()) {
2424     DCHECK(destination->IsRegister() || destination->IsStackSlot());
2425     MemOperand src = g.ToMemOperand(source);
2426     if (destination->IsRegister()) {
2427       __ Ld_d(g.ToRegister(destination), src);
2428     } else {
2429       UseScratchRegisterScope temps(tasm());
2430       Register scratch = temps.Acquire();
2431       __ Ld_d(scratch, src);
2432       __ St_d(scratch, g.ToMemOperand(destination));
2433     }
2434   } else if (source->IsConstant()) {
2435     Constant src = g.ToConstant(source);
2436     if (destination->IsRegister() || destination->IsStackSlot()) {
2437       UseScratchRegisterScope temps(tasm());
2438       Register scratch = temps.Acquire();
2439       Register dst =
2440           destination->IsRegister() ? g.ToRegister(destination) : scratch;
2441       switch (src.type()) {
2442         case Constant::kInt32:
2443           __ li(dst, Operand(src.ToInt32()));
2444           break;
2445         case Constant::kFloat32:
2446           __ li(dst, Operand::EmbeddedNumber(src.ToFloat32()));
2447           break;
2448         case Constant::kInt64:
2449 #if V8_ENABLE_WEBASSEMBLY
2450           if (RelocInfo::IsWasmReference(src.rmode()))
2451             __ li(dst, Operand(src.ToInt64(), src.rmode()));
2452           else
2453 #endif  // V8_ENABLE_WEBASSEMBLY
2454             __ li(dst, Operand(src.ToInt64()));
2455           break;
2456         case Constant::kFloat64:
2457           __ li(dst, Operand::EmbeddedNumber(src.ToFloat64().value()));
2458           break;
2459         case Constant::kExternalReference:
2460           __ li(dst, src.ToExternalReference());
2461           break;
2462         case Constant::kDelayedStringConstant:
2463           __ li(dst, src.ToDelayedStringConstant());
2464           break;
2465         case Constant::kHeapObject: {
2466           Handle<HeapObject> src_object = src.ToHeapObject();
2467           RootIndex index;
2468           if (IsMaterializableFromRoot(src_object, &index)) {
2469             __ LoadRoot(dst, index);
2470           } else {
2471             __ li(dst, src_object);
2472           }
2473           break;
2474         }
2475         case Constant::kCompressedHeapObject:
2476           UNREACHABLE();
2477         case Constant::kRpoNumber:
2478           UNREACHABLE();  // TODO(titzer): loading RPO numbers on LOONG64.
2479       }
2480       if (destination->IsStackSlot()) __ St_d(dst, g.ToMemOperand(destination));
2481     } else if (src.type() == Constant::kFloat32) {
2482       if (destination->IsFPStackSlot()) {
2483         MemOperand dst = g.ToMemOperand(destination);
2484         if (bit_cast<int32_t>(src.ToFloat32()) == 0) {
2485           __ St_d(zero_reg, dst);
2486         } else {
2487           UseScratchRegisterScope temps(tasm());
2488           Register scratch = temps.Acquire();
2489           __ li(scratch, Operand(bit_cast<int32_t>(src.ToFloat32())));
2490           __ St_d(scratch, dst);
2491         }
2492       } else {
2493         DCHECK(destination->IsFPRegister());
2494         FloatRegister dst = g.ToSingleRegister(destination);
2495         __ Move(dst, src.ToFloat32());
2496       }
2497     } else {
2498       DCHECK_EQ(Constant::kFloat64, src.type());
2499       DoubleRegister dst = destination->IsFPRegister()
2500                                ? g.ToDoubleRegister(destination)
2501                                : kScratchDoubleReg;
2502       __ Move(dst, src.ToFloat64().value());
2503       if (destination->IsFPStackSlot()) {
2504         __ Fst_d(dst, g.ToMemOperand(destination));
2505       }
2506     }
2507   } else if (source->IsFPRegister()) {
2508     FPURegister src = g.ToDoubleRegister(source);
2509     if (destination->IsFPRegister()) {
2510       FPURegister dst = g.ToDoubleRegister(destination);
2511       __ Move(dst, src);
2512     } else {
2513       DCHECK(destination->IsFPStackSlot());
2514       __ Fst_d(src, g.ToMemOperand(destination));
2515     }
2516   } else if (source->IsFPStackSlot()) {
2517     DCHECK(destination->IsFPRegister() || destination->IsFPStackSlot());
2518     MemOperand src = g.ToMemOperand(source);
2519     if (destination->IsFPRegister()) {
2520       __ Fld_d(g.ToDoubleRegister(destination), src);
2521     } else {
2522       DCHECK(destination->IsFPStackSlot());
2523       FPURegister temp = kScratchDoubleReg;
2524       __ Fld_d(temp, src);
2525       __ Fst_d(temp, g.ToMemOperand(destination));
2526     }
2527   } else {
2528     UNREACHABLE();
2529   }
2530 }
2531 
2532 void CodeGenerator::AssembleSwap(InstructionOperand* source,
2533                                  InstructionOperand* destination) {
2534   Loong64OperandConverter g(this, nullptr);
2535   // Dispatch on the source and destination operand kinds.  Not all
2536   // combinations are possible.
2537   if (source->IsRegister()) {
2538     UseScratchRegisterScope temps(tasm());
2539     Register scratch = temps.Acquire();
2540     // Register-register.
2541     Register src = g.ToRegister(source);
2542     if (destination->IsRegister()) {
2543       Register dst = g.ToRegister(destination);
2544       __ Move(scratch, src);
2545       __ Move(src, dst);
2546       __ Move(dst, scratch);
2547     } else {
2548       DCHECK(destination->IsStackSlot());
2549       MemOperand dst = g.ToMemOperand(destination);
2550       __ mov(scratch, src);
2551       __ Ld_d(src, dst);
2552       __ St_d(scratch, dst);
2553     }
2554   } else if (source->IsStackSlot()) {
2555     DCHECK(destination->IsStackSlot());
2556     // TODO(LOONG_dev): LOONG64 Optimize scratch registers usage
2557     // Since the Ld instruction may need a scratch reg,
2558     // we should not use both of the two scratch registers in
2559     // UseScratchRegisterScope here.
2560     UseScratchRegisterScope temps(tasm());
2561     Register scratch = temps.Acquire();
2562     FPURegister scratch_d = kScratchDoubleReg;
2563     MemOperand src = g.ToMemOperand(source);
2564     MemOperand dst = g.ToMemOperand(destination);
2565     __ Ld_d(scratch, src);
2566     __ Fld_d(scratch_d, dst);
2567     __ St_d(scratch, dst);
2568     __ Fst_d(scratch_d, src);
2569   } else if (source->IsFPRegister()) {
2570     FPURegister scratch_d = kScratchDoubleReg;
2571     FPURegister src = g.ToDoubleRegister(source);
2572     if (destination->IsFPRegister()) {
2573       FPURegister dst = g.ToDoubleRegister(destination);
2574       __ Move(scratch_d, src);
2575       __ Move(src, dst);
2576       __ Move(dst, scratch_d);
2577     } else {
2578       DCHECK(destination->IsFPStackSlot());
2579       MemOperand dst = g.ToMemOperand(destination);
2580       __ Move(scratch_d, src);
2581       __ Fld_d(src, dst);
2582       __ Fst_d(scratch_d, dst);
2583     }
2584   } else if (source->IsFPStackSlot()) {
2585     DCHECK(destination->IsFPStackSlot());
2586     UseScratchRegisterScope temps(tasm());
2587     Register scratch = temps.Acquire();
2588     MemOperand src0 = g.ToMemOperand(source);
2589     MemOperand src1(src0.base(), src0.offset() + kIntSize);
2590     MemOperand dst0 = g.ToMemOperand(destination);
2591     MemOperand dst1(dst0.base(), dst0.offset() + kIntSize);
2592     FPURegister scratch_d = kScratchDoubleReg;
2593     __ Fld_d(scratch_d, dst0);  // Save destination in temp_1.
2594     __ Ld_w(scratch, src0);  // Then use scratch to copy source to destination.
2595     __ St_w(scratch, dst0);
2596     __ Ld_w(scratch, src1);
2597     __ St_w(scratch, dst1);
2598     __ Fst_d(scratch_d, src0);
2599   } else {
2600     // No other combinations are possible.
2601     UNREACHABLE();
2602   }
2603 }
2604 
2605 void CodeGenerator::AssembleJumpTable(Label** targets, size_t target_count) {
2606   // On 64-bit LOONG64 we emit the jump tables inline.
2607   UNREACHABLE();
2608 }
2609 
2610 #undef ASSEMBLE_ATOMIC_LOAD_INTEGER
2611 #undef ASSEMBLE_ATOMIC_STORE_INTEGER
2612 #undef ASSEMBLE_ATOMIC_BINOP
2613 #undef ASSEMBLE_ATOMIC_BINOP_EXT
2614 #undef ASSEMBLE_ATOMIC_EXCHANGE_INTEGER
2615 #undef ASSEMBLE_ATOMIC_EXCHANGE_INTEGER_EXT
2616 #undef ASSEMBLE_ATOMIC_COMPARE_EXCHANGE_INTEGER
2617 #undef ASSEMBLE_ATOMIC_COMPARE_EXCHANGE_INTEGER_EXT
2618 #undef ASSEMBLE_IEEE754_BINOP
2619 #undef ASSEMBLE_IEEE754_UNOP
2620 
2621 #undef TRACE_MSG
2622 #undef TRACE_UNIMPL
2623 #undef __
2624 
2625 }  // namespace compiler
2626 }  // namespace internal
2627 }  // namespace v8
2628