6#if defined(TARGET_ARCH_ARM64)
28#define __ (compiler->assembler())->
29#define Z (compiler->zone())
37 const Instruction* instr,
38 LocationSummary* locs) {
70LocationSummary* LoadIndexedUnsafeInstr::MakeLocationSummary(Zone* zone,
72 const intptr_t kNumInputs = 1;
73 const intptr_t kNumTemps = ((
representation() == kUnboxedDouble) ? 1 : 0);
74 LocationSummary* locs =
new (zone)
94void LoadIndexedUnsafeInstr::EmitNativeCode(FlowGraphCompiler*
compiler) {
103 case kUnboxedInt64: {
104 const auto out = locs()->out(0).reg();
105#if !defined(DART_COMPRESSED_POINTERS)
110 __ LoadFromOffset(out, out,
offset());
113 case kUnboxedDouble: {
114 const auto tmp = locs()->temp(0).reg();
115 const auto out = locs()->out(0).fpu_reg();
116#if !defined(DART_COMPRESSED_POINTERS)
121 __ LoadDFromOffset(out, tmp,
offset());
132 ASSERT(instr->RequiredInputRepresentation(
134#if !defined(DART_COMPRESSED_POINTERS)
135 __ add(
TMP, instr->base_reg(), compiler::Operand(index,
LSL, 2));
137 __ add(
TMP, instr->base_reg(), compiler::Operand(index,
SXTW, 2));
139 __ str(value, compiler::Address(
TMP, instr->offset()));
147 Fixed<Register, ARGS_DESC_REG>,
148 Temp<Register> temp)) {
149 compiler->EmitTailCallToStub(instr->code());
155 __ set_constant_pool_allowed(
true);
158LocationSummary* MemoryCopyInstr::MakeLocationSummary(Zone* zone,
166 const intptr_t kNumInputs = 5;
167 const intptr_t kNumTemps = 2;
168 LocationSummary* locs =
new (zone)
183 compiler::Label*
done) {
184 __ BranchIfZero(length_reg,
done);
204static void CopyUpToMultipleOfChunkSize(FlowGraphCompiler*
compiler,
212 compiler::Label*
done) {
217 const intptr_t base_shift =
219 const intptr_t offset_sign = reversed ? -1 : 1;
222 intptr_t tested_bits = 0;
224 __ Comment(
"Copying until region size is a multiple of chunk size");
227 bit >= element_shift; bit--) {
228 const intptr_t bytes = 1 << bit;
229 const intptr_t tested_bit = bit + base_shift;
230 tested_bits |= (1 << tested_bit);
231 const intptr_t
offset = offset_sign * bytes;
232 compiler::Label skip_copy;
233 __ tbz(&skip_copy, length_reg, tested_bit);
234 auto const sz = OperandSizeFor(bytes);
235 __ ldr(
TMP, compiler::Address(src_reg,
offset, mode), sz);
236 __ str(
TMP, compiler::Address(dest_reg,
offset, mode), sz);
241 __ andis(length_reg, length_reg, compiler::Immediate(~tested_bits),
250 compiler::Label*
done,
251 compiler::Label* copy_forwards) {
252 const bool reversed = copy_forwards !=
nullptr;
255#if defined(USING_MEMORY_SANITIZER)
256 __ PushPair(length_reg, dest_reg);
262 __ ExtendNonNegativeSmi(length_reg);
265 __ add(
TMP, src_reg, compiler::Operand(length_reg,
ASR, -shift));
267 __ add(
TMP, src_reg, compiler::Operand(length_reg,
LSL, shift));
269 __ CompareRegisters(dest_reg,
TMP);
272 __ MoveRegister(src_reg,
TMP);
274 __ add(dest_reg, dest_reg, compiler::Operand(length_reg,
ASR, -shift));
276 __ add(dest_reg, dest_reg, compiler::Operand(length_reg,
LSL, shift));
279 const intptr_t kChunkSize = 16;
280 ASSERT(kChunkSize >= element_size_);
281 CopyUpToMultipleOfChunkSize(
compiler, dest_reg, src_reg, length_reg,
282 element_size_, unboxed_inputs_, reversed,
285 const intptr_t loop_subtract = (kChunkSize / element_size_)
289 const intptr_t
offset = (reversed ? -1 : 1) * kChunkSize;
292 __ Comment(
"Copying chunks at a time");
293 compiler::Label loop;
297 __ subs(length_reg, length_reg, compiler::Operand(loop_subtract),
301#if defined(USING_MEMORY_SANITIZER)
302 __ PopPair(length_reg, dest_reg);
304 __ ExtendNonNegativeSmi(length_reg);
307 __ AsrImmediate(length_reg, length_reg, -shift);
309 __ LslImmediate(length_reg, length_reg, shift);
311 __ MsanUnpoison(dest_reg, length_reg);
315void MemoryCopyInstr::EmitComputeStartPointer(FlowGraphCompiler*
compiler,
322 if (array_rep != kTagged) {
333 case kOneByteStringCid:
337 case kTwoByteStringCid:
346 ASSERT(start_loc.IsRegister() || start_loc.IsConstant());
347 if (start_loc.IsConstant()) {
348 const auto& constant = start_loc.constant();
349 ASSERT(constant.IsInteger());
350 const int64_t start_value = Integer::Cast(constant).AsInt64Value();
352 Utils::MulWithWrapAround<intptr_t>(start_value, element_size_),
offset);
353 __ AddImmediate(payload_reg, array_reg, add_value);
356 const Register start_reg = start_loc.reg();
361 __ ExtendNonNegativeSmi(start_reg);
363 __ add(payload_reg, array_reg, compiler::Operand(start_reg,
ASR, -shift));
364#if defined(DART_COMPRESSED_POINTERS)
366 __ add(payload_reg, array_reg, compiler::Operand(start_reg,
SXTW, shift));
369 __ add(payload_reg, array_reg, compiler::Operand(start_reg,
LSL, shift));
371 __ AddImmediate(payload_reg,
offset);
374LocationSummary* CalculateElementAddressInstr::MakeLocationSummary(
377 const intptr_t kNumInputs = 3;
378 const intptr_t kNumTemps = 0;
379 auto*
const summary =
new (zone)
397void CalculateElementAddressInstr::EmitNativeCode(FlowGraphCompiler*
compiler) {
401 const Register result_reg = locs()->out(0).reg();
403 if (index_loc.IsConstant()) {
404 if (offset_loc.IsConstant()) {
405 ASSERT_EQUAL(Smi::Cast(index_loc.constant()).Value(), 0);
406 ASSERT(Integer::Cast(offset_loc.constant()).AsInt64Value() != 0);
408 const int64_t offset_value =
409 Integer::Cast(offset_loc.constant()).AsInt64Value();
410 __ AddImmediate(result_reg, base_reg, offset_value);
412 __ add(result_reg, base_reg, compiler::Operand(offset_loc.reg()));
415 const int64_t scaled_index =
416 Smi::Cast(index_loc.constant()).Value() *
index_scale();
417 __ AddImmediate(result_reg, scaled_index);
420 __ add(result_reg, base_reg,
421 compiler::Operand(index_loc.reg(),
LSL,
423 if (offset_loc.IsConstant()) {
424 const int64_t offset_value =
425 Integer::Cast(offset_loc.constant()).AsInt64Value();
426 __ AddImmediate(result_reg, offset_value);
428 __ AddRegisters(result_reg, offset_loc.reg());
433LocationSummary* MoveArgumentInstr::MakeLocationSummary(Zone* zone,
435 const intptr_t kNumInputs = 1;
436 const intptr_t kNumTemps = 0;
437 LocationSummary* locs =
new (zone)
440 if (constant !=
nullptr && constant->HasZeroRepresentation()) {
455class ArgumentsMover :
public ValueObject {
459 if (pending_register_ != kNoRegister) {
460 __ StoreToOffset(pending_register_, SP,
461 pending_sp_relative_index_ * kWordSize);
462 pending_sp_relative_index_ = -1;
468 void MoveRegister(FlowGraphCompiler*
compiler,
469 intptr_t sp_relative_index,
471 if (pending_register_ != kNoRegister) {
472 ASSERT((sp_relative_index + 1) == pending_sp_relative_index_);
473 __ StorePairToOffset(reg, pending_register_, SP,
474 sp_relative_index * kWordSize);
478 pending_register_ = reg;
479 pending_sp_relative_index_ = sp_relative_index;
487 static_assert(((1 <<
LR) & kDartAvailableCpuRegs) == 0,
488 "LR should not be allocatable");
489 static_assert(((1 <<
TMP) & kDartAvailableCpuRegs) == 0,
490 "TMP should not be allocatable");
491 return (pending_register_ == TMP) ?
LR :
TMP;
496 intptr_t pending_sp_relative_index_ = -1;
500void MoveArgumentInstr::EmitNativeCode(FlowGraphCompiler*
compiler) {
503 if (previous()->IsMoveArgument()) {
508 ArgumentsMover pusher;
509 for (MoveArgumentInstr* move_arg =
this; move_arg !=
nullptr;
510 move_arg = move_arg->next()->AsMoveArgument()) {
513 if (
value.IsRegister()) {
515 }
else if (
value.IsConstant()) {
516 if (
value.constant_instruction()->HasZeroRepresentation()) {
519 ASSERT(move_arg->representation() == kTagged);
520 const Object& constant =
value.constant();
521 if (constant.IsNull()) {
524 reg = pusher.GetFreeTempRegister(
compiler);
525 __ LoadObject(reg,
value.constant());
528 }
else if (
value.IsFpuRegister()) {
531 move_arg->location().stack_index() *
kWordSize);
535 const intptr_t value_offset =
value.ToStackSlotOffset();
536 reg = pusher.GetFreeTempRegister(
compiler);
537 __ LoadFromOffset(reg,
value.base_reg(), value_offset);
539 pusher.MoveRegister(
compiler, move_arg->location().stack_index(), reg);
546 const intptr_t kNumInputs = 1;
547 const intptr_t kNumTemps = 0;
548 LocationSummary*
locs =
new (zone)
578 if (
locs()->in(0).IsRegister()) {
581 }
else if (
locs()->in(0).IsPairLocation()) {
592 if (
compiler->parsed_function().function().IsAsyncFunction() ||
593 compiler->parsed_function().function().IsAsyncGenerator()) {
595 const Code& stub = GetReturnStub(
compiler);
600 if (!
compiler->flow_graph().graph_entry()->NeedsFrame()) {
606 compiler::Label stack_ok;
607 __ Comment(
"Stack Check");
608 const intptr_t fp_sp_dist =
609 (compiler::target::frame_layout.first_local_from_fp + 1 -
613 __ sub(
R2,
SP, compiler::Operand(
FP));
614 __ CompareImmediate(
R2, fp_sp_dist);
624 __ set_constant_pool_allowed(
true);
628static bool IsPowerOfTwoKind(intptr_t v1, intptr_t
v2) {
649 BranchLabels labels = {
nullptr,
nullptr,
nullptr};
653 const bool is_power_of_two_kind = IsPowerOfTwoKind(if_true_, if_false_);
655 intptr_t true_value = if_true_;
656 intptr_t false_value = if_false_;
658 if (is_power_of_two_kind) {
659 if (true_value == 0) {
664 if (true_value == 0) {
666 intptr_t temp = true_value;
667 true_value = false_value;
676 if (is_power_of_two_kind) {
677 const intptr_t shift =
684 if (false_value != 0) {
692 const intptr_t kNumInputs = 1;
693 const intptr_t kNumTemps = 0;
694 LocationSummary* summary =
new (zone)
704 const Array& arguments_descriptor =
708 if (FLAG_precompiled_mode) {
711 __ LoadFieldFromOffset(
R2,
R0,
712 compiler::target::Closure::entry_point_offset());
717 compiler::target::Function::code_offset());
720 compiler::target::Function::entry_point_offset());
725 if (!FLAG_precompiled_mode) {
731 UntaggedPcDescriptors::kOther,
locs(),
env());
735LocationSummary* LoadLocalInstr::MakeLocationSummary(Zone* zone,
741void LoadLocalInstr::EmitNativeCode(FlowGraphCompiler*
compiler) {
744 compiler::target::FrameOffsetInBytesForVariable(&
local()));
747LocationSummary* StoreLocalInstr::MakeLocationSummary(Zone* zone,
753void StoreLocalInstr::EmitNativeCode(FlowGraphCompiler*
compiler) {
758 compiler::target::FrameOffsetInBytesForVariable(&
local()));
761LocationSummary* ConstantInstr::MakeLocationSummary(Zone* zone,
767void ConstantInstr::EmitNativeCode(FlowGraphCompiler*
compiler) {
769 if (!locs()->
out(0).IsInvalid()) {
778 intptr_t pair_index) {
780 if (destination.IsRegister()) {
781 if (representation() == kUnboxedInt32 ||
782 representation() == kUnboxedUint32 ||
783 representation() == kUnboxedInt64) {
784 const int64_t
value = Integer::Cast(value_).AsInt64Value();
785 __ LoadImmediate(destination.reg(),
value);
787 ASSERT(representation() == kTagged);
788 __ LoadObject(destination.reg(), value_);
790 }
else if (destination.IsFpuRegister()) {
791 switch (representation()) {
793 __ LoadSImmediate(destination.fpu_reg(), Double::Cast(value_).value());
796 __ LoadDImmediate(destination.fpu_reg(), Double::Cast(value_).value());
798 case kUnboxedFloat64x2:
799 __ LoadQImmediate(destination.fpu_reg(),
800 Float64x2::Cast(value_).value());
802 case kUnboxedFloat32x4:
803 __ LoadQImmediate(destination.fpu_reg(),
804 Float32x4::Cast(value_).value());
806 case kUnboxedInt32x4:
807 __ LoadQImmediate(destination.fpu_reg(), Int32x4::Cast(value_).value());
812 }
else if (destination.IsDoubleStackSlot()) {
813 ASSERT(representation() == kUnboxedDouble);
814 __ LoadDImmediate(
VTMP, Double::Cast(value_).
value());
815 const intptr_t dest_offset = destination.ToStackSlotOffset();
816 __ StoreDToOffset(
VTMP, destination.base_reg(), dest_offset);
817 }
else if (destination.IsQuadStackSlot()) {
818 switch (representation()) {
819 case kUnboxedFloat64x2:
820 __ LoadQImmediate(
VTMP, Float64x2::Cast(value_).
value());
822 case kUnboxedFloat32x4:
823 __ LoadQImmediate(
VTMP, Float32x4::Cast(value_).
value());
825 case kUnboxedInt32x4:
826 __ LoadQImmediate(
VTMP, Int32x4::Cast(value_).
value());
832 ASSERT(destination.IsStackSlot());
834 const intptr_t dest_offset = destination.ToStackSlotOffset();
836 if (representation() == kUnboxedInt32 ||
837 representation() == kUnboxedUint32 ||
838 representation() == kUnboxedInt64) {
839 const int64_t
value = Integer::Cast(value_).AsInt64Value();
845 }
else if (representation() == kUnboxedFloat) {
847 bit_cast<int32_t, float>(Double::Cast(value_).
value());
851 ASSERT(representation() == kTagged);
852 if (value_.IsNull()) {
854 }
else if (value_.IsSmi() && Smi::Cast(value_).Value() == 0) {
857 __ LoadObject(tmp, value_);
860 __ StoreToOffset(tmp, destination.base_reg(), dest_offset, operand_size);
864LocationSummary* UnboxedConstantInstr::MakeLocationSummary(Zone* zone,
866 const bool is_unboxed_int =
869 compiler::target::kWordSize);
870 const intptr_t kNumInputs = 0;
871 const intptr_t kNumTemps = is_unboxed_int ? 0 : 1;
872 LocationSummary* locs =
new (zone)
874 if (is_unboxed_int) {
890void UnboxedConstantInstr::EmitNativeCode(FlowGraphCompiler*
compiler) {
891 if (!locs()->
out(0).IsInvalid()) {
895 : locs()->temp(0).reg();
900LocationSummary* AssertAssignableInstr::MakeLocationSummary(Zone* zone,
902 auto const dst_type_loc =
912 const intptr_t kNonChangeableInputRegs =
914 ((dst_type_loc.IsRegister() ? 1 : 0) << TypeTestABI::kDstTypeReg) |
915 (1 << TypeTestABI::kInstantiatorTypeArgumentsReg) |
916 (1 << TypeTestABI::kFunctionTypeArgumentsReg);
925 const intptr_t kCpuRegistersToPreserve =
927 const intptr_t kFpuRegistersToPreserve =
933 LocationSummary* summary =
new (zone) LocationSummary(
946 intptr_t next_temp = 0;
948 const bool should_preserve = ((1 << i) & kCpuRegistersToPreserve) != 0;
949 if (should_preserve) {
950 summary->set_temp(next_temp++,
956 const bool should_preserve = ((1l << i) & kFpuRegistersToPreserve) != 0;
957 if (should_preserve) {
966void AssertBooleanInstr::EmitNativeCode(FlowGraphCompiler*
compiler) {
967 ASSERT(locs()->always_calls());
969 auto object_store =
compiler->isolate_group()->object_store();
970 const auto& assert_boolean_stub =
973 compiler::Label
done;
976 UntaggedPcDescriptors::kOther, locs(),
1002 switch (condition) {
1029static void EmitBranchOnCondition(FlowGraphCompiler*
compiler,
1031 BranchLabels labels) {
1032 if (labels.fall_through == labels.false_label) {
1034 __ b(labels.true_label, true_condition);
1038 __ b(labels.false_label, false_condition);
1041 if (labels.fall_through != labels.true_label) {
1042 __ b(labels.true_label);
1047static bool AreLabelsNull(BranchLabels labels) {
1048 return (labels.true_label ==
nullptr && labels.false_label ==
nullptr &&
1049 labels.fall_through ==
nullptr);
1052static bool CanUseCbzTbzForComparison(FlowGraphCompiler*
compiler,
1055 BranchLabels labels) {
1056 return !AreLabelsNull(labels) &&
__ CanGenerateCbzTbz(rn, cond);
1059static void EmitCbzTbz(
Register reg,
1062 BranchLabels labels,
1064 ASSERT(CanUseCbzTbzForComparison(
compiler, reg, true_condition, labels));
1065 if (labels.fall_through == labels.false_label) {
1067 __ GenerateCbzTbz(reg, true_condition, labels.true_label, sz);
1071 __ GenerateCbzTbz(reg, false_condition, labels.false_label, sz);
1074 if (labels.fall_through != labels.true_label) {
1075 __ b(labels.true_label);
1081 LocationSummary* locs,
1083 BranchLabels labels) {
1088 Condition true_condition = TokenKindToIntCondition(kind);
1089 if (
left.IsConstant() ||
right.IsConstant()) {
1091 ConstantInstr* constant =
nullptr;
1092 if (
left.IsConstant()) {
1093 constant =
left.constant_instruction();
1097 true_condition = FlipCondition(true_condition);
1099 constant =
right.constant_instruction();
1102 ASSERT(constant->representation() == kTagged);
1105 CanUseCbzTbzForComparison(
compiler,
left.reg(), true_condition,
1107 EmitCbzTbz(
left.reg(),
compiler, true_condition, labels,
1113 __ CompareObjectRegisters(
left.reg(),
right.reg());
1115 return true_condition;
1125 LocationSummary* locs,
1127 BranchLabels labels) {
1132 Condition true_condition = TokenKindToIntCondition(kind);
1133 if (
left.IsConstant() ||
right.IsConstant()) {
1135 ConstantInstr* constant =
nullptr;
1136 if (
left.IsConstant()) {
1137 constant =
left.constant_instruction();
1141 true_condition = FlipCondition(true_condition);
1143 constant =
right.constant_instruction();
1150 if (value == 0 && CanUseCbzTbzForComparison(
compiler,
left.reg(),
1151 true_condition, labels)) {
1152 EmitCbzTbz(
left.reg(),
compiler, true_condition, labels,
1156 __ CompareImmediate(
left.reg(), value);
1163 return true_condition;
1167 LocationSummary* locs,
1169 BranchLabels labels) {
1170 ASSERT((kind == Token::kEQ) || (kind == Token::kNE));
1173 const Condition true_condition = TokenKindToIntCondition(kind);
1174 compiler::Label* equal_result =
1175 (true_condition ==
EQ) ? labels.true_label : labels.false_label;
1176 compiler::Label* not_equal_result =
1177 (true_condition ==
EQ) ? labels.false_label : labels.true_label;
1182 __ b(equal_result,
EQ);
1184 __ BranchIfSmi(
TMP, not_equal_result);
1185 __ CompareClassId(
left, kMintCid);
1186 __ b(not_equal_result,
NE);
1187 __ CompareClassId(
right, kMintCid);
1188 __ b(not_equal_result,
NE);
1192 return true_condition;
1195LocationSummary* EqualityCompareInstr::MakeLocationSummary(Zone* zone,
1197 const intptr_t kNumInputs = 2;
1198 if (operation_cid() == kDoubleCid) {
1199 const intptr_t kNumTemps = 0;
1200 LocationSummary* locs =
new (zone)
1207 if (operation_cid() == kSmiCid || operation_cid() == kMintCid ||
1208 operation_cid() == kIntegerCid) {
1209 const intptr_t kNumTemps = 0;
1210 LocationSummary* locs =
new (zone)
1220 locs->set_in(1, locs->in(0).IsConstant()
1252 LocationSummary* locs,
1253 BranchLabels labels,
1284 BranchLabels labels) {
1286 ASSERT(operation_cid() == kMintCid);
1287 return EmitNullAwareInt64ComparisonOp(
compiler, locs(), kind(), labels);
1289 if (operation_cid() == kSmiCid) {
1290 return EmitSmiComparisonOp(
compiler, locs(), kind(), labels);
1291 }
else if (operation_cid() == kMintCid || operation_cid() == kIntegerCid) {
1292 return EmitInt64ComparisonOp(
compiler, locs(), kind(), labels);
1294 ASSERT(operation_cid() == kDoubleCid);
1295 return EmitDoubleComparisonOp(
compiler, locs(), labels, kind());
1299LocationSummary* TestSmiInstr::MakeLocationSummary(Zone* zone,
bool opt)
const {
1300 const intptr_t kNumInputs = 2;
1301 const intptr_t kNumTemps = 0;
1302 LocationSummary* locs =
new (zone)
1312 BranchLabels labels) {
1315 if (
right.IsConstant()) {
1322 Condition true_condition = (kind() == Token::kNE) ?
NE :
EQ;
1323 return true_condition;
1326LocationSummary* TestCidsInstr::MakeLocationSummary(Zone* zone,
1328 const intptr_t kNumInputs = 1;
1329 const intptr_t kNumTemps = 1;
1330 LocationSummary* locs =
new (zone)
1339 BranchLabels labels) {
1340 ASSERT((kind() == Token::kIS) || (kind() == Token::kISNOT));
1341 const Register val_reg = locs()->in(0).reg();
1342 const Register cid_reg = locs()->temp(0).reg();
1344 compiler::Label* deopt =
1346 ?
compiler->AddDeoptStub(deopt_id(), ICData::kDeoptTestCids)
1349 const intptr_t true_result = (kind() == Token::kIS) ? 1 : 0;
1353 __ BranchIfSmi(val_reg,
result ? labels.true_label : labels.false_label);
1354 __ LoadClassId(cid_reg, val_reg);
1356 for (intptr_t i = 2; i <
data.length(); i += 2) {
1357 const intptr_t test_cid =
data[i];
1358 ASSERT(test_cid != kSmiCid);
1360 __ CompareImmediate(cid_reg, test_cid);
1361 __ b(
result ? labels.true_label : labels.false_label,
EQ);
1364 if (deopt ==
nullptr) {
1368 compiler::Label*
target =
result ? labels.false_label : labels.true_label;
1369 if (
target != labels.fall_through) {
1380LocationSummary* RelationalOpInstr::MakeLocationSummary(Zone* zone,
1382 const intptr_t kNumInputs = 2;
1383 const intptr_t kNumTemps = 0;
1384 if (operation_cid() == kDoubleCid) {
1385 LocationSummary* summary =
new (zone)
1392 if (operation_cid() == kSmiCid || operation_cid() == kMintCid) {
1393 LocationSummary* summary =
new (zone)
1398 summary->set_in(1, summary->in(0).IsConstant()
1410 BranchLabels labels) {
1411 if (operation_cid() == kSmiCid) {
1412 return EmitSmiComparisonOp(
compiler, locs(), kind(), labels);
1413 }
else if (operation_cid() == kMintCid) {
1414 return EmitInt64ComparisonOp(
compiler, locs(), kind(), labels);
1416 ASSERT(operation_cid() == kDoubleCid);
1417 return EmitDoubleComparisonOp(
compiler, locs(), labels, kind());
1435 stub = &StubCode::CallBootstrapNative();
1440 stub = &StubCode::CallBootstrapNative();
1442 stub = &StubCode::CallAutoScopeNative();
1444 stub = &StubCode::CallNoScopeNative();
1447 __ LoadImmediate(
R1, argc_tag);
1448 compiler::ExternalLabel label(entry);
1449 __ LoadNativeEntry(
R5, &label,
1450 link_lazily() ? ObjectPool::Patchability::kPatchable
1451 : ObjectPool::Patchability::kNotPatchable);
1454 source(), *stub, UntaggedPcDescriptors::kOther,
locs(),
1459 compiler->GenerateNonLazyDeoptableStubCall(
1460 source(), *stub, UntaggedPcDescriptors::kOther,
locs(),
1468#define R(r) (1 << r)
1471 bool is_optimizing)
const {
1472 return MakeLocationSummaryInternal(
1473 zone, is_optimizing,
1503 __ LoadObject(
CODE_REG, Object::null_object());
1504 __ set_constant_pool_allowed(
false);
1505 __ EnterDartFrame(0,
PP);
1509 intptr_t stack_space = marshaller_.RequiredStackSpaceInBytes();
1510 __ ReserveAlignedFrameSpace(stack_space);
1511#if defined(USING_MEMORY_SANITIZER)
1516 SPILLS_LR_TO_FRAME(
__ PushRegisters(kVolatileRegisterSet));
1522 __ sub(
R1, is_leaf_ ?
FPREG : saved_fp_or_sp, temp1);
1523 __ MsanUnpoison(temp1,
R1);
1527 __ MsanUnpoison(is_leaf_ ?
FPREG : saved_fp_or_sp,
1532 __ CallCFunction(compiler::Address(
1533 THR, kMsanUnpoisonParamRuntimeEntry.OffsetFromThread()));
1535 RESTORES_LR_FROM_FRAME(
__ PopRegisters(kVolatileRegisterSet));
1542 __ Comment(is_leaf_ ?
"Leaf Call" :
"Call");
1546#if !defined(PRODUCT)
1550 compiler::target::Thread::top_exit_frame_info_offset());
1551 __ StoreToOffset(branch,
THR, compiler::target::Thread::vm_tag_offset());
1556 __ mov(temp_csp,
CSP);
1563 __ mov(
CSP, temp_csp);
1565#if !defined(PRODUCT)
1566 __ LoadImmediate(temp1, compiler::target::Thread::vm_tag_dart_id());
1567 __ StoreToOffset(temp1,
THR, compiler::target::Thread::vm_tag_offset());
1569 compiler::target::Thread::top_exit_frame_info_offset());
1579 UntaggedPcDescriptors::Kind::kOther,
locs(),
1589 THR, compiler::target::Thread::
1590 call_native_through_safepoint_entry_point_offset()));
1597 __ Comment(
"Check Dart_Handle for Error.");
1598 compiler::Label not_error;
1601 compiler::target::LocalHandle::ptr_offset()));
1602 __ BranchIfSmi(temp1, ¬_error);
1603 __ LoadClassId(temp1, temp1);
1608 __ Comment(
"Slow path: call Dart_PropagateError through stub.");
1613 THR, compiler::target::Thread::
1614 call_native_through_safepoint_entry_point_offset()));
1615 __ ldr(branch, compiler::Address(
1616 THR, kPropagateErrorRuntimeEntry.OffsetFromThread()));
1623 __ Bind(¬_error);
1628 __ RestorePinnedRegisters();
1635 __ mov(
SPREG, saved_fp_or_sp);
1637 __ LeaveDartFrame();
1641 if (FLAG_precompiled_mode) {
1642 __ SetupGlobalPoolAndDispatchTable();
1645 __ set_constant_pool_allowed(
true);
1653 __ LeaveDartFrame();
1660 const Register old_exit_through_ffi_reg =
R4;
1663 __ PopPair(old_exit_frame_reg, old_exit_through_ffi_reg);
1666 __ PopPair(tmp, vm_tag_reg);
1667 __ StoreToOffset(tmp,
THR, compiler::target::Thread::top_resource_offset());
1672 __ TransitionGeneratedToNative(vm_tag_reg, old_exit_frame_reg,
1673 old_exit_through_ffi_reg,
1676 __ PopNativeCalleeSavedRegisters();
1690 __ set_constant_pool_allowed(
true);
1694void NativeEntryInstr::EmitNativeCode(FlowGraphCompiler*
compiler) {
1696 __ set_constant_pool_allowed(
false);
1718 __ PushImmediate(0);
1720 __ PushNativeCalleeSavedRegisters();
1723 __ SetupCSPFromThread(
THR);
1725#if defined(DART_TARGET_OS_FUCHSIA)
1728 THR, compiler::target::Thread::saved_shadow_call_stack_offset()));
1729#elif defined(USING_SHADOW_CALL_STACK)
1734 __ RestorePinnedRegisters();
1737 __ LoadFromOffset(
TMP,
THR, compiler::target::Thread::vm_tag_offset());
1739 __ LoadFromOffset(
R0,
THR, compiler::target::Thread::top_resource_offset());
1742 __ StoreToOffset(
ZR,
THR, compiler::target::Thread::top_resource_offset());
1745 compiler::target::Thread::exit_through_ffi_offset());
1751 compiler::target::Thread::top_exit_frame_info_offset());
1756 __ EmitEntryFrameVerification();
1759 __ TransitionNativeToGenerated(
R0,
false);
1765 const Function& target_function = marshaller_.dart_signature();
1766 const intptr_t callback_id = target_function.FfiCallbackId();
1767 __ LoadFromOffset(
R0,
THR, compiler::target::Thread::isolate_group_offset());
1768 __ LoadFromOffset(
R0,
R0,
1769 compiler::target::IsolateGroup::object_store_offset());
1770 __ LoadFromOffset(
R0,
R0,
1771 compiler::target::ObjectStore::ffi_callback_code_offset());
1772 __ LoadCompressedFieldFromOffset(
1773 R0,
R0, compiler::target::GrowableObjectArray::data_offset());
1774 __ LoadCompressedFieldFromOffset(
1776 compiler::target::Array::data_offset() +
1777 callback_id * compiler::target::kCompressedWordSize);
1782 if (FLAG_precompiled_mode) {
1783 __ SetupGlobalPoolAndDispatchTable();
1798 compiler::target::Thread::invoke_dart_code_stub_offset());
1799 __ LoadFieldFromOffset(
LR,
LR,
1800 compiler::target::Code::entry_point_offset());
1803 FunctionEntryInstr::EmitNativeCode(
compiler);
1806#define R(r) (1 << r)
1810 bool is_optimizing)
const {
1824 __ MoveRegister(saved_fp,
FPREG);
1826 const intptr_t frame_space = native_calling_convention_.
StackTopInBytes();
1827 __ EnterCFrame(frame_space);
1829 __ mov(saved_csp,
CSP);
1835 __ str(target_address,
1836 compiler::Address(
THR, compiler::target::Thread::vm_tag_offset()));
1837 __ CallCFunction(target_address);
1838 __ LoadImmediate(temp0, VMTag::kDartTagId);
1840 compiler::Address(
THR, compiler::target::Thread::vm_tag_offset()));
1844 __ mov(
CSP, saved_csp);
1848LocationSummary* OneByteStringFromCharCodeInstr::MakeLocationSummary(
1851 const intptr_t kNumInputs = 1;
1857void OneByteStringFromCharCodeInstr::EmitNativeCode(
1864 compiler::Address(
THR, Thread::predefined_symbols_address_offset()));
1871LocationSummary* StringToCharCodeInstr::MakeLocationSummary(Zone* zone,
1873 const intptr_t kNumInputs = 1;
1878void StringToCharCodeInstr::EmitNativeCode(FlowGraphCompiler*
compiler) {
1879 ASSERT(cid_ == kOneByteStringCid);
1892LocationSummary* Utf8ScanInstr::MakeLocationSummary(Zone* zone,
1894 const intptr_t kNumInputs = 5;
1895 const intptr_t kNumTemps = 0;
1896 LocationSummary* summary =
new (zone)
1907void Utf8ScanInstr::EmitNativeCode(FlowGraphCompiler*
compiler) {
1908 const Register bytes_reg = locs()->in(1).reg();
1909 const Register start_reg = locs()->in(2).reg();
1910 const Register end_reg = locs()->in(3).reg();
1911 const Register table_reg = locs()->in(4).reg();
1912 const Register size_reg = locs()->out(0).reg();
1914 const Register bytes_ptr_reg = start_reg;
1915 const Register bytes_end_reg = end_reg;
1916 const Register flags_reg = bytes_reg;
1918 const Register decoder_temp_reg = start_reg;
1919 const Register flags_temp_reg = end_reg;
1921 const intptr_t kSizeMask = 0x03;
1922 const intptr_t kFlagsMask = 0x3C;
1924 compiler::Label loop, loop_in;
1927 __ LoadFromSlot(bytes_reg, bytes_reg, Slot::PointerBase_data());
1931 table_reg, table_reg,
1932 compiler::target::OneByteString::data_offset() -
kHeapObjectTag);
1935 __ add(bytes_ptr_reg, bytes_reg, compiler::Operand(start_reg));
1936 __ add(bytes_end_reg, bytes_reg, compiler::Operand(end_reg));
1939 __ mov(size_reg,
ZR);
1940 __ mov(flags_reg,
ZR);
1951 __ ldr(temp_reg, compiler::Address(table_reg, temp_reg),
1953 __ orr(flags_reg, flags_reg, compiler::Operand(temp_reg));
1954 __ andi(temp_reg, temp_reg, compiler::Immediate(kSizeMask));
1955 __ add(size_reg, size_reg, compiler::Operand(temp_reg));
1959 __ cmp(bytes_ptr_reg, compiler::Operand(bytes_end_reg));
1963 __ AndImmediate(flags_reg, flags_reg, kFlagsMask);
1965 __ SmiTag(flags_reg);
1968 const Location decoder_location = locs()->in(0);
1969 if (decoder_location.IsStackSlot()) {
1971 decoder_reg = decoder_temp_reg;
1973 decoder_reg = decoder_location.reg();
1975 const auto scan_flags_field_offset = scan_flags_field_.offset_in_bytes();
1977 __ LoadCompressedSmiFieldFromOffset(flags_temp_reg, decoder_reg,
1978 scan_flags_field_offset);
1979 __ orr(flags_temp_reg, flags_temp_reg, compiler::Operand(flags_reg),
1981 __ StoreFieldToOffset(flags_temp_reg, decoder_reg, scan_flags_field_offset,
1984 __ LoadFieldFromOffset(flags_temp_reg, decoder_reg,
1985 scan_flags_field_offset);
1986 __ orr(flags_temp_reg, flags_temp_reg, compiler::Operand(flags_reg));
1987 __ StoreFieldToOffset(flags_temp_reg, decoder_reg, scan_flags_field_offset);
1991LocationSummary* LoadIndexedInstr::MakeLocationSummary(Zone* zone,
1998 const intptr_t kNumInputs = 2;
1999 const intptr_t kNumTemps = 0;
2000 LocationSummary* locs =
new (zone)
2003 const bool can_be_constant =
2023void LoadIndexedInstr::EmitNativeCode(FlowGraphCompiler*
compiler) {
2028 compiler::Address element_address(
TMP);
2029 element_address =
index.IsRegister()
2030 ?
__ ElementAddressForRegIndex(
2033 :
__ ElementAddressForIntIndex(
2044 if (rep == kUnboxedFloat) {
2047 }
else if (rep == kUnboxedDouble) {
2051 ASSERT(rep == kUnboxedInt32x4 || rep == kUnboxedFloat32x4 ||
2052 rep == kUnboxedFloat64x2);
2060 __ LoadCompressed(
result, element_address);
2064LocationSummary* LoadCodeUnitsInstr::MakeLocationSummary(Zone* zone,
2066 const intptr_t kNumInputs = 2;
2067 const intptr_t kNumTemps = 0;
2068 LocationSummary* summary =
new (zone)
2076void LoadCodeUnitsInstr::EmitNativeCode(FlowGraphCompiler*
compiler) {
2078 const Register str = locs()->in(0).reg();
2084 case kOneByteStringCid:
2099 case kTwoByteStringCid:
2116 compiler::Address element_address =
__ ElementAddressForRegIndexWithSize(
2119 __ ldr(
result, element_address, sz);
2125LocationSummary* StoreIndexedInstr::MakeLocationSummary(Zone* zone,
2132 const intptr_t kNumInputs = 3;
2133 const intptr_t kNumTemps = 1;
2134 LocationSummary* locs =
new (zone)
2137 const bool can_be_constant =
2141 locs->set_in(1, can_be_constant
2148 ASSERT(rep == kUnboxedUint8);
2152 if (constant !=
nullptr && constant->HasZeroRepresentation()) {
2158 if (rep == kUnboxedFloat || rep == kUnboxedDouble) {
2160 if (constant !=
nullptr && constant->HasZeroRepresentation()) {
2168 }
else if (
class_id() == kArrayCid) {
2182void StoreIndexedInstr::EmitNativeCode(FlowGraphCompiler*
compiler) {
2186 const Register temp = locs()->temp(0).reg();
2187 compiler::Address element_address(
TMP);
2195 if (
index.IsRegister()) {
2205 __ StoreCompressedIntoArray(
array, temp,
value, CanValueBeSmi());
2209 element_address =
index.IsRegister()
2210 ?
__ ElementAddressForRegIndex(
2213 :
__ ElementAddressForIntIndex(
2218 ASSERT(rep == kUnboxedUint8);
2220 const Smi& constant = Smi::Cast(locs()->in(2).constant());
2225 }
else if (
value < 0) {
2231 __ LoadImmediate(
TMP,
static_cast<int8_t
>(
value));
2237 __ CompareImmediate(
value, 0xFF);
2244 ASSERT(locs()->in(2).constant_instruction()->HasZeroRepresentation());
2247 __ str(locs()->in(2).reg(), element_address,
2251 if (rep == kUnboxedFloat) {
2253 ASSERT(locs()->in(2).constant_instruction()->HasZeroRepresentation());
2256 __ fstrs(locs()->in(2).fpu_reg(), element_address);
2258 }
else if (rep == kUnboxedDouble) {
2260 ASSERT(locs()->in(2).constant_instruction()->HasZeroRepresentation());
2263 __ fstrd(locs()->in(2).fpu_reg(), element_address);
2266 ASSERT(rep == kUnboxedInt32x4 || rep == kUnboxedFloat32x4 ||
2267 rep == kUnboxedFloat64x2);
2268 const VRegister value_reg = locs()->in(2).fpu_reg();
2269 __ fstrq(value_reg, element_address);
2271 }
else if (
class_id() == kArrayCid) {
2274 const Object& constant = locs()->in(2).constant();
2275 __ StoreCompressedObjectIntoObjectNoBarrier(
array, element_address,
2279 __ StoreCompressedIntoObjectNoBarrier(
array, element_address,
value);
2285#if defined(USING_MEMORY_SANITIZER)
2286 if (
index.IsRegister()) {
2297 __ MsanUnpoison(
TMP, length_in_bytes);
2301static void LoadValueCid(FlowGraphCompiler*
compiler,
2304 compiler::Label* value_is_smi =
nullptr) {
2305 compiler::Label
done;
2306 if (value_is_smi ==
nullptr) {
2307 __ LoadImmediate(value_cid_reg, kSmiCid);
2309 __ BranchIfSmi(value_reg, value_is_smi ==
nullptr ? &
done : value_is_smi);
2310 __ LoadClassId(value_cid_reg, value_reg);
2316LocationSummary* GuardFieldClassInstr::MakeLocationSummary(Zone* zone,
2318 const intptr_t kNumInputs = 1;
2323 const bool emit_full_guard = !opt || (field_cid ==
kIllegalCid);
2325 const bool needs_value_cid_temp_reg =
2326 emit_full_guard || ((value_cid ==
kDynamicCid) && (field_cid != kSmiCid));
2328 const bool needs_field_temp_reg = emit_full_guard;
2330 intptr_t num_temps = 0;
2331 if (needs_value_cid_temp_reg) {
2334 if (needs_field_temp_reg) {
2338 LocationSummary* summary =
new (zone)
2342 for (intptr_t i = 0; i < num_temps; i++) {
2349void GuardFieldClassInstr::EmitNativeCode(FlowGraphCompiler*
compiler) {
2350 ASSERT(compiler::target::UntaggedObject::kClassIdTagSize == 20);
2351 ASSERT(
sizeof(UntaggedField::guarded_cid_) == 4);
2352 ASSERT(
sizeof(UntaggedField::is_nullable_) == 4);
2362 const bool emit_full_guard =
2365 const bool needs_value_cid_temp_reg =
2366 emit_full_guard || ((value_cid ==
kDynamicCid) && (field_cid != kSmiCid));
2368 const bool needs_field_temp_reg = emit_full_guard;
2370 const Register value_reg = locs()->in(0).reg();
2373 needs_value_cid_temp_reg ? locs()->temp(0).reg() :
kNoRegister;
2375 const Register field_reg = needs_field_temp_reg
2376 ? locs()->temp(locs()->temp_count() - 1).reg()
2379 compiler::Label
ok, fail_label;
2381 compiler::Label* deopt =
2383 ?
compiler->AddDeoptStub(deopt_id(), ICData::kDeoptGuardField)
2386 compiler::Label*
fail = (deopt !=
nullptr) ? deopt : &fail_label;
2388 if (emit_full_guard) {
2391 compiler::FieldAddress field_cid_operand(field_reg,
2393 compiler::FieldAddress field_nullability_operand(
2397 LoadValueCid(
compiler, value_cid_reg, value_reg);
2398 compiler::Label skip_length_check;
2400 __ CompareRegisters(value_cid_reg,
TMP);
2403 __ CompareRegisters(value_cid_reg,
TMP);
2404 }
else if (value_cid ==
kNullCid) {
2405 __ ldr(value_cid_reg, field_nullability_operand,
2407 __ CompareImmediate(value_cid_reg, value_cid);
2409 compiler::Label skip_length_check;
2411 __ CompareImmediate(value_cid_reg, value_cid);
2421 if (!
field().needs_length_check()) {
2430 __ str(value_cid_reg, field_nullability_operand,
2433 __ LoadImmediate(
TMP, value_cid);
2441 if (deopt ==
nullptr) {
2449 __ PushPair(value_reg, field_reg);
2451 __ CallRuntime(kUpdateFieldCidRuntimeEntry, 2);
2458 ASSERT(deopt !=
nullptr);
2465 if (field_cid != kSmiCid) {
2467 __ LoadClassId(value_cid_reg, value_reg);
2468 __ CompareImmediate(value_cid_reg, field_cid);
2473 __ CompareObject(value_reg, Object::null_object());
2477 }
else if (value_cid == field_cid) {
2482 ASSERT(value_cid != nullability);
2489LocationSummary* GuardFieldLengthInstr::MakeLocationSummary(Zone* zone,
2491 const intptr_t kNumInputs = 1;
2493 const intptr_t kNumTemps = 3;
2494 LocationSummary* summary =
new (zone)
2503 LocationSummary* summary =
new (zone)
2511void GuardFieldLengthInstr::EmitNativeCode(FlowGraphCompiler*
compiler) {
2516 compiler::Label* deopt =
2518 ?
compiler->AddDeoptStub(deopt_id(), ICData::kDeoptGuardField)
2521 const Register value_reg = locs()->in(0).reg();
2525 const Register field_reg = locs()->temp(0).reg();
2526 const Register offset_reg = locs()->temp(1).reg();
2527 const Register length_reg = locs()->temp(2).reg();
2534 compiler::FieldAddress(
2537 __ LoadCompressedSmi(
2541 __ tst(offset_reg, compiler::Operand(offset_reg));
2548 __ LoadCompressedSmi(
TMP, compiler::Address(value_reg, offset_reg));
2549 __ CompareObjectRegisters(length_reg,
TMP);
2551 if (deopt ==
nullptr) {
2554 __ PushPair(value_reg, field_reg);
2556 __ CallRuntime(kUpdateFieldCidRuntimeEntry, 2);
2566 ASSERT(
field().guarded_list_length_in_object_offset() !=
2569 __ ldr(
TMP, compiler::FieldAddress(
2570 value_reg,
field().guarded_list_length_in_object_offset()));
2576LocationSummary* StoreStaticFieldInstr::MakeLocationSummary(Zone* zone,
2578 const intptr_t kNumInputs = 1;
2579 const intptr_t kNumTemps = 1;
2580 LocationSummary* locs =
new (zone)
2587void StoreStaticFieldInstr::EmitNativeCode(FlowGraphCompiler*
compiler) {
2589 const Register temp = locs()->temp(0).reg();
2593 __ LoadFromOffset(temp,
THR,
2594 compiler::target::Thread::field_table_values_offset());
2597 compiler::target::FieldTable::OffsetOf(
field()));
2600LocationSummary* InstanceOfInstr::MakeLocationSummary(Zone* zone,
2602 const intptr_t kNumInputs = 3;
2603 const intptr_t kNumTemps = 0;
2604 LocationSummary* summary =
new (zone)
2615void InstanceOfInstr::EmitNativeCode(FlowGraphCompiler*
compiler) {
2626 const intptr_t kNumInputs = 2;
2627 const intptr_t kNumTemps = 0;
2628 LocationSummary*
locs =
new (zone)
2639static void InlineArrayAllocation(FlowGraphCompiler*
compiler,
2640 intptr_t num_elements,
2641 compiler::Label* slow_path,
2642 compiler::Label*
done) {
2643 const int kInlineArraySize = 12;
2646 __ TryAllocateArray(kArrayCid, instance_size, slow_path,
2654 __ StoreCompressedIntoObjectNoBarrier(
2661 __ StoreCompressedIntoObjectNoBarrier(
2673 if (num_elements > 0) {
2674 const intptr_t array_size = instance_size -
sizeof(UntaggedArray);
2678 intptr_t current_offset = 0;
2679 while (current_offset < array_size) {
2680 __ StoreCompressedIntoObjectNoBarrier(
2686 compiler::Label end_loop, init_loop;
2687 __ Bind(&init_loop);
2688 __ CompareRegisters(
R8,
R3);
2689 __ b(&end_loop,
CS);
2701 TypeUsageInfo* type_usage_info =
compiler->thread()->type_usage_info();
2702 if (type_usage_info !=
nullptr) {
2703 const Class& list_class =
2709 compiler::Label slow_path,
done;
2710 if (!FLAG_use_slow_path && FLAG_inline_alloc) {
2711 if (
compiler->is_optimizing() && !FLAG_precompiled_mode &&
2722 __ Bind(&slow_path);
2723 auto object_store =
compiler->isolate_group()->object_store();
2724 const auto& allocate_array_stub =
2736 const intptr_t kNumInputs = 0;
2737 const intptr_t kNumTemps = 3;
2738 LocationSummary*
locs =
new (zone) LocationSummary(
2747class AllocateContextSlowPath
2748 :
public TemplateSlowPathCode<AllocateUninitializedContextInstr> {
2750 explicit AllocateContextSlowPath(
2751 AllocateUninitializedContextInstr* instruction)
2752 : TemplateSlowPathCode(instruction) {}
2754 virtual void EmitNativeCode(FlowGraphCompiler*
compiler) {
2755 __ Comment(
"AllocateContextSlowPath");
2756 __ Bind(entry_label());
2758 LocationSummary* locs = instruction()->locs();
2759 locs->live_registers()->Remove(locs->out(0));
2763 auto slow_path_env =
compiler->SlowPathEnvironmentFor(
2765 ASSERT(slow_path_env !=
nullptr);
2767 auto object_store =
compiler->isolate_group()->object_store();
2768 const auto& allocate_context_stub = Code::ZoneHandle(
2769 compiler->zone(), object_store->allocate_context_stub());
2771 __ LoadImmediate(R1, instruction()->num_context_variables());
2772 compiler->GenerateStubCall(instruction()->
source(), allocate_context_stub,
2773 UntaggedPcDescriptors::kOther, locs,
2774 instruction()->deopt_id(), slow_path_env);
2775 ASSERT(instruction()->locs()->
out(0).reg() == R0);
2776 compiler->RestoreLiveRegisters(instruction()->locs());
2788 AllocateContextSlowPath* slow_path =
new AllocateContextSlowPath(
this);
2789 compiler->AddSlowPathCode(slow_path);
2792 if (!FLAG_use_slow_path && FLAG_inline_alloc) {
2793 __ TryAllocateArray(kContextCid, instance_size, slow_path->entry_label(),
2795 temp0, temp1, temp2);
2802 __ Jump(slow_path->entry_label());
2805 __ Bind(slow_path->exit_label());
2810 const intptr_t kNumInputs = 0;
2811 const intptr_t kNumTemps = 1;
2812 LocationSummary*
locs =
new (zone)
2823 auto object_store =
compiler->isolate_group()->object_store();
2824 const auto& allocate_context_stub =
2832LocationSummary* CloneContextInstr::MakeLocationSummary(Zone* zone,
2834 const intptr_t kNumInputs = 1;
2835 const intptr_t kNumTemps = 0;
2836 LocationSummary* locs =
new (zone)
2843void CloneContextInstr::EmitNativeCode(FlowGraphCompiler*
compiler) {
2847 auto object_store =
compiler->isolate_group()->object_store();
2848 const auto& clone_context_stub =
2851 UntaggedPcDescriptors::kOther, locs(),
2855LocationSummary* CatchBlockEntryInstr::MakeLocationSummary(Zone* zone,
2860void CatchBlockEntryInstr::EmitNativeCode(FlowGraphCompiler*
compiler) {
2862 compiler->AddExceptionHandler(
this);
2869 const intptr_t fp_sp_dist =
2870 (compiler::target::frame_layout.first_local_from_fp + 1 -
2874 __ AddImmediate(
SP,
FP, fp_sp_dist);
2877 if (raw_exception_var_ !=
nullptr) {
2880 compiler::target::FrameOffsetInBytesForVariable(raw_exception_var_));
2882 if (raw_stacktrace_var_ !=
nullptr) {
2885 compiler::target::FrameOffsetInBytesForVariable(raw_stacktrace_var_));
2890LocationSummary* CheckStackOverflowInstr::MakeLocationSummary(Zone* zone,
2892 const intptr_t kNumInputs = 0;
2893 const intptr_t kNumTemps = 1;
2895 LocationSummary* summary =
new (zone)
2896 LocationSummary(zone, kNumInputs, kNumTemps,
2898 : LocationSummary::kCallOnSlowPath);
2903class CheckStackOverflowSlowPath
2904 :
public TemplateSlowPathCode<CheckStackOverflowInstr> {
2906 static constexpr intptr_t kNumSlowPathArgs = 0;
2908 explicit CheckStackOverflowSlowPath(CheckStackOverflowInstr* instruction)
2909 : TemplateSlowPathCode(instruction) {}
2911 virtual void EmitNativeCode(FlowGraphCompiler*
compiler) {
2912 auto locs = instruction()->locs();
2913 if (
compiler->isolate_group()->use_osr() && osr_entry_label()->IsLinked()) {
2915 __ Comment(
"CheckStackOverflowSlowPathOsr");
2916 __ Bind(osr_entry_label());
2917 __ LoadImmediate(value, Thread::kOsrRequest);
2919 compiler::Address(THR, Thread::stack_overflow_flags_offset()));
2921 __ Comment(
"CheckStackOverflowSlowPath");
2922 __ Bind(entry_label());
2923 const bool using_shared_stub = locs->call_on_shared_slow_path();
2924 if (!using_shared_stub) {
2931 compiler->SlowPathEnvironmentFor(instruction(), kNumSlowPathArgs);
2934 const bool has_frame =
compiler->flow_graph().graph_entry()->NeedsFrame();
2935 if (using_shared_stub) {
2937 ASSERT(
__ constant_pool_allowed());
2938 __ set_constant_pool_allowed(
false);
2939 __ EnterDartFrame(0);
2941 auto object_store =
compiler->isolate_group()->object_store();
2942 const bool live_fpu_regs = locs->live_registers()->FpuRegisterCount() > 0;
2943 const auto& stub = Code::ZoneHandle(
2946 ? object_store->stack_overflow_stub_with_fpu_regs_stub()
2947 : object_store->stack_overflow_stub_without_fpu_regs_stub());
2949 if (
compiler->CanPcRelativeCall(stub)) {
2950 __ GenerateUnRelocatedPcRelativeCall();
2951 compiler->AddPcRelativeCallStubTarget(stub);
2953 const uword entry_point_offset =
2954 Thread::stack_overflow_shared_stub_entry_point_offset(
2955 locs->live_registers()->FpuRegisterCount() > 0);
2956 __ Call(compiler::Address(THR, entry_point_offset));
2958 compiler->RecordSafepoint(locs, kNumSlowPathArgs);
2960 compiler->AddCurrentDescriptor(UntaggedPcDescriptors::kOther,
2961 instruction()->deopt_id(),
2962 instruction()->
source());
2964 __ LeaveDartFrame();
2965 __ set_constant_pool_allowed(
true);
2969 __ CallRuntime(kInterruptOrStackOverflowRuntimeEntry, kNumSlowPathArgs);
2971 instruction()->
source(), instruction()->deopt_id(),
2972 UntaggedPcDescriptors::kOther, instruction()->locs(),
env);
2976 instruction()->in_loop()) {
2978 compiler->AddCurrentDescriptor(UntaggedPcDescriptors::kOsrEntry,
2979 instruction()->deopt_id(),
2980 InstructionSource());
2982 compiler->pending_deoptimization_env_ =
nullptr;
2983 if (!using_shared_stub) {
2984 compiler->RestoreLiveRegisters(locs);
2989 compiler::Label* osr_entry_label() {
2990 ASSERT(IsolateGroup::Current()->use_osr());
2991 return &osr_entry_label_;
2995 compiler::Label osr_entry_label_;
2998void CheckStackOverflowInstr::EmitNativeCode(FlowGraphCompiler*
compiler) {
2999 CheckStackOverflowSlowPath* slow_path =
new CheckStackOverflowSlowPath(
this);
3000 compiler->AddSlowPathCode(slow_path);
3002 __ ldr(
TMP, compiler::Address(
3003 THR, compiler::target::Thread::stack_limit_offset()));
3005 __ b(slow_path->entry_label(),
LS);
3012 const intptr_t configured_optimization_counter_threshold =
3013 compiler->thread()->isolate_group()->optimization_counter_threshold();
3014 const int32_t threshold =
3015 configured_optimization_counter_threshold * (
loop_depth() + 1);
3016 __ LoadFieldFromOffset(
TMP,
function, Function::usage_counter_offset(),
3018 __ add(
TMP,
TMP, compiler::Operand(1));
3019 __ StoreFieldToOffset(
TMP,
function, Function::usage_counter_offset(),
3021 __ CompareImmediate(
TMP, threshold);
3022 __ b(slow_path->osr_entry_label(),
GE);
3024 if (
compiler->ForceSlowPathForStackOverflow()) {
3025 __ b(slow_path->entry_label());
3027 __ Bind(slow_path->exit_label());
3030static void EmitSmiShiftLeft(FlowGraphCompiler*
compiler,
3031 BinarySmiOpInstr* shift_left) {
3032 const LocationSummary& locs = *shift_left->locs();
3035 compiler::Label* deopt =
3036 shift_left->CanDeoptimize()
3037 ?
compiler->AddDeoptStub(shift_left->deopt_id(),
3038 ICData::kDeoptBinarySmiOp)
3040 if (locs.in(1).IsConstant()) {
3041 const Object& constant = locs.in(1).constant();
3042 ASSERT(constant.IsSmi());
3044#if !defined(DART_COMPRESSED_POINTERS)
3045 const intptr_t kCountLimit = 0x3F;
3047 const intptr_t kCountLimit = 0x1F;
3049 const intptr_t
value = Smi::Cast(constant).Value();
3050 ASSERT((0 < value) && (value < kCountLimit));
3051 if (shift_left->can_overflow()) {
3064 Range* right_range = shift_left->right_range();
3065 if (shift_left->left()->BindsToConstant() && shift_left->can_overflow()) {
3068 const Object& obj = shift_left->left()->BoundConstant();
3070 const intptr_t left_int = Smi::Cast(obj).Value();
3071 if (left_int == 0) {
3077 const intptr_t max_right =
3079 const bool right_needs_check =
3081 if (right_needs_check) {
3091 const bool right_needs_check =
3093 if (!shift_left->can_overflow()) {
3094 if (right_needs_check) {
3096 ASSERT(shift_left->CanDeoptimize());
3111 if (right_needs_check) {
3112 ASSERT(shift_left->CanDeoptimize());
3120 const Register temp = locs.temp(0).reg();
3130LocationSummary* BinarySmiOpInstr::MakeLocationSummary(Zone* zone,
3132 const intptr_t kNumInputs = 2;
3133 const intptr_t kNumTemps =
3138 LocationSummary* summary =
new (zone)
3140 if (
op_kind() == Token::kTRUNCDIV) {
3151 if (
op_kind() == Token::kMOD) {
3169void BinarySmiOpInstr::EmitNativeCode(FlowGraphCompiler*
compiler) {
3170 if (
op_kind() == Token::kSHL) {
3177 compiler::Label* deopt =
nullptr;
3178 if (CanDeoptimize()) {
3179 deopt =
compiler->AddDeoptStub(deopt_id(), ICData::kDeoptBinarySmiOp);
3183 const Object& constant = locs()->in(1).constant();
3184 ASSERT(constant.IsSmi());
3188 if (deopt ==
nullptr) {
3197 if (deopt ==
nullptr) {
3209 const intptr_t
value = Smi::Cast(constant).Value();
3210 __ LoadImmediate(
TMP, value);
3211#if !defined(DART_COMPRESSED_POINTERS)
3216 if (deopt !=
nullptr) {
3217#if !defined(DART_COMPRESSED_POINTERS)
3229 case Token::kTRUNCDIV: {
3230 const intptr_t
value = Smi::Cast(constant).Value();
3233 const intptr_t shift_count =
3236#if !defined(DART_COMPRESSED_POINTERS)
3243#if !defined(DART_COMPRESSED_POINTERS)
3244 __ add(temp,
left, compiler::Operand(
TMP,
LSR, 64 - shift_count));
3246 __ addw(temp,
left, compiler::Operand(
TMP,
LSR, 32 - shift_count));
3256 case Token::kBIT_AND:
3260 case Token::kBIT_OR:
3264 case Token::kBIT_XOR:
3270#if !defined(DART_COMPRESSED_POINTERS)
3271 const intptr_t kCountLimit = 0x3F;
3273 const intptr_t kCountLimit = 0x1F;
3275 intptr_t
value = Smi::Cast(constant).Value();
3283 case Token::kUSHR: {
3287 const intptr_t kCountLimit = 0x3F;
3288 intptr_t
value = Smi::Cast(constant).Value();
3289 ASSERT((value >= 0) && (value <= kCountLimit));
3292 if (deopt !=
nullptr) {
3293 __ SmiTagAndBranchIfOverflow(
result, deopt);
3309 if (deopt ==
nullptr) {
3318 if (deopt ==
nullptr) {
3328#if !defined(DART_COMPRESSED_POINTERS)
3333 if (deopt !=
nullptr) {
3334#if !defined(DART_COMPRESSED_POINTERS)
3346 case Token::kBIT_AND: {
3351 case Token::kBIT_OR: {
3356 case Token::kBIT_XOR: {
3361 case Token::kTRUNCDIV: {
3374#if !defined(DART_COMPRESSED_POINTERS)
3375 __ CompareImmediate(
result, 0x4000000000000000LL);
3407 compiler::Label
done;
3419 if (CanDeoptimize()) {
3424#if !defined(DART_COMPRESSED_POINTERS)
3425 const intptr_t kCountLimit = 0x3F;
3427 const intptr_t kCountLimit = 0x1F;
3430 __ LoadImmediate(
TMP2, kCountLimit);
3434 const Register temp = locs()->temp(0).reg();
3440 case Token::kUSHR: {
3441 if (CanDeoptimize()) {
3446 const intptr_t kCountLimit = 0x3F;
3448 compiler::Label
done;
3450 __ LoadImmediate(
TMP2, kCountLimit);
3455 const Register temp = locs()->temp(0).reg();
3458 if (deopt !=
nullptr) {
3459 __ SmiTagAndBranchIfOverflow(
result, deopt);
3485LocationSummary* CheckEitherNonSmiInstr::MakeLocationSummary(Zone* zone,
3489 ASSERT((left_cid != kDoubleCid) && (right_cid != kDoubleCid));
3490 const intptr_t kNumInputs = 2;
3491 const intptr_t kNumTemps = 0;
3492 LocationSummary* summary =
new (zone)
3499void CheckEitherNonSmiInstr::EmitNativeCode(FlowGraphCompiler*
compiler) {
3500 compiler::Label* deopt =
3501 compiler->AddDeoptStub(deopt_id(), ICData::kDeoptBinaryDoubleOp);
3506 if (this->
left()->definition() == this->
right()->definition()) {
3507 __ BranchIfSmi(
left, deopt);
3508 }
else if (left_cid == kSmiCid) {
3510 }
else if (right_cid == kSmiCid) {
3511 __ BranchIfSmi(
left, deopt);
3514 __ BranchIfSmi(
TMP, deopt);
3518LocationSummary* BoxInstr::MakeLocationSummary(Zone* zone,
bool opt)
const {
3519 const intptr_t kNumInputs = 1;
3520 const intptr_t kNumTemps = 1;
3521 LocationSummary* summary =
new (zone) LocationSummary(
3529void BoxInstr::EmitNativeCode(FlowGraphCompiler*
compiler) {
3530 const Register out_reg = locs()->out(0).reg();
3531 const Register temp_reg = locs()->temp(0).reg();
3539 case kUnboxedDouble:
3540 __ StoreDFieldToOffset(
value, out_reg, ValueOffset());
3544 __ StoreDFieldToOffset(
FpuTMP, out_reg, ValueOffset());
3546 case kUnboxedFloat32x4:
3547 case kUnboxedFloat64x2:
3548 case kUnboxedInt32x4:
3549 __ StoreQFieldToOffset(
value, out_reg, ValueOffset());
3557LocationSummary* UnboxInstr::MakeLocationSummary(Zone* zone,
bool opt)
const {
3559 const intptr_t kNumInputs = 1;
3560 const intptr_t kNumTemps = 0;
3561 const bool is_floating_point =
3563 LocationSummary* summary =
new (zone)
3571void UnboxInstr::EmitLoadFromBox(FlowGraphCompiler*
compiler) {
3572 const Register box = locs()->in(0).reg();
3575 case kUnboxedInt64: {
3577 __ ldr(
result, compiler::FieldAddress(box, ValueOffset()));
3581 case kUnboxedDouble: {
3583 __ LoadDFieldFromOffset(
result, box, ValueOffset());
3587 case kUnboxedFloat: {
3589 __ LoadDFieldFromOffset(
result, box, ValueOffset());
3594 case kUnboxedFloat32x4:
3595 case kUnboxedFloat64x2:
3596 case kUnboxedInt32x4: {
3598 __ LoadQFieldFromOffset(
result, box, ValueOffset());
3608void UnboxInstr::EmitSmiConversion(FlowGraphCompiler*
compiler) {
3609 const Register box = locs()->in(0).reg();
3613 case kUnboxedInt64: {
3619 case kUnboxedDouble: {
3621 __ SmiUntag(
TMP, box);
3622#if !defined(DART_COMPRESSED_POINTERS)
3636void UnboxInstr::EmitLoadInt32FromBoxOrSmi(FlowGraphCompiler*
compiler) {
3642void UnboxInstr::EmitLoadInt64FromBoxOrSmi(FlowGraphCompiler*
compiler) {
3648LocationSummary* BoxInteger32Instr::MakeLocationSummary(Zone* zone,
3652#if !defined(DART_COMPRESSED_POINTERS)
3655 const bool kMayAllocateMint =
false;
3659 const intptr_t kNumInputs = 1;
3660 const intptr_t kNumTemps = kMayAllocateMint ? 1 : 0;
3661 LocationSummary* summary =
new (zone)
3662 LocationSummary(zone, kNumInputs, kNumTemps,
3664 : LocationSummary::kNoCall);
3667 if (kMayAllocateMint) {
3673void BoxInteger32Instr::EmitNativeCode(FlowGraphCompiler*
compiler) {
3678#if !defined(DART_COMPRESSED_POINTERS)
3679 ASSERT(compiler::target::kSmiBits >= 32);
3687 compiler::Label
done;
3696 __ cmpw(
value, compiler::Operand(out,
ASR, 1));
3706 __ TestImmediate(
value, 0xC0000000);
3710 Register temp = locs()->temp(0).reg();
3723LocationSummary* BoxInt64Instr::MakeLocationSummary(Zone* zone,
3725 const intptr_t kNumInputs = 1;
3731 const bool stubs_in_vm_isolate =
3732 object_store->allocate_mint_with_fpu_regs_stub()
3734 ->InVMIsolateHeap() ||
3735 object_store->allocate_mint_without_fpu_regs_stub()
3737 ->InVMIsolateHeap();
3738 const bool shared_slow_path_call =
3739 SlowPathSharingSupported(opt) && !stubs_in_vm_isolate;
3740 LocationSummary* summary =
new (zone) LocationSummary(
3741 zone, kNumInputs, kNumTemps,
3748 }
else if (shared_slow_path_call) {
3759void BoxInt64Instr::EmitNativeCode(FlowGraphCompiler*
compiler) {
3767 compiler::Label
done;
3768#if !defined(DART_COMPRESSED_POINTERS)
3769 __ adds(out, in, compiler::Operand(in));
3779 Register temp = locs()->temp(0).reg();
3782 compiler->intrinsic_slow_path_label(),
3784 }
else if (locs()->call_on_shared_slow_path()) {
3785 const bool has_frame =
compiler->flow_graph().graph_entry()->NeedsFrame();
3787 ASSERT(
__ constant_pool_allowed());
3788 __ set_constant_pool_allowed(
false);
3789 __ EnterDartFrame(0);
3791 auto object_store =
compiler->isolate_group()->object_store();
3792 const bool live_fpu_regs = locs()->live_registers()->FpuRegisterCount() > 0;
3795 live_fpu_regs ? object_store->allocate_mint_with_fpu_regs_stub()
3796 : object_store->allocate_mint_without_fpu_regs_stub());
3798 ASSERT(!locs()->live_registers()->ContainsRegister(
3800 auto extended_env =
compiler->SlowPathEnvironmentFor(
this, 0);
3801 compiler->GenerateStubCall(
source(), stub, UntaggedPcDescriptors::kOther,
3804 __ LeaveDartFrame();
3805 __ set_constant_pool_allowed(
true);
3816LocationSummary* UnboxInteger32Instr::MakeLocationSummary(Zone* zone,
3818 const intptr_t kNumInputs = 1;
3819 const intptr_t kNumTemps = 0;
3820 LocationSummary* summary =
new (zone)
3827void UnboxInteger32Instr::EmitNativeCode(FlowGraphCompiler*
compiler) {
3831 compiler::Label* deopt =
3833 ?
compiler->AddDeoptStub(GetDeoptId(), ICData::kDeoptUnboxInteger)
3836 if (value_cid == kSmiCid) {
3838 }
else if (value_cid == kMintCid) {
3840 }
else if (!CanDeoptimize()) {
3845 compiler::Label
done;
3851 compiler::Label
done;
3854 __ CompareClassId(
value, kMintCid);
3864 __ cmp(out, compiler::Operand(out,
SXTW, 0));
3869LocationSummary* BinaryDoubleOpInstr::MakeLocationSummary(Zone* zone,
3871 const intptr_t kNumInputs = 2;
3872 const intptr_t kNumTemps = 0;
3873 LocationSummary* summary =
new (zone)
3881void BinaryDoubleOpInstr::EmitNativeCode(FlowGraphCompiler*
compiler) {
3903LocationSummary* DoubleTestOpInstr::MakeLocationSummary(Zone* zone,
3905 const bool needs_temp =
op_kind() != MethodRecognizer::kDouble_getIsNaN;
3906 const intptr_t kNumInputs = 1;
3907 const intptr_t kNumTemps = needs_temp ? 1 : 0;
3908 LocationSummary* summary =
new (zone)
3919 BranchLabels labels) {
3922 const bool is_negated = kind() != Token::kEQ;
3925 case MethodRecognizer::kDouble_getIsNaN: {
3927 return is_negated ?
VC :
VS;
3929 case MethodRecognizer::kDouble_getIsInfinite: {
3930 const Register temp = locs()->temp(0).reg();
3933 __ AndImmediate(temp, temp, 0x7FFFFFFFFFFFFFFFLL);
3935 __ CompareImmediate(temp, 0x7FF0000000000000LL);
3936 return is_negated ?
NE :
EQ;
3938 case MethodRecognizer::kDouble_getIsNegative: {
3939 const Register temp = locs()->temp(0).reg();
3940 compiler::Label not_zero;
3943 __ b(is_negated ? labels.true_label : labels.false_label,
VS);
3947 __ CompareImmediate(temp, 0);
3949 return is_negated ?
GE :
LT;
3958#define DEFINE_EMIT(Name, Args) \
3959 static void Emit##Name(FlowGraphCompiler* compiler, SimdOpInstr* instr, \
3960 PP_APPLY(PP_UNPACK, Args))
3962#define SIMD_OP_FLOAT_ARITH(V, Name, op) \
3963 V(Float32x4##Name, op##s) \
3964 V(Float64x2##Name, op##d)
3966#define SIMD_OP_SIMPLE_BINARY(V) \
3967 SIMD_OP_FLOAT_ARITH(V, Add, vadd) \
3968 SIMD_OP_FLOAT_ARITH(V, Sub, vsub) \
3969 SIMD_OP_FLOAT_ARITH(V, Mul, vmul) \
3970 SIMD_OP_FLOAT_ARITH(V, Div, vdiv) \
3971 SIMD_OP_FLOAT_ARITH(V, Min, vmin) \
3972 SIMD_OP_FLOAT_ARITH(V, Max, vmax) \
3973 V(Int32x4Add, vaddw) \
3974 V(Int32x4Sub, vsubw) \
3975 V(Int32x4BitAnd, vand) \
3976 V(Int32x4BitOr, vorr) \
3977 V(Int32x4BitXor, veor) \
3978 V(Float32x4Equal, vceqs) \
3979 V(Float32x4GreaterThan, vcgts) \
3980 V(Float32x4GreaterThanOrEqual, vcges)
3983 switch (instr->kind()) {
3984#define EMIT(Name, op) \
3985 case SimdOpInstr::k##Name: \
3986 __ op(result, left, right); \
3988 SIMD_OP_SIMPLE_BINARY(EMIT)
3990 case SimdOpInstr::kFloat32x4ShuffleMix:
3991 case SimdOpInstr::kInt32x4ShuffleMix: {
3992 const intptr_t mask = instr->mask();
3999 case SimdOpInstr::kFloat32x4NotEqual:
4004 case SimdOpInstr::kFloat32x4LessThan:
4007 case SimdOpInstr::kFloat32x4LessThanOrEqual:
4010 case SimdOpInstr::kFloat32x4Scale:
4015 case SimdOpInstr::kFloat64x2FromDoubles:
4019 case SimdOpInstr::kFloat64x2Scale:
4028#define SIMD_OP_SIMPLE_UNARY(V) \
4029 SIMD_OP_FLOAT_ARITH(V, Sqrt, vsqrt) \
4030 SIMD_OP_FLOAT_ARITH(V, Negate, vneg) \
4031 SIMD_OP_FLOAT_ARITH(V, Abs, vabs) \
4032 V(Float32x4Reciprocal, VRecps) \
4033 V(Float32x4ReciprocalSqrt, VRSqrts)
4036 switch (instr->kind()) {
4037#define EMIT(Name, op) \
4038 case SimdOpInstr::k##Name: \
4039 __ op(result, value); \
4041 SIMD_OP_SIMPLE_UNARY(EMIT)
4043 case SimdOpInstr::kFloat32x4GetX:
4047 case SimdOpInstr::kFloat32x4GetY:
4051 case SimdOpInstr::kFloat32x4GetZ:
4055 case SimdOpInstr::kFloat32x4GetW:
4059 case SimdOpInstr::kInt32x4Shuffle:
4060 case SimdOpInstr::kFloat32x4Shuffle: {
4061 const intptr_t mask = instr->mask();
4064 }
else if (mask == 0x55) {
4066 }
else if (mask == 0xAA) {
4068 }
else if (mask == 0xFF) {
4071 for (intptr_t i = 0; i < 4; i++) {
4072 __ vinss(
result, i, value, (mask >> (2 * i)) & 0x3);
4077 case SimdOpInstr::kFloat32x4Splat:
4083 case SimdOpInstr::kFloat64x2GetX:
4086 case SimdOpInstr::kFloat64x2GetY:
4089 case SimdOpInstr::kFloat64x2Splat:
4092 case SimdOpInstr::kFloat64x2ToFloat32x4:
4096 __ vinsd(
VTMP, 0, value, 0);
4100 __ vinsd(
VTMP, 0, value, 1);
4104 case SimdOpInstr::kFloat32x4ToFloat64x2:
4106 __ vinss(
VTMP, 0, value, 0);
4110 __ vinss(
VTMP, 0, value, 1);
4119DEFINE_EMIT(Simd32x4GetSignMask,
4122 __ vmovrs(out, value, 0);
4123 __ LsrImmediate(out, out, 31);
4125 __ vmovrs(temp, value, 1);
4126 __ LsrImmediate(temp, temp, 31);
4127 __ orr(out, out, compiler::Operand(temp,
LSL, 1));
4129 __ vmovrs(temp, value, 2);
4130 __ LsrImmediate(temp, temp, 31);
4131 __ orr(out, out, compiler::Operand(temp,
LSL, 2));
4133 __ vmovrs(temp, value, 3);
4134 __ LsrImmediate(temp, temp, 31);
4135 __ orr(out, out, compiler::Operand(temp,
LSL, 3));
4139 Float32x4FromDoubles,
4165DEFINE_EMIT(Float32x4With,
4167 __ fcvtsd(
VTMP, replacement);
4169 switch (instr->kind()) {
4170 case SimdOpInstr::kFloat32x4WithX:
4173 case SimdOpInstr::kFloat32x4WithY:
4176 case SimdOpInstr::kFloat32x4WithZ:
4179 case SimdOpInstr::kFloat32x4WithW:
4187DEFINE_EMIT(Simd32x4ToSimd32x4, (SameAsFirstInput,
VRegister value)) {
4199 __ vmovrd(out, value, 0);
4200 __ LsrImmediate(out, out, 63);
4202 __ vmovrd(
TMP, value, 1);
4204 __ orr(out, out, compiler::Operand(
TMP,
LSL, 1));
4207DEFINE_EMIT(Float64x2With,
4209 switch (instr->kind()) {
4210 case SimdOpInstr::kFloat64x2WithX:
4213 case SimdOpInstr::kFloat64x2WithY:
4231DEFINE_EMIT(Int32x4FromBools,
4237 Temp<Register> temp)) {
4239 __ LoadImmediate(temp, 0xffffffff);
4243 for (intptr_t i = 0; i < 4; i++) {
4244 __ CompareObjectRegisters(vs[i],
TMP2);
4251 switch (instr->kind()) {
4252 case SimdOpInstr::kInt32x4GetFlagX:
4255 case SimdOpInstr::kInt32x4GetFlagY:
4258 case SimdOpInstr::kInt32x4GetFlagZ:
4261 case SimdOpInstr::kInt32x4GetFlagW:
4274DEFINE_EMIT(Int32x4Select,
4279 Temp<VRegister> temp)) {
4281 __ vmov(temp, mask);
4283 __ vnot(temp, temp);
4285 __ vand(mask, mask, trueValue);
4287 __ vand(temp, temp, falseValue);
4289 __ vorr(out, mask, temp);
4292DEFINE_EMIT(Int32x4WithFlag,
4296 __ LoadImmediate(
TMP, 0xffffffff);
4298 switch (instr->kind()) {
4299 case SimdOpInstr::kInt32x4WithFlagX:
4302 case SimdOpInstr::kInt32x4WithFlagY:
4305 case SimdOpInstr::kInt32x4WithFlagZ:
4308 case SimdOpInstr::kInt32x4WithFlagW:
4322#define SIMD_OP_VARIANTS(CASE, ____) \
4323 SIMD_OP_SIMPLE_BINARY(CASE) \
4324 CASE(Float32x4ShuffleMix) \
4325 CASE(Int32x4ShuffleMix) \
4326 CASE(Float32x4NotEqual) \
4327 CASE(Float32x4LessThan) \
4328 CASE(Float32x4LessThanOrEqual) \
4329 CASE(Float32x4Scale) \
4330 CASE(Float64x2FromDoubles) \
4331 CASE(Float64x2Scale) \
4332 ____(SimdBinaryOp) \
4333 SIMD_OP_SIMPLE_UNARY(CASE) \
4334 CASE(Float32x4GetX) \
4335 CASE(Float32x4GetY) \
4336 CASE(Float32x4GetZ) \
4337 CASE(Float32x4GetW) \
4338 CASE(Int32x4Shuffle) \
4339 CASE(Float32x4Shuffle) \
4340 CASE(Float32x4Splat) \
4341 CASE(Float64x2GetX) \
4342 CASE(Float64x2GetY) \
4343 CASE(Float64x2Splat) \
4344 CASE(Float64x2ToFloat32x4) \
4345 CASE(Float32x4ToFloat64x2) \
4347 CASE(Float32x4GetSignMask) \
4348 CASE(Int32x4GetSignMask) \
4349 ____(Simd32x4GetSignMask) \
4350 CASE(Float32x4FromDoubles) \
4351 ____(Float32x4FromDoubles) \
4352 CASE(Float32x4Zero) \
4353 CASE(Float64x2Zero) \
4355 CASE(Float32x4Clamp) \
4356 ____(Float32x4Clamp) \
4357 CASE(Float64x2Clamp) \
4358 ____(Float64x2Clamp) \
4359 CASE(Float32x4WithX) \
4360 CASE(Float32x4WithY) \
4361 CASE(Float32x4WithZ) \
4362 CASE(Float32x4WithW) \
4363 ____(Float32x4With) \
4364 CASE(Float32x4ToInt32x4) \
4365 CASE(Int32x4ToFloat32x4) \
4366 ____(Simd32x4ToSimd32x4) \
4367 CASE(Float64x2GetSignMask) \
4368 ____(Float64x2GetSignMask) \
4369 CASE(Float64x2WithX) \
4370 CASE(Float64x2WithY) \
4371 ____(Float64x2With) \
4372 CASE(Int32x4FromInts) \
4373 ____(Int32x4FromInts) \
4374 CASE(Int32x4FromBools) \
4375 ____(Int32x4FromBools) \
4376 CASE(Int32x4GetFlagX) \
4377 CASE(Int32x4GetFlagY) \
4378 CASE(Int32x4GetFlagZ) \
4379 CASE(Int32x4GetFlagW) \
4380 ____(Int32x4GetFlag) \
4381 CASE(Int32x4Select) \
4382 ____(Int32x4Select) \
4383 CASE(Int32x4WithFlagX) \
4384 CASE(Int32x4WithFlagY) \
4385 CASE(Int32x4WithFlagZ) \
4386 CASE(Int32x4WithFlagW) \
4387 ____(Int32x4WithFlag)
4391#define CASE(Name, ...) case k##Name:
4393 return MakeLocationSummaryFromEmitter(zone, this, &Emit##Name);
4394 SIMD_OP_VARIANTS(
CASE, EMIT)
4407#define CASE(Name, ...) case k##Name:
4409 InvokeEmitter(compiler, this, &Emit##Name); \
4411 SIMD_OP_VARIANTS(
CASE, EMIT)
4422LocationSummary* CaseInsensitiveCompareInstr::MakeLocationSummary(
4425 const intptr_t kNumTemps = 0;
4426 LocationSummary* summary =
new (zone)
4436void CaseInsensitiveCompareInstr::EmitNativeCode(FlowGraphCompiler*
compiler) {
4437 compiler::LeafRuntimeScope rt(
compiler->assembler(),
4444LocationSummary* MathMinMaxInstr::MakeLocationSummary(Zone* zone,
4447 const intptr_t kNumInputs = 2;
4448 const intptr_t kNumTemps = 0;
4449 LocationSummary* summary =
new (zone)
4458 const intptr_t kNumInputs = 2;
4459 const intptr_t kNumTemps = 0;
4460 LocationSummary* summary =
new (zone)
4469void MathMinMaxInstr::EmitNativeCode(FlowGraphCompiler*
compiler) {
4471 (
op_kind() == MethodRecognizer::kMathMax));
4472 const bool is_min = (
op_kind() == MethodRecognizer::kMathMin);
4479 __ b(&returns_nan,
VS);
4482 is_min ? TokenKindToDoubleCondition(Token::kLTE)
4483 : TokenKindToDoubleCondition(Token::kGTE);
4485 __ b(&
done, double_condition);
4489 __ Bind(&returns_nan);
4501 __ CompareImmediate(
TMP, 0);
4528LocationSummary* UnarySmiOpInstr::MakeLocationSummary(Zone* zone,
4530 const intptr_t kNumInputs = 1;
4531 const intptr_t kNumTemps = 0;
4532 LocationSummary* summary =
new (zone)
4541void UnarySmiOpInstr::EmitNativeCode(FlowGraphCompiler*
compiler) {
4545 case Token::kNEGATE: {
4546 compiler::Label* deopt =
4547 compiler->AddDeoptStub(deopt_id(), ICData::kDeoptUnaryOp);
4552 case Token::kBIT_NOT:
4562LocationSummary* UnaryDoubleOpInstr::MakeLocationSummary(Zone* zone,
4564 const intptr_t kNumInputs = 1;
4565 const intptr_t kNumTemps = 0;
4566 LocationSummary* summary =
new (zone)
4573void UnaryDoubleOpInstr::EmitNativeCode(FlowGraphCompiler*
compiler) {
4578 case Token::kNEGATE:
4584 case Token::kSQUARE:
4592LocationSummary* Int32ToDoubleInstr::MakeLocationSummary(Zone* zone,
4594 const intptr_t kNumInputs = 1;
4595 const intptr_t kNumTemps = 0;
4596 LocationSummary*
result =
new (zone)
4603void Int32ToDoubleInstr::EmitNativeCode(FlowGraphCompiler*
compiler) {
4609LocationSummary* SmiToDoubleInstr::MakeLocationSummary(Zone* zone,
4611 const intptr_t kNumInputs = 1;
4612 const intptr_t kNumTemps = 0;
4613 LocationSummary*
result =
new (zone)
4620void SmiToDoubleInstr::EmitNativeCode(FlowGraphCompiler*
compiler) {
4624#if !defined(DART_COMPRESSED_POINTERS)
4631LocationSummary* Int64ToDoubleInstr::MakeLocationSummary(Zone* zone,
4633 const intptr_t kNumInputs = 1;
4634 const intptr_t kNumTemps = 0;
4635 LocationSummary*
result =
new (zone)
4642void Int64ToDoubleInstr::EmitNativeCode(FlowGraphCompiler*
compiler) {
4648LocationSummary* DoubleToIntegerInstr::MakeLocationSummary(Zone* zone,
4650 const intptr_t kNumInputs = 1;
4651 const intptr_t kNumTemps = 0;
4652 LocationSummary*
result =
new (zone) LocationSummary(
4659void DoubleToIntegerInstr::EmitNativeCode(FlowGraphCompiler*
compiler) {
4661 const VRegister value_double = locs()->in(0).fpu_reg();
4663 DoubleToIntegerSlowPath* slow_path =
4664 new DoubleToIntegerSlowPath(
this, value_double);
4665 compiler->AddSlowPathCode(slow_path);
4669 __ fcmpd(value_double, value_double);
4670 __ b(slow_path->entry_label(),
VS);
4673 case MethodRecognizer::kDoubleToInteger:
4676 case MethodRecognizer::kDoubleFloorToInt:
4679 case MethodRecognizer::kDoubleCeilToInt:
4687#if !defined(DART_COMPRESSED_POINTERS)
4689 __ CompareImmediate(
result, 0xC000000000000000);
4690 __ b(slow_path->entry_label(),
MI);
4695 __ b(slow_path->entry_label(),
NE);
4698 __ Bind(slow_path->exit_label());
4701LocationSummary* DoubleToSmiInstr::MakeLocationSummary(Zone* zone,
4703 const intptr_t kNumInputs = 1;
4704 const intptr_t kNumTemps = 0;
4705 LocationSummary*
result =
new (zone)
4712void DoubleToSmiInstr::EmitNativeCode(FlowGraphCompiler*
compiler) {
4713 compiler::Label* deopt =
4714 compiler->AddDeoptStub(deopt_id(), ICData::kDeoptDoubleToSmi);
4725#if !defined(DART_COMPRESSED_POINTERS)
4727 __ CompareImmediate(
result, 0xC000000000000000);
4738LocationSummary* DoubleToFloatInstr::MakeLocationSummary(Zone* zone,
4740 const intptr_t kNumInputs = 1;
4741 const intptr_t kNumTemps = 0;
4742 LocationSummary*
result =
new (zone)
4749void DoubleToFloatInstr::EmitNativeCode(FlowGraphCompiler*
compiler) {
4755LocationSummary* FloatToDoubleInstr::MakeLocationSummary(Zone* zone,
4757 const intptr_t kNumInputs = 1;
4758 const intptr_t kNumTemps = 0;
4759 LocationSummary*
result =
new (zone)
4766void FloatToDoubleInstr::EmitNativeCode(FlowGraphCompiler*
compiler) {
4772LocationSummary* FloatCompareInstr::MakeLocationSummary(Zone* zone,
4778void FloatCompareInstr::EmitNativeCode(FlowGraphCompiler*
compiler) {
4785 const intptr_t kNumTemps =
4787 LocationSummary*
result =
new (zone)
4815static void InvokeDoublePow(FlowGraphCompiler*
compiler,
4816 InvokeMathCFunctionInstr* instr) {
4817 ASSERT(instr->recognized_kind() == MethodRecognizer::kMathDoublePow);
4818 const intptr_t kInputCount = 2;
4819 ASSERT(instr->InputCount() == kInputCount);
4820 LocationSummary* locs = instr->locs();
4823 const VRegister exp = locs->in(1).fpu_reg();
4825 const VRegister saved_base = locs->temp(0).fpu_reg();
4828 compiler::Label skip_call, try_sqrt, check_base, return_nan, do_pow;
4829 __ fmovdd(saved_base,
base);
4833 __ b(&check_base,
VS);
4834 __ b(&skip_call,
EQ);
4838 compiler::Label return_base;
4839 __ b(&return_base,
EQ);
4842 __ LoadDImmediate(
VTMP, 2.0);
4844 compiler::Label return_base_times_2;
4845 __ b(&return_base_times_2,
EQ);
4848 __ LoadDImmediate(
VTMP, 3.0);
4850 __ b(&check_base,
NE);
4853 __ fmuld(
result, saved_base, saved_base);
4857 __ Bind(&return_base);
4861 __ Bind(&return_base_times_2);
4862 __ fmuld(
result, saved_base, saved_base);
4865 __ Bind(&check_base);
4869 __ b(&return_nan,
VS);
4870 __ b(&skip_call,
EQ);
4872 __ fcmpd(saved_base, exp);
4873 __ b(&try_sqrt,
VC);
4875 __ Bind(&return_nan);
4879 compiler::Label return_zero;
4895 __ fcmpdz(saved_base);
4896 __ b(&return_zero,
EQ);
4901 __ Bind(&return_zero);
4906 __ fmovdd(
base, saved_base);
4908 compiler::LeafRuntimeScope rt(
compiler->assembler(),
4913 rt.Call(instr->TargetFunction(), kInputCount);
4916 __ Bind(&skip_call);
4925 compiler::LeafRuntimeScope rt(
compiler->assembler(),
4936LocationSummary* ExtractNthOutputInstr::MakeLocationSummary(Zone* zone,
4940 const intptr_t kNumInputs = 1;
4941 LocationSummary* summary =
4968void ExtractNthOutputInstr::EmitNativeCode(FlowGraphCompiler*
compiler) {
4969 ASSERT(locs()->in(0).IsPairLocation());
4970 PairLocation* pair = locs()->in(0).AsPairLocation();
4984LocationSummary* UnboxLaneInstr::MakeLocationSummary(Zone* zone,
4990void UnboxLaneInstr::EmitNativeCode(FlowGraphCompiler*
compiler) {
4994LocationSummary* BoxLanesInstr::MakeLocationSummary(Zone* zone,
5000void BoxLanesInstr::EmitNativeCode(FlowGraphCompiler*
compiler) {
5004LocationSummary* TruncDivModInstr::MakeLocationSummary(Zone* zone,
5006 const intptr_t kNumInputs = 2;
5007 const intptr_t kNumTemps = 0;
5008 LocationSummary* summary =
new (zone)
5018void TruncDivModInstr::EmitNativeCode(FlowGraphCompiler*
compiler) {
5020 compiler::Label* deopt =
5021 compiler->AddDeoptStub(deopt_id(), ICData::kDeoptBinarySmiOp);
5024 ASSERT(locs()->
out(0).IsPairLocation());
5025 const PairLocation* pair = locs()->out(0).AsPairLocation();
5026 const Register result_div = pair->At(0).reg();
5027 const Register result_mod = pair->At(1).reg();
5034 __ SmiUntag(result_mod,
left);
5039#if !defined(DART_COMPRESSED_POINTERS)
5040 __ sdiv(result_div, result_mod,
TMP);
5041 __ CompareImmediate(result_div, 0x4000000000000000);
5043 __ sdivw(result_div, result_mod,
TMP);
5049 __ SmiTag(result_div);
5050 __ SmiTag(result_mod);
5060 compiler::Label
done;
5061 __ CompareObjectRegisters(result_mod,
ZR);
5065 __ sub(result_mod, result_mod, compiler::Operand(
right));
5067 __ add(result_mod, result_mod, compiler::Operand(
right));
5078static void EmitHashIntegerCodeSequence(FlowGraphCompiler*
compiler,
5084 __ LoadImmediate(
TMP2, compiler::Immediate(0x2d51));
5086 __ umulh(value, value,
TMP2);
5091LocationSummary* HashDoubleOpInstr::MakeLocationSummary(Zone* zone,
5093 const intptr_t kNumInputs = 1;
5094 const intptr_t kNumTemps = 1;
5095 LocationSummary* summary =
new (zone)
5103void HashDoubleOpInstr::EmitNativeCode(FlowGraphCompiler*
compiler) {
5105 const VRegister temp_double = locs()->temp(0).fpu_reg();
5108 compiler::Label
done, hash_double;
5110 __ AndImmediate(
TMP,
TMP, 0x7FF0000000000000LL);
5111 __ CompareImmediate(
TMP, 0x7FF0000000000000LL);
5112 __ b(&hash_double,
EQ);
5115 __ scvtfdx(temp_double,
TMP);
5117 __ b(&hash_double,
NE);
5123 __ Bind(&hash_double);
5131LocationSummary* HashIntegerOpInstr::MakeLocationSummary(Zone* zone,
5133 const intptr_t kNumInputs = 1;
5134 const intptr_t kNumTemps = 0;
5135 LocationSummary* summary =
new (zone)
5142void HashIntegerOpInstr::EmitNativeCode(FlowGraphCompiler*
compiler) {
5167LocationSummary* CheckClassInstr::MakeLocationSummary(Zone* zone,
5169 const intptr_t kNumInputs = 1;
5170 const bool need_mask_temp =
IsBitTest();
5171 const intptr_t kNumTemps = !
IsNullCheck() ? (need_mask_temp ? 2 : 1) : 0;
5172 LocationSummary* summary =
new (zone)
5177 if (need_mask_temp) {
5185 compiler::Label* deopt) {
5186 __ CompareObject(locs()->in(0).reg(), Object::null_object());
5196 compiler::Label* deopt) {
5197 Register biased_cid = locs()->temp(0).reg();
5198 __ AddImmediate(biased_cid, -
min);
5199 __ CompareImmediate(biased_cid,
max -
min);
5202 Register bit_reg = locs()->temp(1).reg();
5203 __ LoadImmediate(bit_reg, 1);
5204 __ lslv(bit_reg, bit_reg, biased_cid);
5205 __ TestImmediate(bit_reg, mask);
5209int CheckClassInstr::EmitCheckCid(FlowGraphCompiler*
compiler,
5214 compiler::Label* is_ok,
5215 compiler::Label* deopt,
5216 bool use_near_jump) {
5217 Register biased_cid = locs()->temp(0).reg();
5219 if (cid_start == cid_end) {
5220 __ CompareImmediate(biased_cid, cid_start - bias);
5226 __ AddImmediate(biased_cid, bias - cid_start);
5228 __ CompareImmediate(biased_cid, cid_end - cid_start);
5233 __ b(deopt, no_match);
5240LocationSummary* CheckClassIdInstr::MakeLocationSummary(Zone* zone,
5242 const intptr_t kNumInputs = 1;
5243 const intptr_t kNumTemps = 0;
5244 LocationSummary* summary =
new (zone)
5251void CheckClassIdInstr::EmitNativeCode(FlowGraphCompiler*
compiler) {
5253 compiler::Label* deopt =
5254 compiler->AddDeoptStub(deopt_id(), ICData::kDeoptCheckClass);
5255 if (cids_.IsSingleCid()) {
5265LocationSummary* CheckSmiInstr::MakeLocationSummary(Zone* zone,
5267 const intptr_t kNumInputs = 1;
5268 const intptr_t kNumTemps = 0;
5269 LocationSummary* summary =
new (zone)
5275void CheckSmiInstr::EmitNativeCode(FlowGraphCompiler*
compiler) {
5277 compiler::Label* deopt =
5278 compiler->AddDeoptStub(deopt_id(), ICData::kDeoptCheckSmi);
5279 __ BranchIfNotSmi(
value, deopt);
5282void CheckNullInstr::EmitNativeCode(FlowGraphCompiler*
compiler) {
5283 ThrowErrorSlowPathCode* slow_path =
new NullErrorSlowPath(
this);
5284 compiler->AddSlowPathCode(slow_path);
5286 Register value_reg = locs()->in(0).reg();
5289 __ CompareObject(value_reg, Object::null_object());
5290 __ BranchIf(
EQUAL, slow_path->entry_label());
5293LocationSummary* CheckArrayBoundInstr::MakeLocationSummary(Zone* zone,
5295 const intptr_t kNumInputs = 2;
5296 const intptr_t kNumTemps = 0;
5297 LocationSummary* locs =
new (zone)
5304void CheckArrayBoundInstr::EmitNativeCode(FlowGraphCompiler*
compiler) {
5306 compiler::Label* deopt =
5307 compiler->AddDeoptStub(deopt_id(), ICData::kDeoptCheckArrayBound,
flags);
5313 if (length_loc.IsConstant() && index_loc.IsConstant()) {
5315 if ((Smi::Cast(length_loc.constant()).Value() >
5316 Smi::Cast(index_loc.constant()).Value()) &&
5317 (Smi::Cast(index_loc.constant()).Value() >= 0)) {
5321 ASSERT((Smi::Cast(length_loc.constant()).Value() <=
5322 Smi::Cast(index_loc.constant()).Value()) ||
5323 (Smi::Cast(index_loc.constant()).Value() < 0));
5330 if (index_loc.IsConstant()) {
5332 const Smi&
index = Smi::Cast(index_loc.constant());
5335 }
else if (length_loc.IsConstant()) {
5336 const Smi&
length = Smi::Cast(length_loc.constant());
5338 if (index_cid != kSmiCid) {
5339 __ BranchIfNotSmi(
index, deopt);
5351 if (index_cid != kSmiCid) {
5352 __ BranchIfNotSmi(
index, deopt);
5359LocationSummary* CheckWritableInstr::MakeLocationSummary(Zone* zone,
5361 const intptr_t kNumInputs = 1;
5362 const intptr_t kNumTemps = 0;
5363 LocationSummary* locs =
new (zone) LocationSummary(
5364 zone, kNumInputs, kNumTemps,
5371void CheckWritableInstr::EmitNativeCode(FlowGraphCompiler*
compiler) {
5372 WriteErrorSlowPath* slow_path =
new WriteErrorSlowPath(
this);
5373 compiler->AddSlowPathCode(slow_path);
5375 compiler::FieldAddress(locs()->in(0).reg(),
5376 compiler::target::Object::tags_offset()),
5379 ASSERT(compiler::target::UntaggedObject::kImmutableBit < 8);
5380 __ tbnz(slow_path->entry_label(),
TMP,
5381 compiler::target::UntaggedObject::kImmutableBit);
5384class Int64DivideSlowPath :
public ThrowErrorSlowPathCode {
5386 Int64DivideSlowPath(BinaryInt64OpInstr* instruction,
5388 Range* divisor_range,
5391 : ThrowErrorSlowPathCode(instruction,
5392 kIntegerDivisionByZeroExceptionRuntimeEntry),
5393 is_mod_(instruction->op_kind() == Token::kMOD),
5395 divisor_range_(divisor_range),
5398 adjust_sign_label_() {}
5400 void EmitNativeCode(FlowGraphCompiler*
compiler)
override {
5402 if (has_divide_by_zero()) {
5403 ThrowErrorSlowPathCode::EmitNativeCode(
compiler);
5405 __ Bind(entry_label());
5406 if (compiler::Assembler::EmittingComments()) {
5407 __ Comment(
"slow path %s operation (no throw)",
name());
5415 if (has_adjust_sign()) {
5416 __ Bind(adjust_sign_label());
5417 if (RangeUtils::Overlaps(divisor_range_, -1, 1)) {
5419 __ CompareRegisters(divisor_, ZR);
5420 __ sub(tmp_, out_, compiler::Operand(divisor_));
5421 __ add(out_, out_, compiler::Operand(divisor_));
5422 __ csel(out_, tmp_, out_, LT);
5423 }
else if (divisor_range_->IsPositive()) {
5425 __ add(out_, out_, compiler::Operand(divisor_));
5428 __ sub(out_, out_, compiler::Operand(divisor_));
5434 const char*
name()
override {
return "int64 divide"; }
5436 bool has_divide_by_zero() {
return RangeUtils::CanBeZero(divisor_range_); }
5438 bool has_adjust_sign() {
return is_mod_; }
5440 bool is_needed() {
return has_divide_by_zero() || has_adjust_sign(); }
5442 compiler::Label* adjust_sign_label() {
5443 ASSERT(has_adjust_sign());
5444 return &adjust_sign_label_;
5450 Range* divisor_range_;
5453 compiler::Label adjust_sign_label_;
5456static void EmitInt64ModTruncDiv(FlowGraphCompiler*
compiler,
5457 BinaryInt64OpInstr* instruction,
5463 ASSERT(op_kind == Token::kMOD || op_kind == Token::kTRUNCDIV);
5469 if (FLAG_optimization_level <= 2) {
5471 }
else if (
auto c = instruction->right()->definition()->AsConstant()) {
5472 if (c->value().IsInteger()) {
5473 const int64_t divisor = Integer::Cast(c->value()).AsInt64Value();
5474 if (divisor <= -2 || divisor >= 2) {
5476 compiler::Label
pos;
5481 __ LoadImmediate(
TMP2, magic);
5484 if (divisor > 0 && magic < 0) {
5486 }
else if (divisor < 0 && magic > 0) {
5494 if (op_kind == Token::kTRUNCDIV) {
5498 __ LoadImmediate(
TMP, divisor);
5501 __ CompareRegisters(out,
ZR);
5503 __ add(
TMP2, out, compiler::Operand(
TMP));
5505 __ sub(
TMP2, out, compiler::Operand(
TMP));
5515 Range* right_range = instruction->right()->definition()->range();
5516 Int64DivideSlowPath* slow_path =
5517 new (
Z) Int64DivideSlowPath(instruction,
right, right_range, tmp, out);
5520 if (slow_path->has_divide_by_zero()) {
5521 __ cbz(slow_path->entry_label(),
right);
5528 if (op_kind == Token::kMOD) {
5533 __ CompareRegisters(out,
ZR);
5534 __ b(slow_path->adjust_sign_label(),
LT);
5539 if (slow_path->is_needed()) {
5540 __ Bind(slow_path->exit_label());
5541 compiler->AddSlowPathCode(slow_path);
5545LocationSummary* BinaryInt64OpInstr::MakeLocationSummary(Zone* zone,
5549 case Token::kTRUNCDIV: {
5550 const intptr_t kNumInputs = 2;
5551 const intptr_t kNumTemps = (
op_kind() == Token::kMOD) ? 1 : 0;
5552 LocationSummary* summary =
new (zone) LocationSummary(
5557 if (kNumTemps == 1) {
5563 const intptr_t kNumInputs = 2;
5564 const intptr_t kNumTemps = 0;
5565 LocationSummary* summary =
new (zone) LocationSummary(
5575void BinaryInt64OpInstr::EmitNativeCode(FlowGraphCompiler*
compiler) {
5577 ASSERT(!CanDeoptimize());
5589 }
else if (
op_kind() == Token::kMUL) {
5591 if (
right.IsConstant()) {
5595 __ LoadImmediate(r, value);
5603 if (
right.IsConstant()) {
5609 __ AddImmediate(out,
left, value);
5612 __ AddImmediate(out,
left, -value);
5614 case Token::kBIT_AND:
5615 __ AndImmediate(out,
left, value);
5617 case Token::kBIT_OR:
5618 __ OrImmediate(out,
left, value);
5620 case Token::kBIT_XOR:
5621 __ XorImmediate(out,
left, value);
5627 compiler::Operand r = compiler::Operand(
right.reg());
5635 case Token::kBIT_AND:
5638 case Token::kBIT_OR:
5641 case Token::kBIT_XOR:
5650static void EmitShiftInt64ByConstant(FlowGraphCompiler*
compiler,
5654 const Object&
right) {
5655 const int64_t shift = Integer::Cast(
right).AsInt64Value();
5659 __ AsrImmediate(out,
left,
5663 case Token::kUSHR: {
5665 __ LsrImmediate(out,
left, shift);
5670 __ LslImmediate(out,
left, shift);
5678static void EmitShiftInt64ByRegister(FlowGraphCompiler*
compiler,
5688 case Token::kUSHR: {
5701static void EmitShiftUint32ByConstant(FlowGraphCompiler*
compiler,
5705 const Object&
right) {
5706 const int64_t shift = Integer::Cast(
right).AsInt64Value();
5709 __ LoadImmediate(out, 0);
5725static void EmitShiftUint32ByRegister(FlowGraphCompiler*
compiler,
5743class ShiftInt64OpSlowPath :
public ThrowErrorSlowPathCode {
5745 explicit ShiftInt64OpSlowPath(ShiftInt64OpInstr* instruction)
5746 : ThrowErrorSlowPathCode(instruction,
5747 kArgumentErrorUnboxedInt64RuntimeEntry) {}
5749 const char*
name()
override {
return "int64 shift"; }
5751 void EmitCodeAtSlowPathEntry(FlowGraphCompiler*
compiler)
override {
5752 const Register left = instruction()->locs()->in(0).reg();
5754 const Register out = instruction()->locs()->out(0).reg();
5757 compiler::Label throw_error;
5758 __ tbnz(&throw_error,
right, kBitsPerWord - 1);
5760 switch (instruction()->AsShiftInt64Op()->op_kind()) {
5762 __ AsrImmediate(out,
left, kBitsPerWord - 1);
5773 __ Bind(&throw_error);
5782 THR, compiler::target::Thread::unboxed_runtime_arg_offset()));
5786LocationSummary* ShiftInt64OpInstr::MakeLocationSummary(Zone* zone,
5788 const intptr_t kNumInputs = 2;
5789 const intptr_t kNumTemps = 0;
5790 LocationSummary* summary =
new (zone) LocationSummary(
5800void ShiftInt64OpInstr::EmitNativeCode(FlowGraphCompiler*
compiler) {
5807 locs()->in(1).constant());
5810 Register shift = locs()->in(1).reg();
5813 ShiftInt64OpSlowPath* slow_path =
nullptr;
5815 slow_path =
new (
Z) ShiftInt64OpSlowPath(
this);
5816 compiler->AddSlowPathCode(slow_path);
5817 __ CompareImmediate(shift, kShiftCountLimit);
5818 __ b(slow_path->entry_label(),
HI);
5823 if (slow_path !=
nullptr) {
5824 __ Bind(slow_path->exit_label());
5829LocationSummary* SpeculativeShiftInt64OpInstr::MakeLocationSummary(
5832 const intptr_t kNumInputs = 2;
5833 const intptr_t kNumTemps = 0;
5834 LocationSummary* summary =
new (zone)
5842void SpeculativeShiftInt64OpInstr::EmitNativeCode(FlowGraphCompiler*
compiler) {
5849 locs()->in(1).constant());
5852 Register shift = locs()->in(1).reg();
5855 __ SmiUntag(
TMP, shift);
5861 compiler::Label* deopt =
5862 compiler->AddDeoptStub(deopt_id(), ICData::kDeoptBinaryInt64Op);
5864 __ CompareImmediate(shift, kShiftCountLimit);
5872class ShiftUint32OpSlowPath :
public ThrowErrorSlowPathCode {
5874 explicit ShiftUint32OpSlowPath(ShiftUint32OpInstr* instruction)
5875 : ThrowErrorSlowPathCode(instruction,
5876 kArgumentErrorUnboxedInt64RuntimeEntry) {}
5878 const char*
name()
override {
return "uint32 shift"; }
5880 void EmitCodeAtSlowPathEntry(FlowGraphCompiler*
compiler)
override {
5890 THR, compiler::target::Thread::unboxed_runtime_arg_offset()));
5894LocationSummary* ShiftUint32OpInstr::MakeLocationSummary(Zone* zone,
5896 const intptr_t kNumInputs = 2;
5897 const intptr_t kNumTemps = 0;
5898 LocationSummary* summary =
new (zone) LocationSummary(
5908void ShiftUint32OpInstr::EmitNativeCode(FlowGraphCompiler*
compiler) {
5914 locs()->in(1).constant());
5918 const bool shift_count_in_range =
5922 if (!shift_count_in_range) {
5923 ShiftUint32OpSlowPath* slow_path =
new (
Z) ShiftUint32OpSlowPath(
this);
5924 compiler->AddSlowPathCode(slow_path);
5931 if (!shift_count_in_range) {
5933 __ CompareImmediate(
right, 31);
5934 __ csel(out, out,
ZR,
LE);
5939LocationSummary* SpeculativeShiftUint32OpInstr::MakeLocationSummary(
5942 const intptr_t kNumInputs = 2;
5943 const intptr_t kNumTemps = 0;
5944 LocationSummary* summary =
new (zone)
5952void SpeculativeShiftUint32OpInstr::EmitNativeCode(
5959 locs()->in(1).constant());
5962 const bool shift_count_in_range =
5969 if (!shift_count_in_range) {
5972 compiler::Label* deopt =
5973 compiler->AddDeoptStub(deopt_id(), ICData::kDeoptBinaryInt64Op);
5975 __ tbnz(deopt,
right, compiler::target::kSmiBits + 1);
5980 if (!shift_count_in_range) {
5983 __ csel(out, out,
ZR,
LE);
5988LocationSummary* UnaryInt64OpInstr::MakeLocationSummary(Zone* zone,
5990 const intptr_t kNumInputs = 1;
5991 const intptr_t kNumTemps = 0;
5992 LocationSummary* summary =
new (zone)
5999void UnaryInt64OpInstr::EmitNativeCode(FlowGraphCompiler*
compiler) {
6003 case Token::kBIT_NOT:
6006 case Token::kNEGATE:
6007 __ sub(out,
ZR, compiler::Operand(
left));
6014LocationSummary* BinaryUint32OpInstr::MakeLocationSummary(Zone* zone,
6016 const intptr_t kNumInputs = 2;
6017 const intptr_t kNumTemps = 0;
6018 LocationSummary* summary =
new (zone)
6026void BinaryUint32OpInstr::EmitNativeCode(FlowGraphCompiler*
compiler) {
6029 compiler::Operand r = compiler::Operand(
right);
6032 case Token::kBIT_AND:
6035 case Token::kBIT_OR:
6038 case Token::kBIT_XOR:
6055LocationSummary* UnaryUint32OpInstr::MakeLocationSummary(Zone* zone,
6057 const intptr_t kNumInputs = 1;
6058 const intptr_t kNumTemps = 0;
6059 LocationSummary* summary =
new (zone)
6066void UnaryUint32OpInstr::EmitNativeCode(FlowGraphCompiler*
compiler) {
6076LocationSummary* IntConverterInstr::MakeLocationSummary(Zone* zone,
6078 const intptr_t kNumInputs = 1;
6079 const intptr_t kNumTemps = 0;
6080 LocationSummary* summary =
new (zone)
6082 if (
from() == kUntagged ||
to() == kUntagged) {
6085 ASSERT(!CanDeoptimize());
6086 }
else if (
from() == kUnboxedInt64) {
6087 ASSERT(
to() == kUnboxedUint32 ||
to() == kUnboxedInt32);
6088 }
else if (
to() == kUnboxedInt64) {
6091 ASSERT(
to() == kUnboxedUint32 ||
to() == kUnboxedInt32);
6095 if (CanDeoptimize()) {
6103void IntConverterInstr::EmitNativeCode(FlowGraphCompiler*
compiler) {
6106 const bool is_nop_conversion =
6109 if (is_nop_conversion) {
6110 ASSERT(locs()->in(0).reg() == locs()->
out(0).reg());
6116 compiler::Label* deopt =
6119 :
compiler->AddDeoptStub(deopt_id(), ICData::kDeoptUnboxInteger);
6120 if (
from() == kUnboxedInt32 &&
to() == kUnboxedUint32) {
6121 if (CanDeoptimize()) {
6128 }
else if (
from() == kUnboxedUint32 &&
to() == kUnboxedInt32) {
6129 if (CanDeoptimize()) {
6136 }
else if (
from() == kUnboxedInt64) {
6137 if (
to() == kUnboxedInt32) {
6147 if (CanDeoptimize()) {
6149 __ cmp(out, compiler::Operand(
value));
6152 }
else if (
to() == kUnboxedInt64) {
6153 if (
from() == kUnboxedUint32) {
6164LocationSummary* BitCastInstr::MakeLocationSummary(Zone* zone,
bool opt)
const {
6165 LocationSummary* summary =
6166 new (zone) LocationSummary(zone,
InputCount(),
6174 case kUnboxedDouble:
6187 case kUnboxedDouble:
6196void BitCastInstr::EmitNativeCode(FlowGraphCompiler*
compiler) {
6198 case kUnboxedInt32: {
6200 const Register from_reg = locs()->in(0).reg();
6201 const FpuRegister to_reg = locs()->out(0).fpu_reg();
6202 __ fmovsr(to_reg, from_reg);
6205 case kUnboxedFloat: {
6207 const FpuRegister from_reg = locs()->in(0).fpu_reg();
6208 const Register to_reg = locs()->out(0).reg();
6209 __ fmovrs(to_reg, from_reg);
6212 case kUnboxedInt64: {
6214 const Register from_reg = locs()->in(0).reg();
6215 const FpuRegister to_reg = locs()->out(0).fpu_reg();
6216 __ fmovdr(to_reg, from_reg);
6219 case kUnboxedDouble: {
6221 const FpuRegister from_reg = locs()->in(0).fpu_reg();
6222 const Register to_reg = locs()->out(0).reg();
6223 __ fmovrd(to_reg, from_reg);
6231LocationSummary* StopInstr::MakeLocationSummary(Zone* zone,
bool opt)
const {
6235void StopInstr::EmitNativeCode(FlowGraphCompiler*
compiler) {
6239void GraphEntryInstr::EmitNativeCode(FlowGraphCompiler*
compiler) {
6241 if (entry !=
nullptr) {
6242 if (!
compiler->CanFallThroughTo(entry)) {
6243 FATAL(
"Checked function entry must have no offset");
6247 if (!
compiler->CanFallThroughTo(entry)) {
6253LocationSummary* GotoInstr::MakeLocationSummary(Zone* zone,
bool opt)
const {
6257void GotoInstr::EmitNativeCode(FlowGraphCompiler*
compiler) {
6259 if (FLAG_reorder_basic_blocks) {
6264 compiler->AddCurrentDescriptor(UntaggedPcDescriptors::kDeopt, GetDeoptId(),
6265 InstructionSource());
6278LocationSummary* IndirectGotoInstr::MakeLocationSummary(Zone* zone,
6280 const intptr_t kNumInputs = 1;
6281 const intptr_t kNumTemps = 2;
6283 LocationSummary* summary =
new (zone)
6293void IndirectGotoInstr::EmitNativeCode(FlowGraphCompiler*
compiler) {
6294 Register index_reg = locs()->in(0).reg();
6295 Register target_address_reg = locs()->temp(0).reg();
6296 Register offset_reg = locs()->temp(1).reg();
6299 __ LoadObject(offset_reg, offsets_);
6300 const auto element_address =
__ ElementAddressForRegIndex(
6301 false, kTypedDataInt32ArrayCid,
6303 false, offset_reg, index_reg,
TMP);
6307 const intptr_t entry_offset =
__ CodeSize();
6309 __ adr(target_address_reg, compiler::Immediate(-entry_offset));
6311 __ adr(target_address_reg, compiler::Immediate(0));
6312 __ AddImmediate(target_address_reg, -entry_offset);
6315 __ add(target_address_reg, target_address_reg, compiler::Operand(offset_reg));
6318 __ br(target_address_reg);
6321LocationSummary* StrictCompareInstr::MakeLocationSummary(Zone* zone,
6323 const intptr_t kNumInputs = 2;
6324 const intptr_t kNumTemps = 0;
6326 LocationSummary* locs =
new (zone)
6333 LocationSummary* locs =
new (zone)
6338 locs->set_in(1, locs->in(0).IsConstant()
6345Condition StrictCompareInstr::EmitComparisonCodeRegConstant(
6347 BranchLabels labels,
6349 const Object& obj) {
6350 Condition orig_cond = (kind() == Token::kEQ_STRICT) ?
EQ :
NE;
6353 CanUseCbzTbzForComparison(
compiler, reg, orig_cond, labels)) {
6363 compiler::Label is_true, is_false;
6364 BranchLabels labels = {&is_true, &is_false, &is_false};
6368 if (is_true.IsLinked() || is_false.IsLinked()) {
6370 EmitBranchOnCondition(
compiler, true_condition, labels);
6372 compiler::Label
done;
6390 BranchInstr* branch) {
6391 BranchLabels labels =
compiler->CreateBranchLabels(branch);
6394 EmitBranchOnCondition(
compiler, true_condition, labels);
6398LocationSummary* BooleanNegateInstr::MakeLocationSummary(Zone* zone,
6404void BooleanNegateInstr::EmitNativeCode(FlowGraphCompiler*
compiler) {
6405 const Register input = locs()->in(0).reg();
6412LocationSummary* BoolToIntInstr::MakeLocationSummary(Zone* zone,
6418void BoolToIntInstr::EmitNativeCode(FlowGraphCompiler*
compiler) {
6422LocationSummary* IntToBoolInstr::MakeLocationSummary(Zone* zone,
6428void IntToBoolInstr::EmitNativeCode(FlowGraphCompiler*
compiler) {
6434 const intptr_t kNumInputs = (
type_arguments() !=
nullptr) ? 1 : 0;
6435 const intptr_t kNumTemps = 0;
6436 LocationSummary*
locs =
new (zone)
6448 TypeUsageInfo* type_usage_info =
compiler->thread()->type_usage_info();
6449 if (type_usage_info !=
nullptr) {
6456 compiler->GenerateStubCall(
source(), stub, UntaggedPcDescriptors::kOther,
6460void DebugStepCheckInstr::EmitNativeCode(FlowGraphCompiler*
compiler) {
6465 __ BranchLinkPatchable(StubCode::DebugStepCheck());
static void done(const char *config, const char *src, const char *srcOptions, const char *name)
static void fail(const SkString &err)
static bool match(const char *needle, const char *haystack)
static bool are_equal(skiatest::Reporter *reporter, const SkMatrix &a, const SkMatrix &b)
static int float_bits(float f)
static bool ok(int result)
static bool left(const SkPoint &p0, const SkPoint &p1)
static bool right(const SkPoint &p0, const SkPoint &p1)
#define ASSERT_EQUAL(expected, actual)
#define RELEASE_ASSERT(cond)
#define COMPILE_ASSERT(expr)
intptr_t num_context_variables() const
Value * type_arguments() const
const Class & cls() const
intptr_t num_context_variables() const
static intptr_t type_arguments_offset()
static intptr_t InstanceSize()
static constexpr bool IsValidLength(intptr_t len)
static intptr_t length_offset()
Token::Kind op_kind() const
bool can_overflow() const
Token::Kind op_kind() const
bool RightIsPowerOfTwoConstant() const
Range * right_range() const
Representation to() const
Representation from() const
ParallelMoveInstr * parallel_move() const
bool HasParallelMove() const
BlockEntryInstr(intptr_t block_id, intptr_t try_index, intptr_t deopt_id, intptr_t stack_depth)
static const Bool & False()
static const Bool & True()
static void Allocate(FlowGraphCompiler *compiler, Instruction *instruction, const Class &cls, Register result, Register temp)
Representation from_representation() const
virtual bool ValueFitsSmi() const
ComparisonInstr * comparison() const
intptr_t index_scale() const
static constexpr Register kSecondReturnReg
static const Register ArgumentRegisters[]
static constexpr FpuRegister kReturnFpuReg
static constexpr Register kFfiAnyNonAbiRegister
static constexpr Register kReturnReg
static constexpr Register kSecondNonArgumentRegister
const RuntimeEntry & TargetFunction() const
bool IsDeoptIfNull() const
DECLARE_INSTRUCTION_SERIALIZABLE_FIELDS(CheckClassInstr, TemplateInstruction, FIELD_LIST) private void EmitBitTest(FlowGraphCompiler *compiler, intptr_t min, intptr_t max, intptr_t mask, compiler::Label *deopt)
void EmitNullCheck(FlowGraphCompiler *compiler, compiler::Label *deopt)
bool IsDeoptIfNotNull() const
virtual bool UseSharedSlowPathStub(bool is_optimizing) const
intptr_t loop_depth() const
virtual void EmitBranchCode(FlowGraphCompiler *compiler, BranchInstr *branch)
virtual void EmitNativeCode(FlowGraphCompiler *compiler)
virtual Condition EmitComparisonCode(FlowGraphCompiler *compiler, BranchLabels labels)=0
const Object & value() const
void EmitMoveToLocation(FlowGraphCompiler *compiler, const Location &destination, Register tmp=kNoRegister, intptr_t pair_index=0)
static intptr_t num_variables_offset()
static intptr_t InstanceSize()
Value * type_arguments() const
virtual Value * num_elements() const
virtual Representation representation() const
static constexpr intptr_t kNone
MethodRecognizer::Kind op_kind() const
MethodRecognizer::Kind recognized_kind() const
bool is_null_aware() const
void EmitReturnMoves(FlowGraphCompiler *compiler, const Register temp0, const Register temp1)
DECLARE_INSTRUCTION_SERIALIZABLE_FIELDS(FfiCallInstr, VariadicDefinition, FIELD_LIST) private void EmitParamMoves(FlowGraphCompiler *compiler, const Register saved_fp, const Register temp0, const Register temp1)
intptr_t TargetAddressIndex() const
static intptr_t guarded_cid_offset()
static intptr_t guarded_list_length_in_object_offset_offset()
intptr_t guarded_cid() const
static intptr_t is_nullable_offset()
static intptr_t guarded_list_length_offset()
ParallelMoveInstr * parallel_move() const
BlockEntryInstr * block() const
bool HasParallelMove() const
JoinEntryInstr * successor() const
FunctionEntryInstr * normal_entry() const
OsrEntryInstr * osr_entry() const
const Field & field() const
ComparisonInstr * comparison() const
virtual Representation RequiredInputRepresentation(intptr_t idx) const
const AbstractType & type() const
Environment * env() const
virtual LocationSummary * MakeLocationSummary(Zone *zone, bool is_optimizing) const =0
virtual void EmitNativeCode(FlowGraphCompiler *compiler)
void InitializeLocationSummary(Zone *zone, bool optimizing)
virtual Representation representation() const
InstructionSource source() const
intptr_t deopt_id() const
static LocationSummary * MakeCallSummary(Zone *zone, const Instruction *instr, LocationSummary *locs=nullptr)
bool is_truncating() const
Representation to() const
Representation from() const
const RuntimeEntry & TargetFunction() const
MethodRecognizer::Kind recognized_kind() const
ObjectStore * object_store() const
static IsolateGroup * Current()
intptr_t TargetAddressIndex() const
void EmitParamMoves(FlowGraphCompiler *compiler, Register saved_fp, Register temp0)
LocationSummary * MakeLocationSummaryInternal(Zone *zone, const RegList temps) const
intptr_t index_scale() const
bool can_pack_into_smi() const
intptr_t element_count() const
intptr_t class_id() const
intptr_t class_id() const
intptr_t index_scale() const
Representation representation() const
virtual Representation RequiredInputRepresentation(intptr_t index) const
Register base_reg() const
virtual Representation representation() const
const LocalVariable & local() const
Location temp(intptr_t index) const
Location out(intptr_t index) const
static LocationSummary * Make(Zone *zone, intptr_t input_count, Location out, ContainsCall contains_call)
void set_temp(intptr_t index, Location loc)
void set_out(intptr_t index, Location loc)
bool always_calls() const
Location in(intptr_t index) const
void set_in(intptr_t index, Location loc)
static Location NoLocation()
static Location SameAsFirstInput()
static Location Pair(Location first, Location second)
static Location FpuRegisterLocation(FpuRegister reg)
static Location WritableRegister()
static Location RegisterLocation(Register reg)
PairLocation * AsPairLocation() const
static Location RequiresRegister()
static Location RequiresFpuRegister()
FpuRegister fpu_reg() const
static Location Constant(const ConstantInstr *obj, int pair_index=0)
intptr_t result_cid() const
MethodRecognizer::Kind op_kind() const
bool unboxed_inputs() const
Value * src_start() const
void EmitLoopCopy(FlowGraphCompiler *compiler, Register dest_reg, Register src_reg, Register length_reg, compiler::Label *done, compiler::Label *copy_forwards=nullptr)
void PrepareLengthRegForLoop(FlowGraphCompiler *compiler, Register length_reg, compiler::Label *done)
Value * dest_start() const
static intptr_t value_offset()
virtual Representation representation() const
static int ComputeArgcTag(const Function &function)
bool is_auto_scope() const
bool is_bootstrap_native() const
const Function & function() const
NativeFunction native_c_function() const
static uword LinkNativeCallEntry()
static Object & ZoneHandle()
Value * char_code() const
static intptr_t data_offset()
Location At(intptr_t i) const
static bool IsNegative(Range *range)
static bool Overlaps(Range *range, intptr_t min, intptr_t max)
static bool OnlyLessThanOrEqualTo(Range *range, intptr_t value)
static bool IsWithin(const Range *range, int64_t min, int64_t max)
static bool IsPositive(Range *range)
static bool CanBeZero(Range *range)
DECLARE_INSTRUCTION_SERIALIZABLE_FIELDS(ShiftIntegerOpInstr, BinaryIntegerOpInstr, FIELD_LIST) protected bool IsShiftCountInRange(int64_t max=kShiftCountLimit) const
Range * shift_range() const
static constexpr intptr_t kBits
static SmiPtr New(intptr_t value)
static constexpr intptr_t kMaxValue
static intptr_t RawValue(intptr_t value)
const char * message() const
bool ShouldEmitStoreBarrier() const
virtual Representation RequiredInputRepresentation(intptr_t idx) const
intptr_t class_id() const
intptr_t index_scale() const
const LocalVariable & local() const
const Field & field() const
bool needs_number_check() const
static intptr_t length_offset()
static CodePtr GetAllocationStubForClass(const Class &cls)
static constexpr int kNullCharCodeSymbolOffset
intptr_t ArgumentCount() const
ArrayPtr GetArgumentsDescriptor() const
virtual intptr_t InputCount() const
const ZoneGrowableArray< intptr_t > & cid_results() const
virtual Representation representation() const
Token::Kind op_kind() const
Token::Kind op_kind() const
virtual Representation representation() const
bool is_truncating() const
virtual Representation representation() const
bool IsScanFlagsUnboxed() const
static bool IsInt(intptr_t N, T value)
static void CalculateMagicAndShiftForDivRem(int64_t divisor, int64_t *magic, int64_t *shift)
static constexpr T Maximum(T x, T y)
static constexpr int ShiftForPowerOfTwo(T x)
static T Minimum(T x, T y)
static T AddWithWrapAround(T a, T b)
static constexpr int CountOneBits64(uint64_t x)
static constexpr size_t HighestBit(int64_t v)
static constexpr bool IsPowerOfTwo(T x)
bool BindsToConstant() const
Definition * definition() const
Value(Definition *definition)
intptr_t InputCount() const
void static bool EmittingComments()
static bool AddressCanHoldConstantIndex(const Object &constant, bool is_load, bool is_external, intptr_t cid, intptr_t index_scale, bool *needs_base=nullptr)
intptr_t StackTopInBytes() const
FlutterSemanticsFlag flag
FlutterSemanticsFlag flags
Dart_NativeFunction function
static float max(float r, float g, float b)
static float min(float r, float g, float b)
#define CASE(Arity, Mask, Name, Args, Result)
#define DEFINE_UNIMPLEMENTED_INSTRUCTION(Name)
#define DEFINE_BACKEND(Name, Args)
const intptr_t kResultIndex
word ToRawSmi(const dart::Object &a)
const Object & NullObject()
constexpr OperandSize kWordBytes
bool HasIntegerValue(const dart::Object &object, int64_t *value)
constexpr int64_t kMaxInt64
constexpr int64_t kMinInt64
Location LocationAnyOrConstant(Value *value)
Location LocationRegisterOrConstant(Value *value)
const Register kWriteBarrierSlotReg
constexpr bool IsAbiPreservedRegister(Register reg)
static Condition InvertCondition(Condition c)
const RegList kAbiVolatileCpuRegs
static constexpr int kSavedCallerPcSlotFromFp
bool IsTypedDataBaseClassId(intptr_t index)
constexpr intptr_t kBitsPerWord
const Register kExceptionObjectReg
const Register kWriteBarrierObjectReg
static constexpr intptr_t kBoolVsNullBitPosition
const Register kWriteBarrierValueReg
static constexpr bool IsCalleeSavedRegister(Register reg)
constexpr intptr_t kIntptrMin
static const ClassId kLastErrorCid
static const ClassId kFirstErrorCid
void RegisterTypeArgumentsUse(const Function &function, TypeUsageInfo *type_usage_info, const Class &klass, Definition *type_arguments)
static constexpr int kParamEndSlotFromFp
const Register ARGS_DESC_REG
bool IsClampedTypedDataBaseClassId(intptr_t index)
Location LocationFixedRegisterOrConstant(Value *value, Register reg)
const int kNumberOfFpuRegisters
Location LocationWritableRegisterOrSmiConstant(Value *value, intptr_t min_value, intptr_t max_value)
bool IsExternalPayloadClassId(classid_t cid)
constexpr RegList kDartAvailableCpuRegs
static constexpr intptr_t kCompressedWordSize
static constexpr int kPcMarkerSlotFromFp
const Register FUNCTION_REG
const Register IC_DATA_REG
compiler::Address LocationToStackSlotAddress(Location loc)
constexpr intptr_t kWordSize
static bool IsConstant(Definition *def, int64_t *val)
static constexpr Representation kUnboxedIntPtr
const Register kStackTraceObjectReg
static int8_t data[kExtLength]
const RegList kAbiVolatileFpuRegs
Location LocationRegisterOrSmiConstant(Value *value, intptr_t min_value, intptr_t max_value)
constexpr intptr_t kBitsPerInt64
it will be possible to load the file into Perfetto s trace viewer disable asset Prevents usage of any non test fonts unless they were explicitly Loaded via prefetched default font Indicates whether the embedding started a prefetch of the default font manager before creating the engine run In non interactive mode
void Flush(SkSurface *surface)
static constexpr Register kResultReg
static constexpr Register kLengthReg
static constexpr Register kTypeArgumentsReg
static constexpr Register kResultReg
static constexpr Register kTempReg
static constexpr Register kTypeArgumentsReg
static constexpr Register kResultReg
static constexpr Register kObjectReg
static constexpr Representation NativeRepresentation(Representation rep)
static constexpr intptr_t kBoolValueMask
static constexpr size_t ValueSize(Representation rep)
static constexpr bool IsUnboxedInteger(Representation rep)
static compiler::OperandSize OperandSize(Representation rep)
static constexpr bool IsUnboxed(Representation rep)
static bool IsUnsignedInteger(Representation rep)
static Representation RepresentationOfArrayElement(classid_t cid)
static constexpr Register kDstTypeReg
static constexpr Register kInstanceReg
static constexpr Register kFunctionTypeArgumentsReg
static constexpr Register kInstantiatorTypeArgumentsReg
@ kResetToBootstrapNative