6#if defined(TARGET_ARCH_RISCV32) || defined(TARGET_ARCH_RISCV64)
28#define __ (compiler->assembler())->
29#define Z (compiler->zone())
37 const Instruction* instr,
38 LocationSummary* locs) {
83LocationSummary* LoadIndexedUnsafeInstr::MakeLocationSummary(Zone* zone,
85 const intptr_t kNumInputs = 1;
86 const intptr_t kNumTemps = 0;
87 LocationSummary* locs =
new (zone)
113void LoadIndexedUnsafeInstr::EmitNativeCode(FlowGraphCompiler*
compiler) {
122 const auto out = locs()->out(0).reg();
127 case kUnboxedInt64: {
129 const auto out_lo = locs()->out(0).AsPairLocation()->At(0).reg();
130 const auto out_hi = locs()->out(0).AsPairLocation()->At(1).reg();
133 __ LoadFromOffset(out_hi,
TMP,
offset() + compiler::target::kWordSize);
135 const auto out = locs()->out(0).reg();
141 case kUnboxedDouble: {
142 const auto out = locs()->out(0).fpu_reg();
155 ASSERT(instr->RequiredInputRepresentation(
157 __ AddShifted(
TMP, instr->base_reg(), index,
159 __ sx(value, compiler::Address(
TMP, instr->offset()));
166 Fixed<Register, ARGS_DESC_REG>,
167 Temp<Register> temp)) {
168 compiler->EmitTailCallToStub(instr->code());
174 __ set_constant_pool_allowed(
true);
177LocationSummary* MemoryCopyInstr::MakeLocationSummary(Zone* zone,
185 const intptr_t kNumInputs = 5;
186 const intptr_t kNumTemps = 2;
187 LocationSummary* locs =
new (zone)
202 compiler::Label*
done) {
203 __ BranchIfZero(length_reg,
done);
226static void CopyBytes(FlowGraphCompiler*
compiler,
237 const intptr_t
offset = (reversed ? -1 : 1) *
count;
238 const intptr_t initial = reversed ?
offset : 0;
239 __ lq(
TMP, compiler::Address(src_reg, initial));
241 __ sq(
TMP, compiler::Address(dest_reg, initial));
242 __ addi(dest_reg, dest_reg,
offset);
248 if (
count == 4 * (XLEN / 8)) {
249 auto const sz = OperandSizeFor(XLEN / 8);
250 const intptr_t
offset = (reversed ? -1 : 1) * (XLEN / 8);
251 const intptr_t initial = reversed ?
offset : 0;
252 __ LoadFromOffset(
TMP, src_reg, initial, sz);
254 __ StoreToOffset(
TMP, dest_reg, initial, sz);
256 __ LoadFromOffset(
TMP, src_reg, initial + 2 *
offset, sz);
257 __ LoadFromOffset(
TMP2, src_reg, initial + 3 *
offset, sz);
258 __ addi(src_reg, src_reg, 4 *
offset);
259 __ StoreToOffset(
TMP, dest_reg, initial + 2 *
offset, sz);
260 __ StoreToOffset(
TMP2, dest_reg, initial + 3 *
offset, sz);
261 __ addi(dest_reg, dest_reg, 4 *
offset);
267 if (
count == 2 * (XLEN / 8)) {
268 auto const sz = OperandSizeFor(XLEN / 8);
269 const intptr_t
offset = (reversed ? -1 : 1) * (XLEN / 8);
270 const intptr_t initial = reversed ?
offset : 0;
271 __ LoadFromOffset(
TMP, src_reg, initial, sz);
273 __ addi(src_reg, src_reg, 2 *
offset);
274 __ StoreToOffset(
TMP, dest_reg, initial, sz);
276 __ addi(dest_reg, dest_reg, 2 *
offset);
282 auto const sz = OperandSizeFor(
count);
283 const intptr_t
offset = (reversed ? -1 : 1) *
count;
284 const intptr_t initial = reversed ?
offset : 0;
285 __ LoadFromOffset(
TMP, src_reg, initial, sz);
287 __ StoreToOffset(
TMP, dest_reg, initial, sz);
288 __ addi(dest_reg, dest_reg,
offset);
291static void CopyUpToWordMultiple(FlowGraphCompiler*
compiler,
298 compiler::Label*
done) {
300 if (
element_size >= compiler::target::kWordSize)
return;
303 const intptr_t base_shift =
305 intptr_t tested_bits = 0;
307 __ Comment(
"Copying until region is a multiple of word size");
311 for (intptr_t bit = compiler::target::kWordSizeLog2 - 1; bit >= element_shift;
313 const intptr_t bytes = 1 << bit;
314 const intptr_t tested_bit = bit + base_shift;
315 tested_bits |= 1 << tested_bit;
316 compiler::Label skip_copy;
317 __ andi(
TMP, length_reg, 1 << tested_bit);
318 __ beqz(
TMP, &skip_copy);
319 CopyBytes(
compiler, dest_reg, src_reg, bytes, reversed);
324 __ andi(length_reg, length_reg, ~tested_bits);
325 __ beqz(length_reg,
done);
332 compiler::Label*
done,
333 compiler::Label* copy_forwards) {
334 const bool reversed = copy_forwards !=
nullptr;
341 __ add(
TMP, src_reg, length_reg);
342 }
else if (shift < 0) {
343 __ srai(
TMP, length_reg, -shift);
346 __ slli(
TMP, length_reg, shift);
349 __ CompareRegisters(dest_reg,
TMP);
353 __ add(dest_reg, dest_reg,
TMP);
354 __ sub(dest_reg, dest_reg, src_reg);
355 __ MoveRegister(src_reg,
TMP);
357 CopyUpToWordMultiple(
compiler, dest_reg, src_reg, length_reg, element_size_,
358 unboxed_inputs_, reversed,
done);
361 const intptr_t loop_subtract =
362 Utils::Maximum<intptr_t>(1, (XLEN / 8) / element_size_)
364 __ Comment(
"Copying by multiples of word size");
365 compiler::Label loop;
367 switch (element_size_) {
372 CopyBytes(
compiler, dest_reg, src_reg, 4, reversed);
377 CopyBytes(
compiler, dest_reg, src_reg, 8, reversed);
382 CopyBytes(
compiler, dest_reg, src_reg, 16, reversed);
388 __ subi(length_reg, length_reg, loop_subtract);
389 __ bnez(length_reg, &loop);
392void MemoryCopyInstr::EmitComputeStartPointer(FlowGraphCompiler*
compiler,
399 if (array_rep != kTagged) {
410 case kOneByteStringCid:
414 case kTwoByteStringCid:
423 ASSERT(start_loc.IsRegister() || start_loc.IsConstant());
424 if (start_loc.IsConstant()) {
425 const auto& constant = start_loc.constant();
426 ASSERT(constant.IsInteger());
427 const int64_t start_value = Integer::Cast(constant).AsInt64Value();
428 const intx_t add_value = Utils::AddWithWrapAround<intx_t>(
429 Utils::MulWithWrapAround<intx_t>(start_value, element_size_),
offset);
430 __ AddImmediate(payload_reg, array_reg, add_value);
433 const Register start_reg = start_loc.reg();
436 __ AddShifted(payload_reg, array_reg, start_reg, shift);
437 __ AddImmediate(payload_reg,
offset);
440LocationSummary* CalculateElementAddressInstr::MakeLocationSummary(
443 const intptr_t kNumInputs = 3;
444 const intptr_t kNumTemps = 0;
445 auto*
const summary =
new (zone)
455 kMaxIntX >> scale_shift));
466void CalculateElementAddressInstr::EmitNativeCode(FlowGraphCompiler*
compiler) {
470 const Register result_reg = locs()->out(0).reg();
472 if (index_loc.IsConstant()) {
473 if (offset_loc.IsConstant()) {
474 ASSERT_EQUAL(Smi::Cast(index_loc.constant()).Value(), 0);
475 ASSERT(Integer::Cast(offset_loc.constant()).AsInt64Value() != 0);
477 const intx_t offset_value =
478 Integer::Cast(offset_loc.constant()).AsInt64Value();
479 __ AddImmediate(result_reg, base_reg, offset_value);
481 __ add(result_reg, base_reg, offset_loc.reg());
484 const intx_t scaled_index =
485 Smi::Cast(index_loc.constant()).Value() *
index_scale();
486 __ AddImmediate(result_reg, scaled_index);
489 __ AddShifted(result_reg, base_reg, index_loc.reg(),
491 if (offset_loc.IsConstant()) {
492 const intx_t offset_value =
493 Integer::Cast(offset_loc.constant()).AsInt64Value();
494 __ AddImmediate(result_reg, offset_value);
496 __ AddRegisters(result_reg, offset_loc.reg());
501LocationSummary* MoveArgumentInstr::MakeLocationSummary(Zone* zone,
503 const intptr_t kNumInputs = 1;
504 const intptr_t kNumTemps = 0;
505 LocationSummary* locs =
new (zone)
508 if (constant !=
nullptr && constant->HasZeroRepresentation()) {
526void MoveArgumentInstr::EmitNativeCode(FlowGraphCompiler*
compiler) {
530 if (
value.IsRegister()) {
532 location().stack_index() * compiler::target::kWordSize);
534 }
else if (
value.IsPairLocation()) {
535 __ StoreToOffset(
value.AsPairLocation()->At(1).reg(),
SP,
536 location().AsPairLocation()->At(1).stack_index() *
537 compiler::target::kWordSize);
538 __ StoreToOffset(
value.AsPairLocation()->At(0).reg(),
SP,
539 location().AsPairLocation()->At(0).stack_index() *
540 compiler::target::kWordSize);
542 }
else if (
value.IsConstant()) {
544 ASSERT(
value.constant_instruction()->HasZeroRepresentation());
547 __ StoreToOffset(
ZR,
SP,
offset + compiler::target::kWordSize);
553 ASSERT(
value.constant_instruction()->HasZeroRepresentation());
556 location().AsPairLocation()->At(1).stack_index() *
557 compiler::target::kWordSize);
559 location().AsPairLocation()->At(0).stack_index() *
560 compiler::target::kWordSize);
563 location().stack_index() * compiler::target::kWordSize);
567 const Object& constant =
value.constant();
569 if (constant.IsNull()) {
571 }
else if (constant.IsSmi() && Smi::Cast(constant).Value() == 0) {
575 __ LoadObject(
TMP, constant);
577 __ StoreToOffset(reg,
SP,
578 location().stack_index() * compiler::target::kWordSize);
580 }
else if (
value.IsFpuRegister()) {
582 location().stack_index() * compiler::target::kWordSize);
583 }
else if (
value.IsStackSlot()) {
584 const intptr_t value_offset =
value.ToStackSlotOffset();
585 __ LoadFromOffset(
TMP,
value.base_reg(), value_offset);
587 location().stack_index() * compiler::target::kWordSize);
595 const intptr_t kNumInputs = 1;
596 const intptr_t kNumTemps = 0;
597 LocationSummary*
locs =
new (zone)
638 if (
locs()->in(0).IsRegister()) {
641 }
else if (
locs()->in(0).IsPairLocation()) {
652 if (
compiler->parsed_function().function().IsAsyncFunction() ||
653 compiler->parsed_function().function().IsAsyncGenerator()) {
655 const Code& stub = GetReturnStub(
compiler);
660 if (!
compiler->flow_graph().graph_entry()->NeedsFrame()) {
665 const intptr_t fp_sp_dist =
666 (compiler::target::frame_layout.first_local_from_fp + 1 -
669 __ CheckFpSpDist(fp_sp_dist);
671 __ LeaveDartFrame(fp_sp_dist);
675 __ set_constant_pool_allowed(
true);
679static bool IsPowerOfTwoKind(intptr_t v1, intptr_t
v2) {
700 BranchLabels labels = {
nullptr,
nullptr,
nullptr};
704 const bool is_power_of_two_kind = IsPowerOfTwoKind(if_true_, if_false_);
706 intptr_t true_value = if_true_;
707 intptr_t false_value = if_false_;
709 if (is_power_of_two_kind) {
710 if (true_value == 0) {
715 if (true_value == 0) {
717 intptr_t temp = true_value;
718 true_value = false_value;
727 if (is_power_of_two_kind) {
728 const intptr_t shift =
735 if (false_value != 0) {
743 const intptr_t kNumInputs = 1;
744 const intptr_t kNumTemps = 0;
745 LocationSummary* summary =
new (zone)
755 const Array& arguments_descriptor =
759 if (FLAG_precompiled_mode) {
762 __ LoadFieldFromOffset(
A1,
T0,
763 compiler::target::Closure::entry_point_offset());
768 compiler::target::Function::code_offset());
771 compiler::target::Function::entry_point_offset());
777 if (!FLAG_precompiled_mode) {
783 UntaggedPcDescriptors::kOther,
locs(),
env());
787LocationSummary* LoadLocalInstr::MakeLocationSummary(Zone* zone,
793void LoadLocalInstr::EmitNativeCode(FlowGraphCompiler*
compiler) {
796 compiler::target::FrameOffsetInBytesForVariable(&
local()));
801LocationSummary* StoreLocalInstr::MakeLocationSummary(Zone* zone,
807void StoreLocalInstr::EmitNativeCode(FlowGraphCompiler*
compiler) {
812 compiler::target::FrameOffsetInBytesForVariable(&
local()));
817LocationSummary* ConstantInstr::MakeLocationSummary(Zone* zone,
823void ConstantInstr::EmitNativeCode(FlowGraphCompiler*
compiler) {
825 if (!locs()->
out(0).IsInvalid()) {
834 intptr_t pair_index) {
835 if (destination.IsRegister()) {
840 if (value_.IsSmi() &&
847 __ LoadImmediate(destination.reg(), pair_index == 0
849 : Utils::High32Bits(v));
852 __ LoadImmediate(destination.reg(), v);
855 ASSERT(representation() == kTagged);
856 __ LoadObject(destination.reg(), value_);
858 }
else if (destination.IsFpuRegister()) {
860 if (representation() == kUnboxedFloat) {
861 __ LoadSImmediate(dst, Double::Cast(value_).
value());
863 ASSERT(representation() == kUnboxedDouble);
864 __ LoadDImmediate(dst, Double::Cast(value_).
value());
866 }
else if (destination.IsDoubleStackSlot()) {
867 const intptr_t dest_offset = destination.ToStackSlotOffset();
873 __ StoreToOffset(
ZR, destination.base_reg(), dest_offset);
875 __ LoadDImmediate(
FTMP, Double::Cast(value_).
value());
876 __ StoreDToOffset(
FTMP, destination.base_reg(), dest_offset);
879 ASSERT(destination.IsStackSlot());
881 const intptr_t dest_offset = destination.ToStackSlotOffset();
884 int64_t val = Integer::Cast(value_).AsInt64Value();
893 __ LoadImmediate(tmp, val);
895 }
else if (representation() == kUnboxedFloat) {
897 bit_cast<int32_t, float>(Double::Cast(value_).
value());
901 ASSERT(representation() == kTagged);
902 if (value_.IsNull()) {
904 }
else if (value_.IsSmi() && Smi::Cast(value_).Value() == 0) {
907 __ LoadObject(tmp, value_);
910 __ StoreToOffset(tmp, destination.base_reg(), dest_offset, operand_size);
914LocationSummary* UnboxedConstantInstr::MakeLocationSummary(Zone* zone,
916 const bool is_unboxed_int =
919 compiler::target::kWordSize);
920 const intptr_t kNumInputs = 0;
921 const intptr_t kNumTemps = is_unboxed_int ? 0 : 1;
922 LocationSummary* locs =
new (zone)
924 if (is_unboxed_int) {
927 switch (representation()) {
940void UnboxedConstantInstr::EmitNativeCode(FlowGraphCompiler*
compiler) {
941 if (!locs()->
out(0).IsInvalid()) {
945 : locs()->temp(0).reg();
950LocationSummary* AssertAssignableInstr::MakeLocationSummary(Zone* zone,
952 auto const dst_type_loc =
962 const intptr_t kNonChangeableInputRegs =
964 ((dst_type_loc.IsRegister() ? 1 : 0) << TypeTestABI::kDstTypeReg) |
965 (1 << TypeTestABI::kInstantiatorTypeArgumentsReg) |
966 (1 << TypeTestABI::kFunctionTypeArgumentsReg);
968 const intptr_t kNumInputs = 4;
975 const intptr_t kCpuRegistersToPreserve =
977 const intptr_t kFpuRegistersToPreserve =
983 LocationSummary* summary =
new (zone) LocationSummary(
985 summary->set_in(kInstancePos,
987 summary->set_in(kDstTypePos, dst_type_loc);
996 intptr_t next_temp = 0;
998 const bool should_preserve = ((1 << i) & kCpuRegistersToPreserve) != 0;
999 if (should_preserve) {
1000 summary->set_temp(next_temp++,
1006 const bool should_preserve = ((1l << i) & kFpuRegistersToPreserve) != 0;
1007 if (should_preserve) {
1016void AssertBooleanInstr::EmitNativeCode(FlowGraphCompiler*
compiler) {
1017 ASSERT(locs()->always_calls());
1019 auto object_store =
compiler->isolate_group()->object_store();
1020 const auto& assert_boolean_stub =
1023 compiler::Label
done;
1027 UntaggedPcDescriptors::kOther, locs(),
1053 switch (condition) {
1080static void EmitBranchOnCondition(FlowGraphCompiler*
compiler,
1082 BranchLabels labels) {
1083 if (labels.fall_through == labels.false_label) {
1085 __ BranchIf(true_condition, labels.true_label);
1089 __ BranchIf(false_condition, labels.false_label);
1092 if (labels.fall_through != labels.true_label) {
1093 __ j(labels.true_label);
1099 LocationSummary* locs,
1101 BranchLabels labels) {
1106 Condition true_condition = TokenKindToIntCondition(kind);
1107 if (
left.IsConstant() ||
right.IsConstant()) {
1109 if (
left.IsConstant()) {
1113 true_condition = FlipCondition(true_condition);
1117 __ CompareObjectRegisters(
left.reg(),
right.reg());
1119 return true_condition;
1123 LocationSummary* locs,
1125 BranchLabels labels) {
1130 Condition true_condition = TokenKindToIntCondition(kind);
1131 if (
left.IsConstant() ||
right.IsConstant()) {
1133 if (
left.IsConstant()) {
1137 true_condition = FlipCondition(true_condition);
1139 __ CompareImmediate(
1141 static_cast<uword>(Integer::Cast(
right.constant()).AsInt64Value()));
1145 return true_condition;
1150 LocationSummary* locs,
1153 PairLocation* left_pair = locs->in(0).AsPairLocation();
1154 Register left_lo = left_pair->At(0).reg();
1155 Register left_hi = left_pair->At(1).reg();
1156 PairLocation* right_pair = locs->in(1).AsPairLocation();
1157 Register right_lo = right_pair->At(0).reg();
1158 Register right_hi = right_pair->At(1).reg();
1160 __ xor_(
TMP, left_lo, right_lo);
1161 __ xor_(
TMP2, left_hi, right_hi);
1163 __ CompareImmediate(
TMP, 0);
1164 if (kind == Token::kEQ) {
1166 }
else if (kind == Token::kNE) {
1173 LocationSummary* locs,
1175 BranchLabels labels) {
1176 PairLocation* left_pair = locs->in(0).AsPairLocation();
1177 Register left_lo = left_pair->At(0).reg();
1178 Register left_hi = left_pair->At(1).reg();
1179 PairLocation* right_pair = locs->in(1).AsPairLocation();
1180 Register right_lo = right_pair->At(0).reg();
1181 Register right_hi = right_pair->At(1).reg();
1185 __ bne(left_lo, right_lo, labels.false_label);
1186 __ CompareRegisters(left_hi, right_hi);
1189 __ bne(left_lo, right_lo, labels.true_label);
1190 __ CompareRegisters(left_hi, right_hi);
1193 __ blt(left_hi, right_hi, labels.true_label);
1194 __ bgt(left_hi, right_hi, labels.false_label);
1195 __ CompareRegisters(left_lo, right_lo);
1198 __ bgt(left_hi, right_hi, labels.true_label);
1199 __ blt(left_hi, right_hi, labels.false_label);
1200 __ CompareRegisters(left_lo, right_lo);
1203 __ blt(left_hi, right_hi, labels.true_label);
1204 __ bgt(left_hi, right_hi, labels.false_label);
1205 __ CompareRegisters(left_lo, right_lo);
1208 __ bgt(left_hi, right_hi, labels.true_label);
1209 __ blt(left_hi, right_hi, labels.false_label);
1210 __ CompareRegisters(left_lo, right_lo);
1224 LocationSummary* locs,
1226 BranchLabels labels) {
1231 Condition true_condition = TokenKindToIntCondition(kind);
1232 if (
left.IsConstant() ||
right.IsConstant()) {
1235 if (
left.IsConstant()) {
1236 constant =
left.constant_instruction();
1240 true_condition = FlipCondition(true_condition);
1242 constant =
right.constant_instruction();
1256 return true_condition;
1261 LocationSummary* locs,
1263 BranchLabels labels) {
1264 ASSERT((kind == Token::kEQ) || (kind == Token::kNE));
1267 const Condition true_condition = TokenKindToIntCondition(kind);
1268 compiler::Label* equal_result =
1269 (true_condition ==
EQ) ? labels.true_label : labels.false_label;
1270 compiler::Label* not_equal_result =
1271 (true_condition ==
EQ) ? labels.false_label : labels.true_label;
1276 __ BranchIf(
EQ, equal_result);
1278 __ BranchIfSmi(
TMP, not_equal_result);
1280 __ BranchIf(
NE, not_equal_result);
1282 __ BranchIf(
NE, not_equal_result);
1284 __ LoadFieldFromOffset(
TMP,
left, compiler::target::Mint::value_offset());
1285 __ LoadFieldFromOffset(
TMP2,
right, compiler::target::Mint::value_offset());
1287 __ LoadFieldFromOffset(
1289 compiler::target::Mint::value_offset() + compiler::target::kWordSize);
1290 __ LoadFieldFromOffset(
1292 compiler::target::Mint::value_offset() + compiler::target::kWordSize);
1298 return true_condition;
1301LocationSummary* EqualityCompareInstr::MakeLocationSummary(Zone* zone,
1303 const intptr_t kNumInputs = 2;
1304 const intptr_t kNumTemps = 0;
1305 if (is_null_aware()) {
1306 LocationSummary* locs =
new (zone)
1314 if (operation_cid() == kMintCid) {
1315 LocationSummary* locs =
new (zone)
1325 if (operation_cid() == kDoubleCid) {
1326 LocationSummary* locs =
new (zone)
1333 if (operation_cid() == kSmiCid || operation_cid() == kMintCid ||
1334 operation_cid() == kIntegerCid) {
1335 LocationSummary* locs =
new (zone)
1337 if (is_null_aware()) {
1345 locs->set_in(1, locs->in(0).IsConstant()
1357 LocationSummary* locs,
1358 BranchLabels labels,
1366 __ CompareImmediate(
TMP, 0);
1370 __ CompareImmediate(
TMP, 0);
1374 __ CompareImmediate(
TMP, 0);
1378 __ CompareImmediate(
TMP, 0);
1382 __ CompareImmediate(
TMP, 0);
1386 __ CompareImmediate(
TMP, 0);
1394 BranchLabels labels) {
1395 if (is_null_aware()) {
1396 ASSERT(operation_cid() == kMintCid);
1397 return EmitNullAwareInt64ComparisonOp(
compiler, locs(), kind(), labels);
1399 if (operation_cid() == kSmiCid) {
1400 return EmitSmiComparisonOp(
compiler, locs(), kind(), labels);
1401 }
else if (operation_cid() == kIntegerCid) {
1402 return EmitWordComparisonOp(
compiler, locs(), kind(), labels);
1403 }
else if (operation_cid() == kMintCid) {
1405 return EmitUnboxedMintEqualityOp(
compiler, locs(), kind());
1407 return EmitInt64ComparisonOp(
compiler, locs(), kind(), labels);
1410 ASSERT(operation_cid() == kDoubleCid);
1411 return EmitDoubleComparisonOp(
compiler, locs(), labels, kind());
1415LocationSummary* TestSmiInstr::MakeLocationSummary(Zone* zone,
bool opt)
const {
1416 const intptr_t kNumInputs = 2;
1417 const intptr_t kNumTemps = 0;
1418 LocationSummary* locs =
new (zone)
1428 BranchLabels labels) {
1431 if (
right.IsConstant()) {
1433 const intx_t imm =
static_cast<intx_t
>(
right.constant().ptr());
1434 __ TestImmediate(
left, imm);
1438 Condition true_condition = (kind() == Token::kNE) ?
NE :
EQ;
1439 return true_condition;
1442LocationSummary* TestCidsInstr::MakeLocationSummary(Zone* zone,
1444 const intptr_t kNumInputs = 1;
1445 const intptr_t kNumTemps = 1;
1446 LocationSummary* locs =
new (zone)
1455 BranchLabels labels) {
1456 ASSERT((kind() == Token::kIS) || (kind() == Token::kISNOT));
1457 const Register val_reg = locs()->in(0).reg();
1458 const Register cid_reg = locs()->temp(0).reg();
1460 compiler::Label* deopt =
1462 ?
compiler->AddDeoptStub(deopt_id(), ICData::kDeoptTestCids)
1465 const intptr_t true_result = (kind() == Token::kIS) ? 1 : 0;
1466 const ZoneGrowableArray<intptr_t>&
data = cid_results();
1469 __ BranchIfSmi(val_reg,
result ? labels.true_label : labels.false_label);
1470 __ LoadClassId(cid_reg, val_reg);
1472 for (intptr_t i = 2; i <
data.length(); i += 2) {
1473 const intptr_t test_cid =
data[i];
1474 ASSERT(test_cid != kSmiCid);
1476 __ CompareImmediate(cid_reg, test_cid);
1477 __ BranchIf(
EQ,
result ? labels.true_label : labels.false_label);
1480 if (deopt ==
nullptr) {
1484 compiler::Label*
target =
result ? labels.false_label : labels.true_label;
1485 if (
target != labels.fall_through) {
1496LocationSummary* RelationalOpInstr::MakeLocationSummary(Zone* zone,
1498 const intptr_t kNumInputs = 2;
1499 const intptr_t kNumTemps = 0;
1501 if (operation_cid() == kMintCid) {
1502 LocationSummary* locs =
new (zone)
1512 if (operation_cid() == kDoubleCid) {
1513 LocationSummary* summary =
new (zone)
1520 if (operation_cid() == kSmiCid || operation_cid() == kMintCid) {
1521 LocationSummary* summary =
new (zone)
1526 summary->set_in(1, summary->in(0).IsConstant()
1538 BranchLabels labels) {
1539 if (operation_cid() == kSmiCid) {
1540 return EmitSmiComparisonOp(
compiler, locs(), kind(), labels);
1541 }
else if (operation_cid() == kMintCid) {
1543 return EmitUnboxedMintComparisonOp(
compiler, locs(), kind(), labels);
1545 return EmitInt64ComparisonOp(
compiler, locs(), kind(), labels);
1548 ASSERT(operation_cid() == kDoubleCid);
1549 return EmitDoubleComparisonOp(
compiler, locs(), labels, kind());
1566 if (link_lazily()) {
1567 stub = &StubCode::CallBootstrapNative();
1570 entry =
reinterpret_cast<uword>(native_c_function());
1571 if (is_bootstrap_native()) {
1572 stub = &StubCode::CallBootstrapNative();
1573 }
else if (is_auto_scope()) {
1574 stub = &StubCode::CallAutoScopeNative();
1576 stub = &StubCode::CallNoScopeNative();
1579 __ LoadImmediate(
T1, argc_tag);
1580 compiler::ExternalLabel label(entry);
1581 __ LoadNativeEntry(
T5, &label,
1582 link_lazily() ? ObjectPool::Patchability::kPatchable
1583 : ObjectPool::Patchability::kNotPatchable);
1584 if (link_lazily()) {
1586 source(), *stub, UntaggedPcDescriptors::kOther, locs(),
1591 compiler->GenerateNonLazyDeoptableStubCall(
1592 source(), *stub, UntaggedPcDescriptors::kOther, locs(),
1596 compiler->EmitDropArguments(ArgumentCount());
1599#define R(r) (1 << r)
1602 bool is_optimizing)
const {
1603 return MakeLocationSummaryInternal(
1604 zone, is_optimizing,
1615 const Register temp1 = locs()->temp(0).reg();
1620 const Register saved_fp_or_sp = locs()->temp(1).reg();
1621 const Register temp2 = locs()->temp(2).reg();
1625 ASSERT(temp1 != saved_fp_or_sp);
1626 ASSERT(temp2 != saved_fp_or_sp);
1638 if (FLAG_precompiled_mode) {
1639 __ subi(
SP,
SP, 2 * compiler::target::kWordSize);
1640 __ sx(
RA, compiler::Address(
SP, 1 * compiler::target::kWordSize));
1641 __ sx(
FP, compiler::Address(
SP, 0 * compiler::target::kWordSize));
1642 __ addi(
FP,
SP, 2 * compiler::target::kWordSize);
1644 __ subi(
SP,
SP, 4 * compiler::target::kWordSize);
1645 __ sx(
RA, compiler::Address(
SP, 3 * compiler::target::kWordSize));
1646 __ sx(
FP, compiler::Address(
SP, 2 * compiler::target::kWordSize));
1647 __ sx(
NULL_REG, compiler::Address(
SP, 1 * compiler::target::kWordSize));
1648 __ sx(
NULL_REG, compiler::Address(
SP, 0 * compiler::target::kWordSize));
1649 __ addi(
FP,
SP, 4 * compiler::target::kWordSize);
1654 intptr_t stack_space = marshaller_.RequiredStackSpaceInBytes();
1655 __ ReserveAlignedFrameSpace(stack_space);
1656#if defined(USING_MEMORY_SANITIZER)
1660 __ PushRegisters(kVolatileRegisterSet);
1664 __ LoadImmediate(
A1, stack_space);
1666 compiler::Address(
THR, kMsanUnpoisonRuntimeEntry.OffsetFromThread()));
1670 __ mv(
A0, is_leaf_ ?
FPREG : saved_fp_or_sp);
1673 compiler::Address(
THR, kMsanUnpoisonRuntimeEntry.OffsetFromThread()));
1677 __ CallCFunction(compiler::Address(
1678 THR, kMsanUnpoisonParamRuntimeEntry.OffsetFromThread()));
1680 __ PopRegisters(kVolatileRegisterSet);
1684 EmitParamMoves(
compiler, is_leaf_ ?
FPREG : saved_fp_or_sp, temp1, temp2);
1687 __ Comment(is_leaf_ ?
"Leaf Call" :
"Call");
1691#if !defined(PRODUCT)
1695 compiler::target::Thread::top_exit_frame_info_offset());
1696 __ StoreToOffset(
target,
THR, compiler::target::Thread::vm_tag_offset());
1704#if !defined(PRODUCT)
1705 __ LoadImmediate(temp1, compiler::target::Thread::vm_tag_dart_id());
1706 __ StoreToOffset(temp1,
THR, compiler::target::Thread::vm_tag_offset());
1708 compiler::target::Thread::top_exit_frame_info_offset());
1716 UntaggedPcDescriptors::Kind::kOther, locs(),
1721 if (CanExecuteGeneratedCodeInSafepoint()) {
1723 __ LoadImmediate(temp1, compiler::target::Thread::exit_through_ffi());
1733 __ TransitionNativeToGenerated(temp1,
true);
1741 THR, compiler::target::Thread::
1742 call_native_through_safepoint_entry_point_offset()));
1753 __ Comment(
"Check Dart_Handle for Error.");
1756 compiler::Label not_error;
1758 compiler::target::LocalHandle::ptr_offset());
1759 __ BranchIfSmi(temp1, ¬_error);
1760 __ LoadClassId(temp1, temp1);
1765 __ Comment(
"Slow path: call Dart_PropagateError through stub.");
1770 THR, compiler::target::Thread::
1771 call_native_through_safepoint_entry_point_offset()));
1773 THR, kPropagateErrorRuntimeEntry.OffsetFromThread()));
1780 __ Bind(¬_error);
1785 __ RestorePinnedRegisters();
1788 EmitReturnMoves(
compiler, temp1, temp2);
1794 __ LeaveDartFrame();
1798 if (FLAG_precompiled_mode) {
1799 __ SetupGlobalPoolAndDispatchTable();
1804 __ RestorePoolPointer();
1805 __ set_constant_pool_allowed(
true);
1812 __ LeaveDartFrame();
1819 const Register old_exit_through_ffi_reg =
T4;
1822 __ PopRegisterPair(old_exit_frame_reg, old_exit_through_ffi_reg);
1825 __ PopRegisterPair(tmp, vm_tag_reg);
1826 __ StoreToOffset(tmp,
THR, compiler::target::Thread::top_resource_offset());
1831 __ TransitionGeneratedToNative(vm_tag_reg, old_exit_frame_reg,
1832 old_exit_through_ffi_reg,
1835 __ PopNativeCalleeSavedRegisters();
1846 __ set_constant_pool_allowed(
true);
1850void NativeEntryInstr::EmitNativeCode(FlowGraphCompiler*
compiler) {
1852 __ set_constant_pool_allowed(
false);
1871 __ PushImmediate(0);
1873 __ PushNativeCalleeSavedRegisters();
1875#if defined(USING_SHADOW_CALL_STACK)
1880 __ RestorePinnedRegisters();
1883 __ LoadFromOffset(
TMP,
THR, compiler::target::Thread::vm_tag_offset());
1885 __ LoadFromOffset(
A0,
THR, compiler::target::Thread::top_resource_offset());
1888 __ StoreToOffset(
ZR,
THR, compiler::target::Thread::top_resource_offset());
1891 compiler::target::Thread::exit_through_ffi_offset());
1892 __ PushRegister(
A0);
1897 compiler::target::Thread::top_exit_frame_info_offset());
1898 __ PushRegister(
A0);
1902 __ EmitEntryFrameVerification();
1905 __ TransitionNativeToGenerated(
A0,
false);
1911 const Function& target_function = marshaller_.dart_signature();
1912 const intptr_t callback_id = target_function.FfiCallbackId();
1913 __ LoadFromOffset(
A0,
THR, compiler::target::Thread::isolate_group_offset());
1914 __ LoadFromOffset(
A0,
A0,
1915 compiler::target::IsolateGroup::object_store_offset());
1916 __ LoadFromOffset(
A0,
A0,
1917 compiler::target::ObjectStore::ffi_callback_code_offset());
1918 __ LoadCompressedFieldFromOffset(
1919 A0,
A0, compiler::target::GrowableObjectArray::data_offset());
1920 __ LoadCompressedFieldFromOffset(
1922 compiler::target::Array::data_offset() +
1923 callback_id * compiler::target::kCompressedWordSize);
1928 if (FLAG_precompiled_mode) {
1929 __ SetupGlobalPoolAndDispatchTable();
1943 compiler::target::Thread::invoke_dart_code_stub_offset());
1944 __ LoadFieldFromOffset(
RA,
RA, compiler::target::Code::entry_point_offset());
1946 FunctionEntryInstr::EmitNativeCode(
compiler);
1949#define R(r) (1 << r)
1953 bool is_optimizing)
const {
1956 static_assert(saved_fp < temp0,
"Unexpected ordering of registers in set.");
1957 LocationSummary* summary =
1958 MakeLocationSummaryInternal(zone, (
R(saved_fp) |
R(temp0)));
1965 const Register saved_fp = locs()->temp(0).reg();
1966 const Register temp0 = locs()->temp(1).reg();
1968 __ MoveRegister(saved_fp,
FPREG);
1970 const intptr_t frame_space = native_calling_convention_.StackTopInBytes();
1971 __ EnterCFrame(frame_space);
1973 EmitParamMoves(
compiler, saved_fp, temp0);
1975 const Register target_address = locs()->in(TargetAddressIndex()).reg();
1977 RELEASE_ASSERT(native_calling_convention_.argument_locations().length() < 4);
1978 __ sx(target_address,
1979 compiler::Address(
THR, compiler::target::Thread::vm_tag_offset()));
1980 __ CallCFunction(target_address);
1981 __ li(temp0, VMTag::kDartTagId);
1983 compiler::Address(
THR, compiler::target::Thread::vm_tag_offset()));
1988LocationSummary* OneByteStringFromCharCodeInstr::MakeLocationSummary(
1991 const intptr_t kNumInputs = 1;
1997void OneByteStringFromCharCodeInstr::EmitNativeCode(
2000 const Register char_code = locs()->in(0).reg();
2003 compiler::Address(
THR, Thread::predefined_symbols_address_offset()));
2009LocationSummary* StringToCharCodeInstr::MakeLocationSummary(Zone* zone,
2011 const intptr_t kNumInputs = 1;
2016void StringToCharCodeInstr::EmitNativeCode(FlowGraphCompiler*
compiler) {
2017 ASSERT(cid_ == kOneByteStringCid);
2018 Register str = locs()->in(0).reg();
2020 compiler::Label is_one,
done;
2033LocationSummary* Utf8ScanInstr::MakeLocationSummary(Zone* zone,
2035 const intptr_t kNumInputs = 5;
2036 const intptr_t kNumTemps = 0;
2037 LocationSummary* summary =
new (zone)
2048void Utf8ScanInstr::EmitNativeCode(FlowGraphCompiler*
compiler) {
2049 const Register bytes_reg = locs()->in(1).reg();
2050 const Register start_reg = locs()->in(2).reg();
2051 const Register end_reg = locs()->in(3).reg();
2052 const Register table_reg = locs()->in(4).reg();
2053 const Register size_reg = locs()->out(0).reg();
2055 const Register bytes_ptr_reg = start_reg;
2056 const Register bytes_end_reg = end_reg;
2057 const Register flags_reg = bytes_reg;
2059 const Register decoder_temp_reg = start_reg;
2060 const Register flags_temp_reg = end_reg;
2062 const intptr_t kSizeMask = 0x03;
2063 const intptr_t kFlagsMask = 0x3C;
2065 compiler::Label loop, loop_in;
2068 __ LoadFromSlot(bytes_reg, bytes_reg, Slot::PointerBase_data());
2072 table_reg, table_reg,
2073 compiler::target::OneByteString::data_offset() -
kHeapObjectTag);
2076 __ add(bytes_ptr_reg, bytes_reg, start_reg);
2077 __ add(bytes_end_reg, bytes_reg, end_reg);
2081 __ li(flags_reg, 0);
2087 __ lbu(temp_reg, compiler::Address(bytes_ptr_reg, 0));
2088 __ addi(bytes_ptr_reg, bytes_ptr_reg, 1);
2091 __ add(temp_reg, table_reg, temp_reg);
2092 __ lbu(temp_reg, compiler::Address(temp_reg));
2093 __ or_(flags_reg, flags_reg, temp_reg);
2094 __ andi(temp_reg, temp_reg, kSizeMask);
2095 __ add(size_reg, size_reg, temp_reg);
2102 __ AndImmediate(flags_reg, flags_reg, kFlagsMask);
2103 if (!IsScanFlagsUnboxed()) {
2104 __ SmiTag(flags_reg);
2107 const Location decoder_location = locs()->in(0);
2108 if (decoder_location.IsStackSlot()) {
2110 decoder_reg = decoder_temp_reg;
2112 decoder_reg = decoder_location.reg();
2114 const auto scan_flags_field_offset = scan_flags_field_.offset_in_bytes();
2115 if (scan_flags_field_.is_compressed() && !IsScanFlagsUnboxed()) {
2118 __ LoadFieldFromOffset(flags_temp_reg, decoder_reg,
2119 scan_flags_field_offset);
2120 __ or_(flags_temp_reg, flags_temp_reg, flags_reg);
2121 __ StoreFieldToOffset(flags_temp_reg, decoder_reg, scan_flags_field_offset);
2125LocationSummary* LoadIndexedInstr::MakeLocationSummary(Zone* zone,
2132 const intptr_t kNumInputs = 2;
2133 const intptr_t kNumTemps = 0;
2134 LocationSummary* locs =
new (zone)
2137 const bool can_be_constant =
2138 index()->BindsToConstant() &&
2140 index()->BoundConstant(), IsUntagged(), class_id(), index_scale());
2141 locs->set_in(kIndexPos,
2150 if (rep == kUnboxedInt64) {
2163void LoadIndexedInstr::EmitNativeCode(FlowGraphCompiler*
compiler) {
2165 const Register array = locs()->in(kArrayPos).reg();
2166 const Location index = locs()->in(kIndexPos);
2168 compiler::Address element_address(
TMP);
2169 element_address = index.IsRegister()
2170 ?
__ ElementAddressForRegIndex(
2171 IsUntagged(), class_id(), index_scale(),
2172 index_unboxed_, array, index.reg(),
TMP)
2173 :
__ ElementAddressForIntIndex(
2174 IsUntagged(), class_id(), index_scale(), array,
2175 Smi::Cast(index.constant()).
Value());
2182 if (rep == kUnboxedInt64) {
2183 ASSERT(locs()->
out(0).IsPairLocation());
2184 PairLocation* result_pair = locs()->out(0).AsPairLocation();
2185 const Register result_lo = result_pair->At(0).reg();
2186 const Register result_hi = result_pair->At(1).reg();
2187 __ lw(result_lo, element_address);
2188 __ lw(result_hi, compiler::Address(element_address.base(),
2189 element_address.offset() + 4));
2200 if (rep == kUnboxedFloat) {
2203 }
else if (rep == kUnboxedDouble) {
2207 ASSERT(rep == kUnboxedInt32x4 || rep == kUnboxedFloat32x4 ||
2208 rep == kUnboxedFloat64x2);
2213 ASSERT((class_id() == kArrayCid) || (class_id() == kImmutableArrayCid) ||
2214 (class_id() == kTypeArgumentsCid) || (class_id() == kRecordCid));
2220LocationSummary* LoadCodeUnitsInstr::MakeLocationSummary(Zone* zone,
2222 const intptr_t kNumInputs = 2;
2223 const intptr_t kNumTemps = 0;
2224 LocationSummary* summary =
new (zone)
2229 if (representation() == kUnboxedInt64) {
2233 ASSERT(representation() == kTagged);
2242void LoadCodeUnitsInstr::EmitNativeCode(FlowGraphCompiler*
compiler) {
2244 const Register str = locs()->in(0).reg();
2245 const Location index = locs()->in(1);
2249 if (representation() == kUnboxedInt64) {
2251 ASSERT(locs()->
out(0).IsPairLocation());
2257 switch (class_id()) {
2258 case kOneByteStringCid:
2259 switch (element_count()) {
2273 case kTwoByteStringCid:
2274 switch (element_count()) {
2290 compiler::Address element_address =
__ ElementAddressForRegIndex(
2291 IsExternal(), class_id(), index_scale(),
false, str,
2311 ASSERT(can_pack_into_smi());
2315LocationSummary* StoreIndexedInstr::MakeLocationSummary(Zone* zone,
2322 const intptr_t kNumInputs = 3;
2323 const intptr_t kNumTemps = 1;
2324 LocationSummary* locs =
new (zone)
2327 const bool can_be_constant =
2328 index()->BindsToConstant() &&
2330 index()->BoundConstant(), IsUntagged(), class_id(), index_scale());
2331 locs->set_in(1, can_be_constant
2339 ASSERT(rep == kUnboxedUint8);
2342 if (rep == kUnboxedUint8 || rep == kUnboxedInt8) {
2344 if (constant !=
nullptr && constant->HasZeroRepresentation()) {
2349 }
else if (rep == kUnboxedInt64) {
2355 if (constant !=
nullptr && constant->HasZeroRepresentation()) {
2363 if (constant !=
nullptr && constant->HasZeroRepresentation()) {
2370 if (rep == kUnboxedFloat) {
2372 if (constant !=
nullptr && constant->HasZeroRepresentation()) {
2377 }
else if (rep == kUnboxedDouble) {
2382 if (constant !=
nullptr && constant->HasZeroRepresentation()) {
2391 }
else if (class_id() == kArrayCid) {
2392 locs->set_in(2, ShouldEmitStoreBarrier()
2395 if (ShouldEmitStoreBarrier()) {
2405void StoreIndexedInstr::EmitNativeCode(FlowGraphCompiler*
compiler) {
2407 const Register array = locs()->in(0).reg();
2408 const Location index = locs()->in(1);
2409 const Register temp = locs()->temp(0).reg();
2410 compiler::Address element_address(
TMP);
2413 if (class_id() == kArrayCid && ShouldEmitStoreBarrier()) {
2414 if (index.IsRegister()) {
2415 __ ComputeElementAddressForRegIndex(temp, IsUntagged(), class_id(),
2416 index_scale(), index_unboxed_, array,
2419 __ ComputeElementAddressForIntIndex(temp, IsUntagged(), class_id(),
2420 index_scale(), array,
2421 Smi::Cast(index.constant()).Value());
2424 __ StoreIntoArray(array, temp,
value, CanValueBeSmi());
2428 element_address = index.IsRegister()
2429 ?
__ ElementAddressForRegIndex(
2430 IsUntagged(), class_id(), index_scale(),
2431 index_unboxed_, array, index.reg(), temp)
2432 :
__ ElementAddressForIntIndex(
2433 IsUntagged(), class_id(), index_scale(), array,
2434 Smi::Cast(index.constant()).
Value());
2441 const Smi& constant = Smi::Cast(locs()->in(2).constant());
2442 intptr_t
value = constant.Value();
2446 }
else if (
value < 0) {
2450 __ sb(
ZR, element_address);
2452 __ LoadImmediate(
TMP,
static_cast<int8_t
>(
value));
2453 __ sb(
TMP, element_address);
2458 compiler::Label store_zero, store_ff,
done;
2464 __ sb(
value, element_address);
2467 __ Bind(&store_zero);
2471 __ sb(
TMP, element_address);
2476 if (rep == kUnboxedUint8 || rep == kUnboxedInt8) {
2479 __ sb(
ZR, element_address);
2482 __ sb(
value, element_address);
2484 }
else if (rep == kUnboxedInt64) {
2488 __ sd(
ZR, element_address);
2490 __ sd(locs()->in(2).reg(), element_address);
2493 PairLocation* value_pair = locs()->in(2).AsPairLocation();
2494 Register value_lo = value_pair->At(0).reg();
2495 Register value_hi = value_pair->At(1).reg();
2496 __ sw(value_lo, element_address);
2497 __ sw(value_hi, compiler::Address(element_address.base(),
2498 element_address.offset() + 4));
2505 __ Store(locs()->in(2).reg(), element_address,
2510 if (rep == kUnboxedFloat) {
2513 __ sw(
ZR, element_address);
2515 __ fsw(locs()->in(2).fpu_reg(), element_address);
2517 }
else if (rep == kUnboxedDouble) {
2521 __ sd(
ZR, element_address);
2523 __ fsd(locs()->in(2).fpu_reg(), element_address);
2526 __ fsd(locs()->in(2).fpu_reg(), element_address);
2529 ASSERT(rep == kUnboxedInt32x4 || rep == kUnboxedFloat32x4 ||
2530 rep == kUnboxedFloat64x2);
2533 }
else if (class_id() == kArrayCid) {
2535 ASSERT(!ShouldEmitStoreBarrier());
2537 const Object& constant = locs()->in(2).constant();
2538 __ StoreObjectIntoObjectNoBarrier(array, element_address, constant);
2541 __ StoreIntoObjectNoBarrier(array, element_address,
value);
2547#if defined(USING_MEMORY_SANITIZER)
2552static void LoadValueCid(FlowGraphCompiler*
compiler,
2555 compiler::Label* value_is_smi =
nullptr) {
2556 compiler::Label
done;
2557 if (value_is_smi ==
nullptr) {
2558 __ LoadImmediate(value_cid_reg, kSmiCid);
2560 __ BranchIfSmi(value_reg, value_is_smi ==
nullptr ? &
done : value_is_smi,
2562 __ LoadClassId(value_cid_reg, value_reg);
2568LocationSummary* GuardFieldClassInstr::MakeLocationSummary(Zone* zone,
2570 const intptr_t kNumInputs = 1;
2572 const intptr_t value_cid =
value()->Type()->ToCid();
2573 const intptr_t field_cid = field().guarded_cid();
2575 const bool emit_full_guard = !opt || (field_cid ==
kIllegalCid);
2577 const bool needs_value_cid_temp_reg =
2578 emit_full_guard || ((value_cid ==
kDynamicCid) && (field_cid != kSmiCid));
2580 const bool needs_field_temp_reg = emit_full_guard;
2582 intptr_t num_temps = 0;
2583 if (needs_value_cid_temp_reg) {
2586 if (needs_field_temp_reg) {
2590 LocationSummary* summary =
new (zone)
2594 for (intptr_t i = 0; i < num_temps; i++) {
2601void GuardFieldClassInstr::EmitNativeCode(FlowGraphCompiler*
compiler) {
2602 ASSERT(compiler::target::UntaggedObject::kClassIdTagSize == 20);
2603 ASSERT(
sizeof(UntaggedField::guarded_cid_) == 4);
2604 ASSERT(
sizeof(UntaggedField::is_nullable_) == 4);
2606 const intptr_t value_cid =
value()->Type()->ToCid();
2607 const intptr_t field_cid = field().guarded_cid();
2614 const bool emit_full_guard =
2617 const bool needs_value_cid_temp_reg =
2618 emit_full_guard || ((value_cid ==
kDynamicCid) && (field_cid != kSmiCid));
2620 const bool needs_field_temp_reg = emit_full_guard;
2622 const Register value_reg = locs()->in(0).reg();
2625 needs_value_cid_temp_reg ? locs()->temp(0).reg() :
kNoRegister;
2627 const Register field_reg = needs_field_temp_reg
2628 ? locs()->temp(locs()->temp_count() - 1).reg()
2631 compiler::Label
ok, fail_label;
2633 compiler::Label* deopt =
2635 ?
compiler->AddDeoptStub(deopt_id(), ICData::kDeoptGuardField)
2638 compiler::Label*
fail = (deopt !=
nullptr) ? deopt : &fail_label;
2640 if (emit_full_guard) {
2643 compiler::FieldAddress field_cid_operand(field_reg,
2645 compiler::FieldAddress field_nullability_operand(
2649 LoadValueCid(
compiler, value_cid_reg, value_reg);
2650 compiler::Label skip_length_check;
2651 __ lw(
TMP, field_cid_operand);
2652 __ CompareRegisters(value_cid_reg,
TMP);
2654 __ lw(
TMP, field_nullability_operand);
2655 __ CompareRegisters(value_cid_reg,
TMP);
2656 }
else if (value_cid ==
kNullCid) {
2657 __ lw(value_cid_reg, field_nullability_operand);
2658 __ CompareImmediate(value_cid_reg, value_cid);
2660 compiler::Label skip_length_check;
2661 __ lw(value_cid_reg, field_cid_operand);
2662 __ CompareImmediate(value_cid_reg, value_cid);
2672 if (!field().needs_length_check()) {
2675 __ lw(
TMP, field_cid_operand);
2680 __ sw(value_cid_reg, field_cid_operand);
2681 __ sw(value_cid_reg, field_nullability_operand);
2683 __ LoadImmediate(
TMP, value_cid);
2684 __ sw(
TMP, field_cid_operand);
2685 __ sw(
TMP, field_nullability_operand);
2691 if (deopt ==
nullptr) {
2699 __ PushRegisterPair(value_reg, field_reg);
2701 __ CallRuntime(kUpdateFieldCidRuntimeEntry, 2);
2708 ASSERT(deopt !=
nullptr);
2715 if (field_cid != kSmiCid) {
2717 __ LoadClassId(value_cid_reg, value_reg);
2718 __ CompareImmediate(value_cid_reg, field_cid);
2721 if (field().is_nullable() && (field_cid !=
kNullCid)) {
2723 __ CompareObject(value_reg, Object::null_object());
2727 }
else if (value_cid == field_cid) {
2732 ASSERT(value_cid != nullability);
2739LocationSummary* GuardFieldLengthInstr::MakeLocationSummary(Zone* zone,
2741 const intptr_t kNumInputs = 1;
2743 const intptr_t kNumTemps = 3;
2744 LocationSummary* summary =
new (zone)
2753 LocationSummary* summary =
new (zone)
2761void GuardFieldLengthInstr::EmitNativeCode(FlowGraphCompiler*
compiler) {
2766 compiler::Label* deopt =
2768 ?
compiler->AddDeoptStub(deopt_id(), ICData::kDeoptGuardField)
2771 const Register value_reg = locs()->in(0).reg();
2775 const Register field_reg = locs()->temp(0).reg();
2776 const Register offset_reg = locs()->temp(1).reg();
2777 const Register length_reg = locs()->temp(2).reg();
2784 compiler::FieldAddress(
2796 __ add(
TMP, value_reg, offset_reg);
2797 __ lx(
TMP, compiler::Address(
TMP, 0));
2798 __ CompareObjectRegisters(length_reg,
TMP);
2800 if (deopt ==
nullptr) {
2803 __ PushRegisterPair(value_reg, field_reg);
2805 __ CallRuntime(kUpdateFieldCidRuntimeEntry, 2);
2808 __ BranchIf(
NE, deopt);
2814 ASSERT(field().guarded_list_length() >= 0);
2815 ASSERT(field().guarded_list_length_in_object_offset() !=
2818 __ lx(
TMP, compiler::FieldAddress(
2819 value_reg, field().guarded_list_length_in_object_offset()));
2821 __ BranchIf(
NE, deopt);
2825LocationSummary* StoreStaticFieldInstr::MakeLocationSummary(Zone* zone,
2827 const intptr_t kNumInputs = 1;
2828 const intptr_t kNumTemps = 0;
2829 LocationSummary* locs =
new (zone)
2835void StoreStaticFieldInstr::EmitNativeCode(FlowGraphCompiler*
compiler) {
2838 compiler->used_static_fields().Add(&field());
2841 compiler::target::Thread::field_table_values_offset());
2843 __ StoreToOffset(
value,
TMP, compiler::target::FieldTable::OffsetOf(field()));
2846LocationSummary* InstanceOfInstr::MakeLocationSummary(Zone* zone,
2848 const intptr_t kNumInputs = 3;
2849 const intptr_t kNumTemps = 0;
2850 LocationSummary* summary =
new (zone)
2862void InstanceOfInstr::EmitNativeCode(FlowGraphCompiler*
compiler) {
2873 const intptr_t kNumInputs = 2;
2874 const intptr_t kNumTemps = 0;
2875 LocationSummary* locs =
new (zone)
2877 locs->
set_in(kTypeArgumentsPos,
2879 locs->set_in(kLengthPos,
2886static void InlineArrayAllocation(FlowGraphCompiler*
compiler,
2887 intptr_t num_elements,
2888 compiler::Label* slow_path,
2889 compiler::Label*
done) {
2890 const int kInlineArraySize = 12;
2893 __ TryAllocateArray(kArrayCid, instance_size, slow_path,
2901 __ StoreCompressedIntoObjectNoBarrier(
2908 __ StoreCompressedIntoObjectNoBarrier(
2919 if (num_elements > 0) {
2920 const intptr_t array_size = instance_size -
sizeof(UntaggedArray);
2924 intptr_t current_offset = 0;
2925 while (current_offset < array_size) {
2926 __ StoreCompressedIntoObjectNoBarrier(
2932 compiler::Label end_loop, init_loop;
2933 __ Bind(&init_loop);
2934 __ CompareRegisters(
T5,
T3);
2947 TypeUsageInfo* type_usage_info =
compiler->thread()->type_usage_info();
2948 if (type_usage_info !=
nullptr) {
2949 const Class& list_class =
2952 type_arguments()->definition());
2955 compiler::Label slow_path,
done;
2956 if (!FLAG_use_slow_path && FLAG_inline_alloc) {
2957 if (
compiler->is_optimizing() && !FLAG_precompiled_mode &&
2958 num_elements()->BindsToConstant() &&
2959 num_elements()->BoundConstant().
IsSmi()) {
2961 Smi::Cast(num_elements()->BoundConstant()).Value();
2968 __ Bind(&slow_path);
2969 auto object_store =
compiler->isolate_group()->object_store();
2970 const auto& allocate_array_stub =
2973 UntaggedPcDescriptors::kOther, locs(), deopt_id(),
2982 const intptr_t kNumInputs = 0;
2983 const intptr_t kNumTemps = 3;
2984 LocationSummary* locs =
new (zone) LocationSummary(
2993class AllocateContextSlowPath
2994 :
public TemplateSlowPathCode<AllocateUninitializedContextInstr> {
2996 explicit AllocateContextSlowPath(
2997 AllocateUninitializedContextInstr* instruction)
2998 : TemplateSlowPathCode(instruction) {}
3000 virtual void EmitNativeCode(FlowGraphCompiler*
compiler) {
3001 __ Comment(
"AllocateContextSlowPath");
3002 __ Bind(entry_label());
3004 LocationSummary* locs = instruction()->locs();
3005 locs->live_registers()->Remove(locs->out(0));
3009 auto slow_path_env =
compiler->SlowPathEnvironmentFor(
3011 ASSERT(slow_path_env !=
nullptr);
3013 auto object_store =
compiler->isolate_group()->object_store();
3014 const auto& allocate_context_stub = Code::ZoneHandle(
3015 compiler->zone(), object_store->allocate_context_stub());
3017 __ LoadImmediate(T1, instruction()->num_context_variables());
3018 compiler->GenerateStubCall(instruction()->
source(), allocate_context_stub,
3019 UntaggedPcDescriptors::kOther, locs,
3020 instruction()->deopt_id(), slow_path_env);
3021 ASSERT(instruction()->locs()->
out(0).reg() == A0);
3022 compiler->RestoreLiveRegisters(instruction()->locs());
3029 Register temp0 = locs()->temp(0).reg();
3030 Register temp1 = locs()->temp(1).reg();
3031 Register temp2 = locs()->temp(2).reg();
3034 AllocateContextSlowPath* slow_path =
new AllocateContextSlowPath(
this);
3035 compiler->AddSlowPathCode(slow_path);
3038 if (!FLAG_use_slow_path && FLAG_inline_alloc) {
3039 __ TryAllocateArray(kContextCid, instance_size, slow_path->entry_label(),
3041 temp0, temp1, temp2);
3044 __ LoadImmediate(temp0, num_context_variables());
3048 __ Jump(slow_path->entry_label());
3051 __ Bind(slow_path->exit_label());
3056 const intptr_t kNumInputs = 0;
3057 const intptr_t kNumTemps = 1;
3058 LocationSummary* locs =
new (zone)
3066 ASSERT(locs()->temp(0).reg() ==
T1);
3069 auto object_store =
compiler->isolate_group()->object_store();
3070 const auto& allocate_context_stub =
3072 __ LoadImmediate(
T1, num_context_variables());
3074 UntaggedPcDescriptors::kOther, locs(), deopt_id(),
3078LocationSummary* CloneContextInstr::MakeLocationSummary(Zone* zone,
3080 const intptr_t kNumInputs = 1;
3081 const intptr_t kNumTemps = 0;
3082 LocationSummary* locs =
new (zone)
3089void CloneContextInstr::EmitNativeCode(FlowGraphCompiler*
compiler) {
3093 auto object_store =
compiler->isolate_group()->object_store();
3094 const auto& clone_context_stub =
3097 UntaggedPcDescriptors::kOther, locs(),
3101LocationSummary* CatchBlockEntryInstr::MakeLocationSummary(Zone* zone,
3106void CatchBlockEntryInstr::EmitNativeCode(FlowGraphCompiler*
compiler) {
3108 compiler->AddExceptionHandler(
this);
3109 if (HasParallelMove()) {
3110 parallel_move()->EmitNativeCode(
compiler);
3115 const intptr_t fp_sp_dist =
3116 (compiler::target::frame_layout.first_local_from_fp + 1 -
3120 __ AddImmediate(
SP,
FP, fp_sp_dist);
3123 if (raw_exception_var_ !=
nullptr) {
3126 compiler::target::FrameOffsetInBytesForVariable(raw_exception_var_));
3128 if (raw_stacktrace_var_ !=
nullptr) {
3131 compiler::target::FrameOffsetInBytesForVariable(raw_stacktrace_var_));
3136LocationSummary* CheckStackOverflowInstr::MakeLocationSummary(Zone* zone,
3138 const intptr_t kNumInputs = 0;
3139 const intptr_t kNumTemps = 1;
3140 const bool using_shared_stub = UseSharedSlowPathStub(opt);
3141 LocationSummary* summary =
new (zone)
3142 LocationSummary(zone, kNumInputs, kNumTemps,
3144 : LocationSummary::kCallOnSlowPath);
3149class CheckStackOverflowSlowPath
3150 :
public TemplateSlowPathCode<CheckStackOverflowInstr> {
3152 static constexpr intptr_t kNumSlowPathArgs = 0;
3154 explicit CheckStackOverflowSlowPath(CheckStackOverflowInstr* instruction)
3155 : TemplateSlowPathCode(instruction) {}
3157 virtual void EmitNativeCode(FlowGraphCompiler*
compiler) {
3158 auto locs = instruction()->locs();
3159 if (
compiler->isolate_group()->use_osr() && osr_entry_label()->IsLinked()) {
3161 __ Comment(
"CheckStackOverflowSlowPathOsr");
3162 __ Bind(osr_entry_label());
3163 __ li(value, Thread::kOsrRequest);
3165 compiler::Address(THR, Thread::stack_overflow_flags_offset()));
3167 __ Comment(
"CheckStackOverflowSlowPath");
3168 __ Bind(entry_label());
3169 const bool using_shared_stub = locs->call_on_shared_slow_path();
3170 if (!using_shared_stub) {
3177 compiler->SlowPathEnvironmentFor(instruction(), kNumSlowPathArgs);
3180 const bool has_frame =
compiler->flow_graph().graph_entry()->NeedsFrame();
3181 if (using_shared_stub) {
3183 ASSERT(
__ constant_pool_allowed());
3184 __ set_constant_pool_allowed(
false);
3185 __ EnterDartFrame(0);
3187 auto object_store =
compiler->isolate_group()->object_store();
3188 const bool live_fpu_regs = locs->live_registers()->FpuRegisterCount() > 0;
3189 const auto& stub = Code::ZoneHandle(
3192 ? object_store->stack_overflow_stub_with_fpu_regs_stub()
3193 : object_store->stack_overflow_stub_without_fpu_regs_stub());
3195 if (
compiler->CanPcRelativeCall(stub)) {
3196 __ GenerateUnRelocatedPcRelativeCall();
3197 compiler->AddPcRelativeCallStubTarget(stub);
3199 const uword entry_point_offset =
3200 Thread::stack_overflow_shared_stub_entry_point_offset(
3201 locs->live_registers()->FpuRegisterCount() > 0);
3202 __ Call(compiler::Address(THR, entry_point_offset));
3204 compiler->RecordSafepoint(locs, kNumSlowPathArgs);
3206 compiler->AddCurrentDescriptor(UntaggedPcDescriptors::kOther,
3207 instruction()->deopt_id(),
3208 instruction()->
source());
3210 __ LeaveDartFrame();
3211 __ set_constant_pool_allowed(
true);
3215 __ CallRuntime(kInterruptOrStackOverflowRuntimeEntry, kNumSlowPathArgs);
3217 instruction()->
source(), instruction()->deopt_id(),
3218 UntaggedPcDescriptors::kOther, instruction()->locs(),
env);
3222 instruction()->in_loop()) {
3224 compiler->AddCurrentDescriptor(UntaggedPcDescriptors::kOsrEntry,
3225 instruction()->deopt_id(),
3226 InstructionSource());
3228 compiler->pending_deoptimization_env_ =
nullptr;
3229 if (!using_shared_stub) {
3230 compiler->RestoreLiveRegisters(locs);
3235 compiler::Label* osr_entry_label() {
3236 ASSERT(IsolateGroup::Current()->use_osr());
3237 return &osr_entry_label_;
3241 compiler::Label osr_entry_label_;
3244void CheckStackOverflowInstr::EmitNativeCode(FlowGraphCompiler*
compiler) {
3245 CheckStackOverflowSlowPath* slow_path =
new CheckStackOverflowSlowPath(
this);
3246 compiler->AddSlowPathCode(slow_path);
3249 compiler::Address(
THR, compiler::target::Thread::stack_limit_offset()));
3250 __ bleu(
SP,
TMP, slow_path->entry_label());
3251 if (
compiler->CanOSRFunction() && in_loop()) {
3257 const intptr_t configured_optimization_counter_threshold =
3258 compiler->thread()->isolate_group()->optimization_counter_threshold();
3259 const int32_t threshold =
3260 configured_optimization_counter_threshold * (loop_depth() + 1);
3261 __ LoadFieldFromOffset(
TMP,
function, Function::usage_counter_offset(),
3264 __ StoreFieldToOffset(
TMP,
function, Function::usage_counter_offset(),
3266 __ CompareImmediate(
TMP, threshold);
3267 __ BranchIf(
GE, slow_path->osr_entry_label());
3269 if (
compiler->ForceSlowPathForStackOverflow()) {
3270 __ j(slow_path->entry_label());
3272 __ Bind(slow_path->exit_label());
3275static void EmitSmiShiftLeft(FlowGraphCompiler*
compiler,
3276 BinarySmiOpInstr* shift_left) {
3277 const LocationSummary& locs = *shift_left->locs();
3280 compiler::Label* deopt =
3281 shift_left->CanDeoptimize()
3282 ?
compiler->AddDeoptStub(shift_left->deopt_id(),
3283 ICData::kDeoptBinarySmiOp)
3285 if (locs.in(1).IsConstant()) {
3286 const Object& constant = locs.in(1).constant();
3287 ASSERT(constant.IsSmi());
3289 const intptr_t kCountLimit = XLEN - 1;
3290 const intptr_t
value = Smi::Cast(constant).Value();
3293 if (shift_left->can_overflow()) {
3303 Range* right_range = shift_left->right_range();
3304 if (shift_left->left()->BindsToConstant() && shift_left->can_overflow()) {
3307 const Object& obj = shift_left->left()->BoundConstant();
3309 const intptr_t left_int = Smi::Cast(obj).Value();
3310 if (left_int == 0) {
3315 const intptr_t max_right =
3317 const bool right_needs_check =
3319 if (right_needs_check) {
3321 __ BranchIf(
CS, deopt);
3329 const bool right_needs_check =
3331 if (!shift_left->can_overflow()) {
3332 if (right_needs_check) {
3334 ASSERT(shift_left->CanDeoptimize());
3338 compiler::Label
done, is_not_zero;
3343 __ Bind(&is_not_zero);
3352 if (right_needs_check) {
3353 ASSERT(shift_left->CanDeoptimize());
3355 __ BranchIf(
CS, deopt);
3365LocationSummary* BinarySmiOpInstr::MakeLocationSummary(Zone* zone,
3367 const intptr_t kNumInputs = 2;
3368 const intptr_t kNumTemps =
3369 ((op_kind() == Token::kUSHR) || (op_kind() == Token::kMUL)) ? 1 : 0;
3370 LocationSummary* summary =
new (zone)
3372 if (op_kind() == Token::kTRUNCDIV) {
3374 if (RightIsPowerOfTwoConstant()) {
3383 if (op_kind() == Token::kMOD) {
3391 if (kNumTemps == 1) {
3400void BinarySmiOpInstr::EmitNativeCode(FlowGraphCompiler*
compiler) {
3401 if (op_kind() == Token::kSHL) {
3408 compiler::Label* deopt =
nullptr;
3409 if (CanDeoptimize()) {
3410 deopt =
compiler->AddDeoptStub(deopt_id(), ICData::kDeoptBinarySmiOp);
3414 const Object& constant = locs()->in(1).constant();
3415 ASSERT(constant.IsSmi());
3416 const intx_t imm =
static_cast<intx_t
>(constant.ptr());
3417 switch (op_kind()) {
3419 if (deopt ==
nullptr) {
3422 __ AddImmediateBranchOverflow(
result,
left, imm, deopt);
3427 if (deopt ==
nullptr) {
3432 __ SubtractImmediateBranchOverflow(
result,
left, imm, deopt);
3438 const intptr_t
value = Smi::Cast(constant).Value();
3439 if (deopt ==
nullptr) {
3447 case Token::kTRUNCDIV: {
3448 const intptr_t
value = Smi::Cast(constant).Value();
3451 const intptr_t shift_count =
3457 __ srli(
TMP,
TMP, XLEN - shift_count);
3460 __ srai(
result, temp, shift_count);
3467 case Token::kBIT_AND:
3471 case Token::kBIT_OR:
3475 case Token::kBIT_XOR:
3481 const intptr_t kCountLimit = XLEN - 1;
3482 intptr_t
value = Smi::Cast(constant).Value();
3487 case Token::kUSHR: {
3507 if (
value < (64 - compiler::target::kSmiBits)) {
3508 if (deopt !=
nullptr) {
3517 if (
value >= compiler::target::kSmiBits) {
3535 const intptr_t kCountLimit = XLEN - 1;
3536 intptr_t
value = Smi::Cast(constant).Value();
3541 if (deopt !=
nullptr) {
3556 switch (op_kind()) {
3558 if (deopt ==
nullptr) {
3574 if (deopt ==
nullptr) {
3590 const Register temp = locs()->temp(0).reg();
3592 if (deopt ==
nullptr) {
3599 case Token::kBIT_AND: {
3604 case Token::kBIT_OR: {
3609 case Token::kBIT_XOR: {
3614 case Token::kTRUNCDIV: {
3650 compiler::Label
done, adjust;
3663 if (CanDeoptimize()) {
3668 const intptr_t kCountLimit = XLEN - 1;
3670 __ LoadImmediate(
TMP2, kCountLimit);
3671 compiler::Label shift_in_bounds;
3674 __ Bind(&shift_in_bounds);
3681 case Token::kUSHR: {
3683 compiler::Label
done;
3701 right_range(), 64 - compiler::target::kSmiBits - 1)) {
3711 __ CompareImmediate(
TMP, 64 - compiler::target::kSmiBits);
3716 compiler::Label
next;
3728 if (deopt !=
nullptr) {
3737 compiler::target::kSmiBits - 1)) {
3741 __ CompareImmediate(
TMP, compiler::target::kSmiBits);
3746 const Register temp = locs()->temp(0).reg();
3752 if (CanDeoptimize()) {
3757 const intptr_t kCountLimit = XLEN - 1;
3759 compiler::Label
done;
3761 __ LoadImmediate(
TMP2, kCountLimit);
3762 compiler::Label shift_in_bounds;
3766 __ Bind(&shift_in_bounds);
3771 if (deopt !=
nullptr) {
3800LocationSummary* CheckEitherNonSmiInstr::MakeLocationSummary(Zone* zone,
3802 intptr_t left_cid =
left()->Type()->ToCid();
3803 intptr_t right_cid =
right()->Type()->ToCid();
3804 ASSERT((left_cid != kDoubleCid) && (right_cid != kDoubleCid));
3805 const intptr_t kNumInputs = 2;
3806 const intptr_t kNumTemps = 0;
3807 LocationSummary* summary =
new (zone)
3814void CheckEitherNonSmiInstr::EmitNativeCode(FlowGraphCompiler*
compiler) {
3815 compiler::Label* deopt =
3816 compiler->AddDeoptStub(deopt_id(), ICData::kDeoptBinaryDoubleOp);
3817 intptr_t left_cid =
left()->Type()->ToCid();
3818 intptr_t right_cid =
right()->Type()->ToCid();
3821 if (this->
left()->definition() == this->
right()->definition()) {
3822 __ BranchIfSmi(
left, deopt);
3823 }
else if (left_cid == kSmiCid) {
3825 }
else if (right_cid == kSmiCid) {
3826 __ BranchIfSmi(
left, deopt);
3829 __ BranchIfSmi(
TMP, deopt);
3833LocationSummary* BoxInstr::MakeLocationSummary(Zone* zone,
bool opt)
const {
3834 const intptr_t kNumInputs = 1;
3835 const intptr_t kNumTemps = 0;
3836 LocationSummary* summary =
new (zone) LocationSummary(
3843void BoxInstr::EmitNativeCode(FlowGraphCompiler*
compiler) {
3844 const Register out_reg = locs()->out(0).reg();
3848 compiler->BoxClassFor(from_representation()),
3851 switch (from_representation()) {
3852 case kUnboxedDouble:
3853 __ StoreDFieldToOffset(
value, out_reg, ValueOffset());
3857 __ StoreDFieldToOffset(
FpuTMP, out_reg, ValueOffset());
3859 case kUnboxedFloat32x4:
3860 case kUnboxedFloat64x2:
3861 case kUnboxedInt32x4:
3870LocationSummary* UnboxInstr::MakeLocationSummary(Zone* zone,
bool opt)
const {
3872 const intptr_t kNumInputs = 1;
3873 const intptr_t kNumTemps = 1;
3874 const bool is_floating_point =
3876 LocationSummary* summary =
new (zone)
3881 if (is_floating_point) {
3884 }
else if (representation() == kUnboxedInt64) {
3894void UnboxInstr::EmitLoadFromBox(FlowGraphCompiler*
compiler) {
3895 const Register box = locs()->in(0).reg();
3897 switch (representation()) {
3898 case kUnboxedInt64: {
3900 PairLocation*
result = locs()->out(0).AsPairLocation();
3902 __ LoadFieldFromOffset(
result->At(0).reg(), box, ValueOffset());
3903 __ LoadFieldFromOffset(
result->At(1).reg(), box,
3904 ValueOffset() + compiler::target::kWordSize);
3907 __ ld(
result, compiler::FieldAddress(box, ValueOffset()));
3912 case kUnboxedDouble: {
3914 __ LoadDFieldFromOffset(
result, box, ValueOffset());
3918 case kUnboxedFloat: {
3920 __ LoadDFieldFromOffset(
result, box, ValueOffset());
3925 case kUnboxedFloat32x4:
3926 case kUnboxedFloat64x2:
3927 case kUnboxedInt32x4: {
3938void UnboxInstr::EmitSmiConversion(FlowGraphCompiler*
compiler) {
3939 const Register box = locs()->in(0).reg();
3941 switch (representation()) {
3943 case kUnboxedInt64: {
3944 PairLocation*
result = locs()->out(0).AsPairLocation();
3945 __ SmiUntag(
result->At(0).reg(), box);
3946 __ srai(
result->At(1).reg(), box, XLEN - 1);
3951 case kUnboxedInt64: {
3958 case kUnboxedFloat: {
3960 __ SmiUntag(
TMP, box);
3968 case kUnboxedDouble: {
3970 __ SmiUntag(
TMP, box);
3985void UnboxInstr::EmitLoadInt32FromBoxOrSmi(FlowGraphCompiler*
compiler) {
3991void UnboxInstr::EmitLoadInt64FromBoxOrSmi(FlowGraphCompiler*
compiler) {
3993 const Register box = locs()->in(0).reg();
3994 PairLocation*
result = locs()->out(0).AsPairLocation();
3997 compiler::Label
done;
3998 __ srai(
result->At(1).reg(), box, XLEN - 1);
3999 __ SmiUntag(
result->At(0).reg(), box);
4010LocationSummary* BoxInteger32Instr::MakeLocationSummary(Zone* zone,
4012 ASSERT((from_representation() == kUnboxedInt32) ||
4013 (from_representation() == kUnboxedUint32));
4014 const intptr_t kNumInputs = 1;
4015 const intptr_t kNumTemps = 0;
4019 const bool kMayAllocateMint =
false;
4021 const bool kMayAllocateMint = !ValueFitsSmi();
4023 LocationSummary* summary =
new (zone)
4024 LocationSummary(zone, kNumInputs, kNumTemps,
4026 : LocationSummary::kNoCall);
4032void BoxInteger32Instr::EmitNativeCode(FlowGraphCompiler*
compiler) {
4038 ASSERT(compiler::target::kSmiBits >= 32);
4039 __ slli(out,
value, XLEN - 32);
4040 if (from_representation() == kUnboxedInt32) {
4043 ASSERT(from_representation() == kUnboxedUint32);
4048 if (ValueFitsSmi()) {
4051 compiler::Label
done;
4052 if (from_representation() == kUnboxedInt32) {
4053 __ srai(
TMP, out, 1);
4056 ASSERT(from_representation() == kUnboxedUint32);
4063 __ StoreFieldToOffset(
value, out, compiler::target::Mint::value_offset());
4064 if (from_representation() == kUnboxedInt32) {
4066 __ StoreFieldToOffset(
4068 compiler::target::Mint::value_offset() + compiler::target::kWordSize);
4070 ASSERT(from_representation() == kUnboxedUint32);
4071 __ StoreFieldToOffset(
4073 compiler::target::Mint::value_offset() + compiler::target::kWordSize);
4079LocationSummary* BoxInt64Instr::MakeLocationSummary(Zone* zone,
4085 const bool stubs_in_vm_isolate =
4086 object_store->allocate_mint_with_fpu_regs_stub()
4088 ->InVMIsolateHeap() ||
4089 object_store->allocate_mint_without_fpu_regs_stub()
4091 ->InVMIsolateHeap();
4092 const bool shared_slow_path_call =
4093 SlowPathSharingSupported(opt) && !stubs_in_vm_isolate;
4094 const intptr_t kNumInputs = 1;
4095 const intptr_t kNumTemps = ValueFitsSmi() ? 0 : 1;
4096 LocationSummary* summary =
new (zone) LocationSummary(
4097 zone, kNumInputs, kNumTemps,
4108 if (ValueFitsSmi()) {
4110 }
else if (shared_slow_path_call) {
4121void BoxInt64Instr::EmitNativeCode(FlowGraphCompiler*
compiler) {
4123 if (ValueFitsSmi()) {
4124 PairLocation* value_pair = locs()->in(0).AsPairLocation();
4125 Register value_lo = value_pair->At(0).reg();
4126 Register out_reg = locs()->out(0).reg();
4127 __ SmiTag(out_reg, value_lo);
4131 PairLocation* value_pair = locs()->in(0).AsPairLocation();
4132 Register value_lo = value_pair->At(0).reg();
4133 Register value_hi = value_pair->At(1).reg();
4134 Register out_reg = locs()->out(0).reg();
4136 compiler::Label overflow,
done;
4137 __ SmiTag(out_reg, value_lo);
4140 __ srai(
TMP, out_reg, XLEN - 1);
4146 compiler->intrinsic_slow_path_label(),
4148 }
else if (locs()->call_on_shared_slow_path()) {
4149 const bool has_frame =
compiler->flow_graph().graph_entry()->NeedsFrame();
4151 ASSERT(
__ constant_pool_allowed());
4152 __ set_constant_pool_allowed(
false);
4153 __ EnterDartFrame(0);
4155 auto object_store =
compiler->isolate_group()->object_store();
4156 const bool live_fpu_regs = locs()->live_registers()->FpuRegisterCount() > 0;
4159 live_fpu_regs ? object_store->allocate_mint_with_fpu_regs_stub()
4160 : object_store->allocate_mint_without_fpu_regs_stub());
4162 ASSERT(!locs()->live_registers()->ContainsRegister(
4164 auto extended_env =
compiler->SlowPathEnvironmentFor(
this, 0);
4165 compiler->GenerateStubCall(
source(), stub, UntaggedPcDescriptors::kOther,
4168 __ LeaveDartFrame();
4169 __ set_constant_pool_allowed(
true);
4176 __ StoreFieldToOffset(value_lo, out_reg,
4177 compiler::target::Mint::value_offset());
4178 __ StoreFieldToOffset(
4180 compiler::target::Mint::value_offset() + compiler::target::kWordSize);
4185 if (ValueFitsSmi()) {
4190 compiler::Label
done;
4194 __ SmiUntag(
TMP, out);
4199 compiler->intrinsic_slow_path_label(),
4201 }
else if (locs()->call_on_shared_slow_path()) {
4202 const bool has_frame =
compiler->flow_graph().graph_entry()->NeedsFrame();
4204 ASSERT(
__ constant_pool_allowed());
4205 __ set_constant_pool_allowed(
false);
4206 __ EnterDartFrame(0);
4208 auto object_store =
compiler->isolate_group()->object_store();
4209 const bool live_fpu_regs = locs()->live_registers()->FpuRegisterCount() > 0;
4212 live_fpu_regs ? object_store->allocate_mint_with_fpu_regs_stub()
4213 : object_store->allocate_mint_without_fpu_regs_stub());
4215 ASSERT(!locs()->live_registers()->ContainsRegister(
4217 auto extended_env =
compiler->SlowPathEnvironmentFor(
this, 0);
4218 compiler->GenerateStubCall(
source(), stub, UntaggedPcDescriptors::kOther,
4221 __ LeaveDartFrame();
4222 __ set_constant_pool_allowed(
true);
4235static void LoadInt32FromMint(FlowGraphCompiler*
compiler,
4238 compiler::Label* deopt) {
4239 __ LoadFieldFromOffset(
result, mint, compiler::target::Mint::value_offset());
4240 if (deopt !=
nullptr) {
4241 __ LoadFieldFromOffset(
4243 compiler::target::Mint::value_offset() + compiler::target::kWordSize);
4250LocationSummary* UnboxInteger32Instr::MakeLocationSummary(Zone* zone,
4252 const intptr_t kNumInputs = 1;
4253 const intptr_t kNumTemps = 0;
4254 LocationSummary* summary =
new (zone)
4261void UnboxInteger32Instr::EmitNativeCode(FlowGraphCompiler*
compiler) {
4263 const intptr_t value_cid =
value()->Type()->ToCid();
4266 compiler::Label* deopt =
4268 ?
compiler->AddDeoptStub(GetDeoptId(), ICData::kDeoptUnboxInteger)
4270 compiler::Label* out_of_range = !is_truncating() ? deopt :
nullptr;
4273 if (value_cid == kSmiCid) {
4275 }
else if (value_cid == kMintCid) {
4277 }
else if (!CanDeoptimize()) {
4278 compiler::Label
done;
4284 compiler::Label
done;
4288 __ BranchIf(
NE, deopt);
4293 const intptr_t value_cid =
value()->Type()->ToCid();
4296 compiler::Label* deopt =
4298 ?
compiler->AddDeoptStub(GetDeoptId(), ICData::kDeoptUnboxInteger)
4301 if (value_cid == kSmiCid) {
4303 }
else if (value_cid == kMintCid) {
4305 }
else if (!CanDeoptimize()) {
4310 compiler::Label
done;
4316 compiler::Label
done;
4320 __ BranchIf(
NE, deopt);
4327 if (!is_truncating() && (deopt !=
nullptr)) {
4328 ASSERT(representation() == kUnboxedInt32);
4330 __ bne(
TMP, out, deopt);
4335LocationSummary* BinaryDoubleOpInstr::MakeLocationSummary(Zone* zone,
4337 const intptr_t kNumInputs = 2;
4338 const intptr_t kNumTemps = 0;
4339 LocationSummary* summary =
new (zone)
4347void BinaryDoubleOpInstr::EmitNativeCode(FlowGraphCompiler*
compiler) {
4351 if (representation() == kUnboxedDouble) {
4352 switch (op_kind()) {
4375 ASSERT(representation() == kUnboxedFloat);
4376 switch (op_kind()) {
4401LocationSummary* DoubleTestOpInstr::MakeLocationSummary(Zone* zone,
4403 const intptr_t kNumInputs = 1;
4404 const intptr_t kNumTemps = 0;
4405 LocationSummary* summary =
new (zone)
4413 BranchLabels labels) {
4418 if (op_kind() == MethodRecognizer::kDouble_getIsNaN) {
4420 }
else if (op_kind() == MethodRecognizer::kDouble_getIsInfinite) {
4422 }
else if (op_kind() == MethodRecognizer::kDouble_getIsNegative) {
4440LocationSummary* CaseInsensitiveCompareInstr::MakeLocationSummary(
4443 const intptr_t kNumTemps = 0;
4444 LocationSummary* summary =
new (zone)
4455void CaseInsensitiveCompareInstr::EmitNativeCode(FlowGraphCompiler*
compiler) {
4461 compiler::LeafRuntimeScope rt(
compiler->assembler(),
4464 if (locs()->in(3).IsRegister()) {
4465 __ mv(
A3, locs()->in(3).reg());
4466 }
else if (locs()->in(3).IsStackSlot()) {
4474LocationSummary* MathMinMaxInstr::MakeLocationSummary(Zone* zone,
4476 if (result_cid() == kDoubleCid) {
4477 const intptr_t kNumInputs = 2;
4478 const intptr_t kNumTemps = 0;
4479 LocationSummary* summary =
new (zone)
4487 ASSERT(result_cid() == kSmiCid);
4488 const intptr_t kNumInputs = 2;
4489 const intptr_t kNumTemps = 0;
4490 LocationSummary* summary =
new (zone)
4499void MathMinMaxInstr::EmitNativeCode(FlowGraphCompiler*
compiler) {
4500 ASSERT((op_kind() == MethodRecognizer::kMathMin) ||
4501 (op_kind() == MethodRecognizer::kMathMax));
4502 const bool is_min = (op_kind() == MethodRecognizer::kMathMin);
4503 if (result_cid() == kDoubleCid) {
4516 ASSERT(result_cid() == kSmiCid);
4520 compiler::Label choose_right,
done;
4528 __ Bind(&choose_right);
4533LocationSummary* UnarySmiOpInstr::MakeLocationSummary(Zone* zone,
4535 const intptr_t kNumInputs = 1;
4536 const intptr_t kNumTemps = 0;
4537 LocationSummary* summary =
new (zone)
4546void UnarySmiOpInstr::EmitNativeCode(FlowGraphCompiler*
compiler) {
4549 switch (op_kind()) {
4550 case Token::kNEGATE: {
4551 compiler::Label* deopt =
4552 compiler->AddDeoptStub(deopt_id(), ICData::kDeoptUnaryOp);
4558 case Token::kBIT_NOT:
4567LocationSummary* UnaryDoubleOpInstr::MakeLocationSummary(Zone* zone,
4569 const intptr_t kNumInputs = 1;
4570 const intptr_t kNumTemps = 0;
4571 LocationSummary* summary =
new (zone)
4578void UnaryDoubleOpInstr::EmitNativeCode(FlowGraphCompiler*
compiler) {
4581 if (representation() == kUnboxedDouble) {
4582 switch (op_kind()) {
4586 case Token::kNEGATE:
4592 case Token::kSQUARE:
4599 ASSERT(representation() == kUnboxedFloat);
4600 switch (op_kind()) {
4604 case Token::kNEGATE:
4607 case Token::kRECIPROCAL:
4612 case Token::kRECIPROCAL_SQRT:
4621 case Token::kSQUARE:
4630LocationSummary* Int32ToDoubleInstr::MakeLocationSummary(Zone* zone,
4632 const intptr_t kNumInputs = 1;
4633 const intptr_t kNumTemps = 0;
4634 LocationSummary*
result =
new (zone)
4641void Int32ToDoubleInstr::EmitNativeCode(FlowGraphCompiler*
compiler) {
4647LocationSummary* SmiToDoubleInstr::MakeLocationSummary(Zone* zone,
4649 const intptr_t kNumInputs = 1;
4650 const intptr_t kNumTemps = 0;
4651 LocationSummary*
result =
new (zone)
4658void SmiToDoubleInstr::EmitNativeCode(FlowGraphCompiler*
compiler) {
4669LocationSummary* Int64ToDoubleInstr::MakeLocationSummary(Zone* zone,
4675 const intptr_t kNumInputs = 1;
4676 const intptr_t kNumTemps = 0;
4677 LocationSummary*
result =
new (zone)
4685void Int64ToDoubleInstr::EmitNativeCode(FlowGraphCompiler*
compiler) {
4695LocationSummary* DoubleToIntegerInstr::MakeLocationSummary(Zone* zone,
4697 const intptr_t kNumInputs = 1;
4698 const intptr_t kNumTemps = 0;
4699 LocationSummary*
result =
new (zone) LocationSummary(
4706void DoubleToIntegerInstr::EmitNativeCode(FlowGraphCompiler*
compiler) {
4708 const FRegister value_double = locs()->in(0).fpu_reg();
4710 DoubleToIntegerSlowPath* slow_path =
4711 new DoubleToIntegerSlowPath(
this, value_double);
4712 compiler->AddSlowPathCode(slow_path);
4715 switch (recognized_kind()) {
4716 case MethodRecognizer::kDoubleToInteger:
4719 case MethodRecognizer::kDoubleFloorToInt:
4722 case MethodRecognizer::kDoubleCeilToInt:
4730 __ fcvtwd(
TMP, value_double, rounding);
4732 __ fcvtld(
TMP, value_double, rounding);
4740 __ bne(
TMP,
TMP2, slow_path->entry_label());
4741 __ Bind(slow_path->exit_label());
4744LocationSummary* DoubleToSmiInstr::MakeLocationSummary(Zone* zone,
4746 const intptr_t kNumInputs = 1;
4747 const intptr_t kNumTemps = 0;
4748 LocationSummary*
result =
new (zone)
4755void DoubleToSmiInstr::EmitNativeCode(FlowGraphCompiler*
compiler) {
4756 compiler::Label* deopt =
4757 compiler->AddDeoptStub(deopt_id(), ICData::kDeoptDoubleToSmi);
4775LocationSummary* DoubleToFloatInstr::MakeLocationSummary(Zone* zone,
4777 const intptr_t kNumInputs = 1;
4778 const intptr_t kNumTemps = 0;
4779 LocationSummary*
result =
new (zone)
4786void DoubleToFloatInstr::EmitNativeCode(FlowGraphCompiler*
compiler) {
4792LocationSummary* FloatToDoubleInstr::MakeLocationSummary(Zone* zone,
4794 const intptr_t kNumInputs = 1;
4795 const intptr_t kNumTemps = 0;
4796 LocationSummary*
result =
new (zone)
4803void FloatToDoubleInstr::EmitNativeCode(FlowGraphCompiler*
compiler) {
4809LocationSummary* FloatCompareInstr::MakeLocationSummary(Zone* zone,
4811 const intptr_t kNumInputs = 2;
4812 const intptr_t kNumTemps = 0;
4813 LocationSummary*
result =
new (zone)
4821void FloatCompareInstr::EmitNativeCode(FlowGraphCompiler*
compiler) {
4822 const FRegister lhs = locs()->in(0).fpu_reg();
4823 const FRegister rhs = locs()->in(1).fpu_reg();
4826 switch (op_kind()) {
4851 const intptr_t kNumTemps = 0;
4852 LocationSummary*
result =
new (zone)
4868 compiler::LeafRuntimeScope rt(
compiler->assembler(),
4881LocationSummary* ExtractNthOutputInstr::MakeLocationSummary(Zone* zone,
4885 const intptr_t kNumInputs = 1;
4886 LocationSummary* summary =
4888 if (representation() == kUnboxedDouble) {
4899 ASSERT(representation() == kTagged);
4913void ExtractNthOutputInstr::EmitNativeCode(FlowGraphCompiler*
compiler) {
4914 ASSERT(locs()->in(0).IsPairLocation());
4915 PairLocation* pair = locs()->in(0).AsPairLocation();
4916 Location in_loc = pair->At(index());
4917 if (representation() == kUnboxedDouble) {
4922 ASSERT(representation() == kTagged);
4929LocationSummary* UnboxLaneInstr::MakeLocationSummary(Zone* zone,
4931 const intptr_t kNumInputs = 1;
4932 LocationSummary* summary =
4935 switch (representation()) {
4936 case kUnboxedDouble:
4949void UnboxLaneInstr::EmitNativeCode(FlowGraphCompiler*
compiler) {
4951 switch (representation()) {
4952 case kUnboxedDouble:
4953 __ fld(locs()->
out(0).fpu_reg(),
4954 compiler::FieldAddress(
4955 in, compiler::target::Float64x2::value_offset() +
4956 lane() *
sizeof(
double)));
4959 __ flw(locs()->
out(0).fpu_reg(),
4960 compiler::FieldAddress(
4961 in, compiler::target::Float32x4::value_offset() +
4962 lane() *
sizeof(
float)));
4966 locs()->
out(0).reg(),
4967 compiler::FieldAddress(in, compiler::target::Int32x4::value_offset() +
4968 lane() *
sizeof(int32_t)));
4975LocationSummary* BoxLanesInstr::MakeLocationSummary(Zone* zone,
4978 LocationSummary* summary =
new (zone)
4980 switch (from_representation()) {
4981 case kUnboxedDouble:
5004void BoxLanesInstr::EmitNativeCode(FlowGraphCompiler*
compiler) {
5006 switch (from_representation()) {
5007 case kUnboxedDouble:
5010 for (intptr_t i = 0; i < 2; i++) {
5011 __ fsd(locs()->in(i).fpu_reg(),
5012 compiler::FieldAddress(
5013 result, compiler::target::Float64x2::value_offset() +
5014 i *
sizeof(
double)));
5020 for (intptr_t i = 0; i < 4; i++) {
5021 __ fsw(locs()->in(i).fpu_reg(),
5022 compiler::FieldAddress(
5023 result, compiler::target::Float32x4::value_offset() +
5024 i *
sizeof(
float)));
5030 for (intptr_t i = 0; i < 4; i++) {
5031 __ sw(locs()->in(i).reg(),
5032 compiler::FieldAddress(
result,
5033 compiler::target::Int32x4::value_offset() +
5034 i *
sizeof(int32_t)));
5042LocationSummary* TruncDivModInstr::MakeLocationSummary(Zone* zone,
5044 const intptr_t kNumInputs = 2;
5045 const intptr_t kNumTemps = 0;
5046 LocationSummary* summary =
new (zone)
5056void TruncDivModInstr::EmitNativeCode(FlowGraphCompiler*
compiler) {
5058 compiler::Label* deopt =
5059 compiler->AddDeoptStub(deopt_id(), ICData::kDeoptBinarySmiOp);
5062 ASSERT(locs()->
out(0).IsPairLocation());
5063 const PairLocation* pair = locs()->out(0).AsPairLocation();
5064 const Register result_div = pair->At(0).reg();
5065 const Register result_mod = pair->At(1).reg();
5087 compiler::Label
done, adjust;
5091 __ sub(result_mod, result_mod,
TMP2);
5093 __ add(result_mod, result_mod,
TMP2);
5096 __ sub(result_mod, result_mod,
TMP2);
5099 __ add(result_mod, result_mod,
TMP2);
5106 __ mv(
TMP, result_div);
5107 __ SmiTag(result_div);
5108 __ SmiTag(result_mod);
5109 __ SmiUntag(
TMP2, result_div);
5112 __ SmiTag(result_div);
5113 __ SmiTag(result_mod);
5119static void EmitHashIntegerCodeSequence(FlowGraphCompiler*
compiler,
5130 __ LoadImmediate(
TMP, 0x2d51);
5138 __ mulhu(value_lo, value_hi,
TMP);
5148static void EmitHashIntegerCodeSequence(FlowGraphCompiler*
compiler,
5153 __ LoadImmediate(
TMP, 0x2d51);
5164LocationSummary* HashDoubleOpInstr::MakeLocationSummary(Zone* zone,
5166 const intptr_t kNumInputs = 1;
5167 const intptr_t kNumTemps = 3;
5168 LocationSummary* summary =
new (zone) LocationSummary(
5184void HashDoubleOpInstr::EmitNativeCode(FlowGraphCompiler*
compiler) {
5187 const PairLocation* out_pair = locs()->out(0).AsPairLocation();
5189 const Register result_hi = out_pair->At(1).reg();
5193 const Register temp = locs()->temp(0).reg();
5194 const Register temp1 = locs()->temp(1).reg();
5195 const FpuRegister temp_double = locs()->temp(2).fpu_reg();
5197 compiler::Label hash_double, hash_double_value, hash_integer;
5198 compiler::Label slow_path,
done;
5205 __ fcvtdw(temp_double, temp1);
5208 __ fcvtdl(temp_double, temp1);
5210 __ feqd(temp,
value, temp_double);
5211 __ CompareImmediate(temp, 1);
5212 __ BranchIf(
NE, &hash_double_value);
5215 __ srai(temp, temp1, XLEN - 1);
5216 __ Bind(&hash_integer);
5221 __ Bind(&hash_integer);
5226 __ Bind(&slow_path);
5230 compiler::target::Thread::unboxed_runtime_arg_offset());
5232 compiler::LeafRuntimeScope rt(
compiler->assembler(), 0,
5237 rt.Call(kTryDoubleAsIntegerRuntimeEntry, 1);
5241 __ LoadFromOffset(temp1,
THR,
5242 compiler::target::Thread::unboxed_runtime_arg_offset());
5243 __ LoadFromOffset(temp,
THR,
5244 compiler::target::Thread::unboxed_runtime_arg_offset() +
5245 compiler::target::kWordSize);
5248 __ srli(temp, temp1, 32);
5250 __ CompareImmediate(
TMP, 0);
5251 __ BranchIf(
NE, &hash_integer);
5255 __ Bind(&hash_double_value);
5257 compiler::target::Thread::unboxed_runtime_arg_offset());
5258 __ LoadFromOffset(temp1,
THR,
5259 compiler::target::Thread::unboxed_runtime_arg_offset());
5260 __ LoadFromOffset(temp,
THR,
5261 compiler::target::Thread::unboxed_runtime_arg_offset() +
5262 compiler::target::kWordSize);
5264 __ Bind(&hash_double_value);
5266 __ srli(temp, temp1, 32);
5270 __ Bind(&hash_double);
5276 __ xor_(result_hi, result_hi, result_hi);
5280LocationSummary* HashIntegerOpInstr::MakeLocationSummary(Zone* zone,
5282 const intptr_t kNumInputs = 1;
5284 const intptr_t kNumTemps = 1;
5285 LocationSummary* summary =
new (zone)
5289 const intptr_t kNumTemps = 0;
5290 LocationSummary* summary =
new (zone)
5298void HashIntegerOpInstr::EmitNativeCode(FlowGraphCompiler*
compiler) {
5303 Register value_hi = locs()->temp(0).reg();
5307 __ srai(value_hi,
value, XLEN - 1);
5309 __ LoadFieldFromOffset(value_hi,
value,
5326 comparison()->InitializeLocationSummary(zone, opt);
5329 return comparison()->locs();
5333 comparison()->EmitBranchCode(
compiler,
this);
5336LocationSummary* CheckClassInstr::MakeLocationSummary(Zone* zone,
5338 const intptr_t kNumInputs = 1;
5339 const bool need_mask_temp = IsBitTest();
5340 const intptr_t kNumTemps = !IsNullCheck() ? (need_mask_temp ? 2 : 1) : 0;
5341 LocationSummary* summary =
new (zone)
5344 if (!IsNullCheck()) {
5346 if (need_mask_temp) {
5354 compiler::Label* deopt) {
5355 if (IsDeoptIfNull()) {
5356 __ beq(locs()->in(0).reg(),
NULL_REG, deopt);
5357 }
else if (IsDeoptIfNotNull()) {
5358 __ bne(locs()->in(0).reg(),
NULL_REG, deopt);
5368 compiler::Label* deopt) {
5369 Register biased_cid = locs()->temp(0).reg();
5370 __ AddImmediate(biased_cid, -
min);
5371 __ CompareImmediate(biased_cid,
max -
min);
5372 __ BranchIf(
HI, deopt);
5374 Register bit_reg = locs()->temp(1).reg();
5375 __ LoadImmediate(bit_reg, 1);
5376 __ sll(bit_reg, bit_reg, biased_cid);
5377 __ TestImmediate(bit_reg, mask);
5378 __ BranchIf(
EQ, deopt);
5381int CheckClassInstr::EmitCheckCid(FlowGraphCompiler*
compiler,
5386 compiler::Label* is_ok,
5387 compiler::Label* deopt,
5388 bool use_near_jump) {
5389 Register biased_cid = locs()->temp(0).reg();
5391 if (cid_start == cid_end) {
5392 __ CompareImmediate(biased_cid, cid_start - bias);
5398 __ AddImmediate(biased_cid, bias - cid_start);
5400 __ CompareImmediate(biased_cid, cid_end - cid_start);
5405 __ BranchIf(no_match, deopt);
5412LocationSummary* CheckClassIdInstr::MakeLocationSummary(Zone* zone,
5414 const intptr_t kNumInputs = 1;
5415 const intptr_t kNumTemps = 0;
5416 LocationSummary* summary =
new (zone)
5423void CheckClassIdInstr::EmitNativeCode(FlowGraphCompiler*
compiler) {
5425 compiler::Label* deopt =
5426 compiler->AddDeoptStub(deopt_id(), ICData::kDeoptCheckClass);
5427 if (cids_.IsSingleCid()) {
5429 __ BranchIf(
NE, deopt);
5433 __ BranchIf(
HI, deopt);
5437LocationSummary* CheckSmiInstr::MakeLocationSummary(Zone* zone,
5439 const intptr_t kNumInputs = 1;
5440 const intptr_t kNumTemps = 0;
5441 LocationSummary* summary =
new (zone)
5447void CheckSmiInstr::EmitNativeCode(FlowGraphCompiler*
compiler) {
5449 compiler::Label* deopt =
5450 compiler->AddDeoptStub(deopt_id(), ICData::kDeoptCheckSmi);
5451 __ BranchIfNotSmi(
value, deopt);
5454void CheckNullInstr::EmitNativeCode(FlowGraphCompiler*
compiler) {
5455 ThrowErrorSlowPathCode* slow_path =
new NullErrorSlowPath(
this);
5456 compiler->AddSlowPathCode(slow_path);
5458 Register value_reg = locs()->in(0).reg();
5461 __ CompareObject(value_reg, Object::null_object());
5462 __ BranchIf(
EQUAL, slow_path->entry_label());
5465LocationSummary* CheckArrayBoundInstr::MakeLocationSummary(Zone* zone,
5467 const intptr_t kNumInputs = 2;
5468 const intptr_t kNumTemps = 0;
5469 LocationSummary* locs =
new (zone)
5476void CheckArrayBoundInstr::EmitNativeCode(FlowGraphCompiler*
compiler) {
5478 compiler::Label* deopt =
5479 compiler->AddDeoptStub(deopt_id(), ICData::kDeoptCheckArrayBound,
flags);
5481 Location length_loc = locs()->in(kLengthPos);
5482 Location index_loc = locs()->in(kIndexPos);
5484 const intptr_t index_cid = index()->Type()->ToCid();
5485 if (length_loc.IsConstant() && index_loc.IsConstant()) {
5487 if ((Smi::Cast(length_loc.constant()).Value() >
5488 Smi::Cast(index_loc.constant()).Value()) &&
5489 (Smi::Cast(index_loc.constant()).Value() >= 0)) {
5493 ASSERT((Smi::Cast(length_loc.constant()).Value() <=
5494 Smi::Cast(index_loc.constant()).Value()) ||
5495 (Smi::Cast(index_loc.constant()).Value() < 0));
5502 if (index_loc.IsConstant()) {
5504 const Smi& index = Smi::Cast(index_loc.constant());
5506 __ BranchIf(
LS, deopt);
5507 }
else if (length_loc.IsConstant()) {
5508 const Smi&
length = Smi::Cast(length_loc.constant());
5509 const Register index = index_loc.reg();
5510 if (index_cid != kSmiCid) {
5511 __ BranchIfNotSmi(index, deopt);
5514 __ bltz(index, deopt);
5517 __ BranchIf(
CS, deopt);
5521 const Register index = index_loc.reg();
5522 if (index_cid != kSmiCid) {
5523 __ BranchIfNotSmi(index, deopt);
5525 __ CompareObjectRegisters(index,
length);
5526 __ BranchIf(
CS, deopt);
5530LocationSummary* CheckWritableInstr::MakeLocationSummary(Zone* zone,
5532 const intptr_t kNumInputs = 1;
5533 const intptr_t kNumTemps = 0;
5534 LocationSummary* locs =
new (zone) LocationSummary(
5535 zone, kNumInputs, kNumTemps,
5542void CheckWritableInstr::EmitNativeCode(FlowGraphCompiler*
compiler) {
5543 WriteErrorSlowPath* slow_path =
new WriteErrorSlowPath(
this);
5544 compiler->AddSlowPathCode(slow_path);
5545 __ lbu(
TMP, compiler::FieldAddress(locs()->in(0).reg(),
5546 compiler::target::Object::tags_offset()));
5548 ASSERT(compiler::target::UntaggedObject::kImmutableBit < 8);
5549 __ andi(
TMP,
TMP, 1 << compiler::target::UntaggedObject::kImmutableBit);
5550 __ bnez(
TMP, slow_path->entry_label());
5553class Int64DivideSlowPath :
public ThrowErrorSlowPathCode {
5555 Int64DivideSlowPath(BinaryInt64OpInstr* instruction,
5557 Range* divisor_range,
5560 : ThrowErrorSlowPathCode(instruction,
5561 kIntegerDivisionByZeroExceptionRuntimeEntry),
5562 is_mod_(instruction->op_kind() == Token::kMOD),
5564 divisor_range_(divisor_range),
5567 adjust_sign_label_() {}
5569 void EmitNativeCode(FlowGraphCompiler*
compiler)
override {
5571 if (has_divide_by_zero()) {
5572 ThrowErrorSlowPathCode::EmitNativeCode(
compiler);
5574 __ Bind(entry_label());
5575 if (compiler::Assembler::EmittingComments()) {
5576 __ Comment(
"slow path %s operation (no throw)",
name());
5584 if (has_adjust_sign()) {
5585 __ Bind(adjust_sign_label());
5586 if (RangeUtils::Overlaps(divisor_range_, -1, 1)) {
5588 compiler::Label adjust,
done;
5589 __ bgez(divisor_, &adjust, compiler::Assembler::kNearJump);
5590 __ sub(out_, out_, divisor_);
5591 __ j(&
done, compiler::Assembler::kNearJump);
5593 __ add(out_, out_, divisor_);
5595 }
else if (divisor_range_->IsPositive()) {
5597 __ add(out_, out_, divisor_);
5600 __ sub(out_, out_, divisor_);
5606 const char*
name()
override {
return "int64 divide"; }
5608 bool has_divide_by_zero() {
return RangeUtils::CanBeZero(divisor_range_); }
5610 bool has_adjust_sign() {
return is_mod_; }
5612 bool is_needed() {
return has_divide_by_zero() || has_adjust_sign(); }
5614 compiler::Label* adjust_sign_label() {
5615 ASSERT(has_adjust_sign());
5616 return &adjust_sign_label_;
5622 Range* divisor_range_;
5625 compiler::Label adjust_sign_label_;
5629static void EmitInt64ModTruncDiv(FlowGraphCompiler*
compiler,
5630 BinaryInt64OpInstr* instruction,
5636 ASSERT(op_kind == Token::kMOD || op_kind == Token::kTRUNCDIV);
5642 Range* right_range = instruction->right()->definition()->range();
5643 Int64DivideSlowPath* slow_path =
5644 new (
Z) Int64DivideSlowPath(instruction,
right, right_range, tmp, out);
5647 if (slow_path->has_divide_by_zero()) {
5648 __ beqz(
right, slow_path->entry_label());
5655 if (op_kind == Token::kMOD) {
5659 __ bltz(out, slow_path->adjust_sign_label());
5664 if (slow_path->is_needed()) {
5665 __ Bind(slow_path->exit_label());
5666 compiler->AddSlowPathCode(slow_path);
5671LocationSummary* BinaryInt64OpInstr::MakeLocationSummary(Zone* zone,
5676 const intptr_t kNumInputs = 2;
5677 const intptr_t kNumTemps = 0;
5678 LocationSummary* summary =
new (zone)
5688 switch (op_kind()) {
5690 case Token::kTRUNCDIV: {
5691 const intptr_t kNumInputs = 2;
5692 const intptr_t kNumTemps = (op_kind() == Token::kMOD) ? 1 : 0;
5693 LocationSummary* summary =
new (zone) LocationSummary(
5698 if (kNumTemps == 1) {
5704 const intptr_t kNumInputs = 2;
5705 const intptr_t kNumTemps = 0;
5706 LocationSummary* summary =
new (zone) LocationSummary(
5717void BinaryInt64OpInstr::EmitNativeCode(FlowGraphCompiler*
compiler) {
5719 PairLocation* left_pair = locs()->in(0).AsPairLocation();
5720 Register left_lo = left_pair->At(0).reg();
5721 Register left_hi = left_pair->At(1).reg();
5722 PairLocation* right_pair = locs()->in(1).AsPairLocation();
5723 Register right_lo = right_pair->At(0).reg();
5724 Register right_hi = right_pair->At(1).reg();
5725 PairLocation* out_pair = locs()->out(0).AsPairLocation();
5726 Register out_lo = out_pair->At(0).reg();
5727 Register out_hi = out_pair->At(1).reg();
5729 ASSERT(!CanDeoptimize());
5731 switch (op_kind()) {
5732 case Token::kBIT_AND: {
5733 __ and_(out_lo, left_lo, right_lo);
5734 __ and_(out_hi, left_hi, right_hi);
5737 case Token::kBIT_OR: {
5738 __ or_(out_lo, left_lo, right_lo);
5739 __ or_(out_hi, left_hi, right_hi);
5742 case Token::kBIT_XOR: {
5743 __ xor_(out_lo, left_lo, right_lo);
5744 __ xor_(out_hi, left_hi, right_hi);
5748 __ add(out_hi, left_hi, right_hi);
5749 __ add(out_lo, left_lo, right_lo);
5750 __ sltu(
TMP, out_lo, right_lo);
5751 __ add(out_hi, out_hi,
TMP);
5755 __ sltu(
TMP, left_lo, right_lo);
5756 __ sub(out_hi, left_hi, right_hi);
5757 __ sub(out_hi, out_hi,
TMP);
5758 __ sub(out_lo, left_lo, right_lo);
5763 __ mul(out_lo, right_lo, left_hi);
5764 __ mulhu(out_hi, right_lo, left_lo);
5765 __ add(out_lo, out_lo, out_hi);
5766 __ mul(out_hi, right_hi, left_lo);
5767 __ add(out_hi, out_hi, out_lo);
5768 __ mul(out_lo, right_lo, left_lo);
5776 ASSERT(!CanDeoptimize());
5782 if (op_kind() == Token::kMOD || op_kind() == Token::kTRUNCDIV) {
5784 (op_kind() == Token::kMOD) ? locs()->temp(0).reg() :
kNoRegister;
5788 }
else if (op_kind() == Token::kMUL) {
5790 if (
right.IsConstant()) {
5802 if (
right.IsConstant()) {
5806 switch (op_kind()) {
5813 case Token::kBIT_AND:
5816 case Token::kBIT_OR:
5819 case Token::kBIT_XOR:
5826 switch (op_kind()) {
5833 case Token::kBIT_AND:
5836 case Token::kBIT_OR:
5839 case Token::kBIT_XOR:
5850static void EmitShiftInt64ByConstant(FlowGraphCompiler*
compiler,
5856 const Object&
right) {
5857 const int64_t shift = Integer::Cast(
right).AsInt64Value();
5863 __ slli(out_lo, left_hi, 32 - shift);
5864 __ srli(
TMP, left_lo, shift);
5865 __ or_(out_lo, out_lo,
TMP);
5866 __ srai(out_hi, left_hi, shift);
5869 __ mv(out_lo, left_hi);
5870 }
else if (shift < 64) {
5871 __ srai(out_lo, left_hi, shift - 32);
5873 __ srai(out_lo, left_hi, 31);
5875 __ srai(out_hi, left_hi, 31);
5879 case Token::kUSHR: {
5882 __ slli(out_lo, left_hi, 32 - shift);
5883 __ srli(
TMP, left_lo, shift);
5884 __ or_(out_lo, out_lo,
TMP);
5885 __ srli(out_hi, left_hi, shift);
5888 __ mv(out_lo, left_hi);
5890 __ srli(out_lo, left_hi, shift - 32);
5900 __ srli(out_hi, left_lo, 32 - shift);
5901 __ slli(
TMP, left_hi, shift);
5902 __ or_(out_hi, out_hi,
TMP);
5903 __ slli(out_lo, left_lo, shift);
5906 __ mv(out_hi, left_lo);
5908 __ slli(out_hi, left_lo, shift - 32);
5919static void EmitShiftInt64ByConstant(FlowGraphCompiler*
compiler,
5923 const Object&
right) {
5924 const int64_t shift = Integer::Cast(
right).AsInt64Value();
5928 __ srai(out,
left, Utils::Minimum<int64_t>(shift, XLEN - 1));
5931 case Token::kUSHR: {
5933 __ srli(out,
left, shift);
5938 __ slli(out,
left, shift);
5948static void EmitShiftInt64ByRegister(FlowGraphCompiler*
compiler,
5958 compiler::Label big_shift,
done;
5963 __ srl(out_lo, left_lo,
right);
5964 __ sra(out_hi, left_hi,
right);
5968 __ or_(out_lo, out_lo,
TMP2);
5972 __ Bind(&big_shift);
5974 __ sra(out_lo, left_hi,
TMP);
5975 __ srai(out_hi, left_hi, XLEN - 1);
5979 case Token::kUSHR: {
5980 compiler::Label big_shift,
done;
5985 __ srl(out_lo, left_lo,
right);
5986 __ srl(out_hi, left_hi,
right);
5990 __ or_(out_lo, out_lo,
TMP2);
5994 __ Bind(&big_shift);
5996 __ srl(out_lo, left_hi,
TMP);
6002 compiler::Label big_shift,
done;
6007 __ sll(out_lo, left_lo,
right);
6008 __ sll(out_hi, left_hi,
right);
6012 __ or_(out_hi, out_hi,
TMP2);
6016 __ Bind(&big_shift);
6018 __ sll(out_hi, left_lo,
TMP);
6028static void EmitShiftInt64ByRegister(FlowGraphCompiler*
compiler,
6038 case Token::kUSHR: {
6052static void EmitShiftUint32ByConstant(FlowGraphCompiler*
compiler,
6056 const Object&
right) {
6057 const int64_t shift = Integer::Cast(
right).AsInt64Value();
6066 __ srli(out,
left, shift);
6068 __ srliw(out,
left, shift);
6073 __ slli(out,
left, shift);
6075 __ slliw(out,
left, shift);
6084static void EmitShiftUint32ByRegister(FlowGraphCompiler*
compiler,
6110class ShiftInt64OpSlowPath :
public ThrowErrorSlowPathCode {
6112 explicit ShiftInt64OpSlowPath(ShiftInt64OpInstr* instruction)
6113 : ThrowErrorSlowPathCode(instruction,
6114 kArgumentErrorUnboxedInt64RuntimeEntry) {}
6116 const char*
name()
override {
return "int64 shift"; }
6118 void EmitCodeAtSlowPathEntry(FlowGraphCompiler*
compiler)
override {
6120 PairLocation* left_pair = instruction()->locs()->in(0).AsPairLocation();
6121 Register left_hi = left_pair->At(1).reg();
6122 PairLocation* right_pair = instruction()->locs()->in(1).AsPairLocation();
6123 Register right_lo = right_pair->At(0).reg();
6124 Register right_hi = right_pair->At(1).reg();
6125 PairLocation* out_pair = instruction()->locs()->out(0).AsPairLocation();
6126 Register out_lo = out_pair->At(0).reg();
6127 Register out_hi = out_pair->At(1).reg();
6129 compiler::Label throw_error;
6130 __ bltz(right_hi, &throw_error);
6132 switch (instruction()->AsShiftInt64Op()->op_kind()) {
6134 __ srai(out_hi, left_hi, compiler::target::kBitsPerWord - 1);
6135 __ mv(out_lo, out_hi);
6149 __ Bind(&throw_error);
6156 __ StoreToOffset(right_lo, THR,
6157 compiler::target::Thread::unboxed_runtime_arg_offset());
6158 __ StoreToOffset(right_hi, THR,
6159 compiler::target::Thread::unboxed_runtime_arg_offset() +
6160 compiler::target::kWordSize);
6162 const Register left = instruction()->locs()->in(0).reg();
6164 const Register out = instruction()->locs()->out(0).reg();
6167 compiler::Label throw_error;
6170 switch (instruction()->AsShiftInt64Op()->op_kind()) {
6172 __ srai(out,
left, XLEN - 1);
6183 __ Bind(&throw_error);
6192 THR, compiler::target::Thread::unboxed_runtime_arg_offset()));
6197LocationSummary* ShiftInt64OpInstr::MakeLocationSummary(Zone* zone,
6199 const intptr_t kNumInputs = 2;
6200 const intptr_t kNumTemps = 0;
6202 LocationSummary* summary =
new (zone) LocationSummary(
6207 right()->definition()->IsConstant()) {
6217 LocationSummary* summary =
new (zone) LocationSummary(
6228void ShiftInt64OpInstr::EmitNativeCode(FlowGraphCompiler*
compiler) {
6230 PairLocation* left_pair = locs()->in(0).AsPairLocation();
6231 Register left_lo = left_pair->At(0).reg();
6232 Register left_hi = left_pair->At(1).reg();
6233 PairLocation* out_pair = locs()->out(0).AsPairLocation();
6234 Register out_lo = out_pair->At(0).reg();
6235 Register out_hi = out_pair->At(1).reg();
6239 EmitShiftInt64ByConstant(
compiler, op_kind(), out_lo, out_hi, left_lo,
6240 left_hi, locs()->in(1).constant());
6243 PairLocation* right_pair = locs()->in(1).AsPairLocation();
6244 Register right_lo = right_pair->At(0).reg();
6245 Register right_hi = right_pair->At(1).reg();
6248 ShiftInt64OpSlowPath* slow_path =
nullptr;
6249 if (!IsShiftCountInRange()) {
6250 slow_path =
new (
Z) ShiftInt64OpSlowPath(
this);
6251 compiler->AddSlowPathCode(slow_path);
6252 __ CompareImmediate(right_hi, 0);
6253 __ BranchIf(
NE, slow_path->entry_label());
6254 __ CompareImmediate(right_lo, kShiftCountLimit);
6255 __ BranchIf(
HI, slow_path->entry_label());
6258 EmitShiftInt64ByRegister(
compiler, op_kind(), out_lo, out_hi, left_lo,
6261 if (slow_path !=
nullptr) {
6262 __ Bind(slow_path->exit_label());
6271 EmitShiftInt64ByConstant(
compiler, op_kind(), out,
left,
6272 locs()->in(1).constant());
6275 Register shift = locs()->in(1).reg();
6278 ShiftInt64OpSlowPath* slow_path =
nullptr;
6279 if (!IsShiftCountInRange()) {
6280 slow_path =
new (
Z) ShiftInt64OpSlowPath(
this);
6281 compiler->AddSlowPathCode(slow_path);
6282 __ CompareImmediate(shift, kShiftCountLimit);
6283 __ BranchIf(
HI, slow_path->entry_label());
6286 EmitShiftInt64ByRegister(
compiler, op_kind(), out,
left, shift);
6288 if (slow_path !=
nullptr) {
6289 __ Bind(slow_path->exit_label());
6295LocationSummary* SpeculativeShiftInt64OpInstr::MakeLocationSummary(
6298 const intptr_t kNumInputs = 2;
6299 const intptr_t kNumTemps = 0;
6300 LocationSummary* summary =
new (zone)
6316void SpeculativeShiftInt64OpInstr::EmitNativeCode(FlowGraphCompiler*
compiler) {
6318 PairLocation* left_pair = locs()->in(0).AsPairLocation();
6319 Register left_lo = left_pair->At(0).reg();
6320 Register left_hi = left_pair->At(1).reg();
6321 PairLocation* out_pair = locs()->out(0).AsPairLocation();
6322 Register out_lo = out_pair->At(0).reg();
6323 Register out_hi = out_pair->At(1).reg();
6327 EmitShiftInt64ByConstant(
compiler, op_kind(), out_lo, out_hi, left_lo,
6328 left_hi, locs()->in(1).constant());
6331 Register shift = locs()->in(1).reg();
6335 if (!IsShiftCountInRange()) {
6337 compiler::Label* deopt =
6338 compiler->AddDeoptStub(deopt_id(), ICData::kDeoptBinaryInt64Op);
6340 __ CompareImmediate(shift, kShiftCountLimit);
6341 __ BranchIf(
HI, deopt);
6344 EmitShiftInt64ByRegister(
compiler, op_kind(), out_lo, out_hi, left_lo,
6353 EmitShiftInt64ByConstant(
compiler, op_kind(), out,
left,
6354 locs()->in(1).constant());
6357 Register shift = locs()->in(1).reg();
6360 __ SmiUntag(
TMP, shift);
6364 if (!IsShiftCountInRange()) {
6366 compiler::Label* deopt =
6367 compiler->AddDeoptStub(deopt_id(), ICData::kDeoptBinaryInt64Op);
6369 __ CompareImmediate(shift, kShiftCountLimit);
6370 __ BranchIf(
HI, deopt);
6373 EmitShiftInt64ByRegister(
compiler, op_kind(), out,
left, shift);
6378class ShiftUint32OpSlowPath :
public ThrowErrorSlowPathCode {
6380 explicit ShiftUint32OpSlowPath(ShiftUint32OpInstr* instruction)
6381 : ThrowErrorSlowPathCode(instruction,
6382 kArgumentErrorUnboxedInt64RuntimeEntry) {}
6384 const char*
name()
override {
return "uint32 shift"; }
6386 void EmitCodeAtSlowPathEntry(FlowGraphCompiler*
compiler)
override {
6388 PairLocation* right_pair = instruction()->locs()->in(1).AsPairLocation();
6389 Register right_lo = right_pair->At(0).reg();
6390 Register right_hi = right_pair->At(1).reg();
6391 Register out = instruction()->locs()->out(0).reg();
6393 compiler::Label throw_error;
6394 __ bltz(right_hi, &throw_error, compiler::Assembler::kNearJump);
6398 __ Bind(&throw_error);
6404 __ StoreToOffset(right_lo, THR,
6405 compiler::target::Thread::unboxed_runtime_arg_offset());
6406 __ StoreToOffset(right_hi, THR,
6407 compiler::target::Thread::unboxed_runtime_arg_offset() +
6408 compiler::target::kWordSize);
6419 THR, compiler::target::Thread::unboxed_runtime_arg_offset()));
6424LocationSummary* ShiftUint32OpInstr::MakeLocationSummary(Zone* zone,
6426 const intptr_t kNumInputs = 2;
6427 const intptr_t kNumTemps = 0;
6428 LocationSummary* summary =
new (zone) LocationSummary(
6432 right()->definition()->IsConstant()) {
6447void ShiftUint32OpInstr::EmitNativeCode(FlowGraphCompiler*
compiler) {
6455 EmitShiftUint32ByConstant(
compiler, op_kind(), out,
left,
6456 locs()->in(1).constant());
6459 PairLocation* right_pair = locs()->in(1).AsPairLocation();
6460 Register right_lo = right_pair->At(0).reg();
6461 Register right_hi = right_pair->At(1).reg();
6464 ShiftUint32OpSlowPath* slow_path =
nullptr;
6465 if (!IsShiftCountInRange(kUint32ShiftCountLimit)) {
6466 slow_path =
new (
Z) ShiftUint32OpSlowPath(
this);
6467 compiler->AddSlowPathCode(slow_path);
6469 __ CompareImmediate(right_hi, 0);
6470 __ BranchIf(
NE, slow_path->entry_label());
6471 __ CompareImmediate(right_lo, kUint32ShiftCountLimit);
6472 __ BranchIf(
HI, slow_path->entry_label());
6475 EmitShiftUint32ByRegister(
compiler, op_kind(), out,
left, right_lo);
6477 if (slow_path !=
nullptr) {
6478 __ Bind(slow_path->exit_label());
6486 EmitShiftUint32ByConstant(
compiler, op_kind(), out,
left,
6487 locs()->in(1).constant());
6491 const bool shift_count_in_range =
6492 IsShiftCountInRange(kUint32ShiftCountLimit);
6495 if (!shift_count_in_range) {
6496 ShiftUint32OpSlowPath* slow_path =
new (
Z) ShiftUint32OpSlowPath(
this);
6497 compiler->AddSlowPathCode(slow_path);
6499 __ bltz(
right, slow_path->entry_label());
6504 if (!shift_count_in_range) {
6506 compiler::Label
done;
6507 __ CompareImmediate(
right, 31);
6516LocationSummary* SpeculativeShiftUint32OpInstr::MakeLocationSummary(
6519 const intptr_t kNumInputs = 2;
6520 const intptr_t kNumTemps = 0;
6521 LocationSummary* summary =
new (zone)
6529void SpeculativeShiftUint32OpInstr::EmitNativeCode(
6535 EmitShiftUint32ByConstant(
compiler, op_kind(), out,
left,
6536 locs()->in(1).constant());
6539 const bool shift_count_in_range =
6540 IsShiftCountInRange(kUint32ShiftCountLimit);
6546 if (!shift_count_in_range) {
6549 compiler::Label* deopt =
6550 compiler->AddDeoptStub(deopt_id(), ICData::kDeoptBinaryInt64Op);
6557 if (!shift_count_in_range) {
6559 compiler::Label
done;
6560 __ CompareImmediate(
right, 31);
6568LocationSummary* UnaryInt64OpInstr::MakeLocationSummary(Zone* zone,
6571 const intptr_t kNumInputs = 1;
6572 const intptr_t kNumTemps = 0;
6573 LocationSummary* summary =
new (zone)
6581 const intptr_t kNumInputs = 1;
6582 const intptr_t kNumTemps = 0;
6583 LocationSummary* summary =
new (zone)
6591void UnaryInt64OpInstr::EmitNativeCode(FlowGraphCompiler*
compiler) {
6593 PairLocation* left_pair = locs()->in(0).AsPairLocation();
6594 Register left_lo = left_pair->At(0).reg();
6595 Register left_hi = left_pair->At(1).reg();
6597 PairLocation* out_pair = locs()->out(0).AsPairLocation();
6598 Register out_lo = out_pair->At(0).reg();
6599 Register out_hi = out_pair->At(1).reg();
6601 switch (op_kind()) {
6602 case Token::kBIT_NOT:
6603 __ not_(out_lo, left_lo);
6604 __ not_(out_hi, left_hi);
6606 case Token::kNEGATE:
6607 __ snez(
TMP, left_lo);
6608 __ neg(out_lo, left_lo);
6609 __ neg(out_hi, left_hi);
6610 __ sub(out_hi, out_hi,
TMP);
6618 switch (op_kind()) {
6619 case Token::kBIT_NOT:
6622 case Token::kNEGATE:
6631LocationSummary* BinaryUint32OpInstr::MakeLocationSummary(Zone* zone,
6633 const intptr_t kNumInputs = 2;
6634 const intptr_t kNumTemps = 0;
6635 LocationSummary* summary =
new (zone)
6643void BinaryUint32OpInstr::EmitNativeCode(FlowGraphCompiler*
compiler) {
6647 switch (op_kind()) {
6648 case Token::kBIT_AND:
6651 case Token::kBIT_OR:
6654 case Token::kBIT_XOR:
6679LocationSummary* UnaryUint32OpInstr::MakeLocationSummary(Zone* zone,
6681 const intptr_t kNumInputs = 1;
6682 const intptr_t kNumTemps = 0;
6683 LocationSummary* summary =
new (zone)
6690void UnaryUint32OpInstr::EmitNativeCode(FlowGraphCompiler*
compiler) {
6694 ASSERT(op_kind() == Token::kBIT_NOT);
6699static void EmitInt32ShiftLeft(FlowGraphCompiler*
compiler,
6700 BinaryInt32OpInstr* shift_left) {
6701 const LocationSummary& locs = *shift_left->locs();
6704 compiler::Label* deopt =
6705 shift_left->CanDeoptimize()
6706 ?
compiler->AddDeoptStub(shift_left->deopt_id(),
6707 ICData::kDeoptBinarySmiOp)
6709 ASSERT(locs.in(1).IsConstant());
6710 const Object& constant = locs.in(1).constant();
6713 const intptr_t kCountLimit = 0x1F;
6717 if (shift_left->can_overflow()) {
6723LocationSummary* BinaryInt32OpInstr::MakeLocationSummary(Zone* zone,
6725 const intptr_t kNumInputs = 2;
6727 intptr_t num_temps = 0;
6728 if (((op_kind() == Token::kSHL) && can_overflow()) ||
6729 (op_kind() == Token::kSHR) || (op_kind() == Token::kUSHR) ||
6730 (op_kind() == Token::kMUL)) {
6733 LocationSummary* summary =
new (zone)
6737 if (num_temps == 1) {
6746void BinaryInt32OpInstr::EmitNativeCode(FlowGraphCompiler*
compiler) {
6747 if (op_kind() == Token::kSHL) {
6748 EmitInt32ShiftLeft(
compiler,
this);
6754 compiler::Label* deopt =
nullptr;
6755 if (CanDeoptimize()) {
6756 deopt =
compiler->AddDeoptStub(deopt_id(), ICData::kDeoptBinarySmiOp);
6760 const Object& constant = locs()->in(1).constant();
6763 switch (op_kind()) {
6765 if (deopt ==
nullptr) {
6773 if (deopt ==
nullptr) {
6785 if (deopt ==
nullptr) {
6792 case Token::kBIT_AND: {
6797 case Token::kBIT_OR: {
6802 case Token::kBIT_XOR: {
6809 const intptr_t kCountLimit = 0x1F;
6813 case Token::kUSHR: {
6826 switch (op_kind()) {
6828 if (deopt ==
nullptr) {
6836 if (deopt ==
nullptr) {
6844 if (deopt ==
nullptr) {
6851 case Token::kBIT_AND: {
6856 case Token::kBIT_OR: {
6861 case Token::kBIT_XOR: {
6875LocationSummary* IntConverterInstr::MakeLocationSummary(Zone* zone,
6878 const intptr_t kNumInputs = 1;
6879 const intptr_t kNumTemps = 0;
6880 LocationSummary* summary =
new (zone)
6882 if (from() == kUntagged || to() == kUntagged) {
6883 ASSERT((from() == kUntagged && to() == kUnboxedInt32) ||
6884 (from() == kUntagged && to() == kUnboxedUint32) ||
6885 (from() == kUnboxedInt32 && to() == kUntagged) ||
6886 (from() == kUnboxedUint32 && to() == kUntagged));
6887 ASSERT(!CanDeoptimize());
6890 }
else if (from() == kUnboxedInt64) {
6891 ASSERT(to() == kUnboxedUint32 || to() == kUnboxedInt32);
6895 }
else if (to() == kUnboxedInt64) {
6896 ASSERT(from() == kUnboxedUint32 || from() == kUnboxedInt32);
6901 ASSERT(to() == kUnboxedUint32 || to() == kUnboxedInt32);
6902 ASSERT(from() == kUnboxedUint32 || from() == kUnboxedInt32);
6908 const intptr_t kNumInputs = 1;
6909 const intptr_t kNumTemps = 0;
6910 LocationSummary* summary =
new (zone)
6912 if (from() == kUntagged || to() == kUntagged) {
6915 ASSERT(!CanDeoptimize());
6916 }
else if (from() == kUnboxedInt64) {
6917 ASSERT(to() == kUnboxedUint32 || to() == kUnboxedInt32);
6918 }
else if (to() == kUnboxedInt64) {
6919 ASSERT(from() == kUnboxedInt32 || from() == kUnboxedUint32);
6921 ASSERT(to() == kUnboxedUint32 || to() == kUnboxedInt32);
6922 ASSERT(from() == kUnboxedUint32 || from() == kUnboxedInt32);
6925 if (CanDeoptimize()) {
6934void IntConverterInstr::EmitNativeCode(FlowGraphCompiler*
compiler) {
6936 const bool is_nop_conversion =
6937 (from() == kUntagged && to() == kUnboxedInt32) ||
6938 (from() == kUntagged && to() == kUnboxedUint32) ||
6939 (from() == kUnboxedInt32 && to() == kUntagged) ||
6940 (from() == kUnboxedUint32 && to() == kUntagged);
6941 if (is_nop_conversion) {
6942 ASSERT(locs()->in(0).reg() == locs()->
out(0).reg());
6946 if (from() == kUnboxedInt32 && to() == kUnboxedUint32) {
6949 ASSERT(out == locs()->in(0).reg());
6950 }
else if (from() == kUnboxedUint32 && to() == kUnboxedInt32) {
6953 ASSERT(out == locs()->in(0).reg());
6954 if (CanDeoptimize()) {
6955 compiler::Label* deopt =
6956 compiler->AddDeoptStub(deopt_id(), ICData::kDeoptUnboxInteger);
6957 __ bltz(out, deopt);
6959 }
else if (from() == kUnboxedInt64) {
6960 ASSERT(to() == kUnboxedUint32 || to() == kUnboxedInt32);
6961 PairLocation* in_pair = locs()->in(0).AsPairLocation();
6962 Register in_lo = in_pair->At(0).reg();
6963 Register in_hi = in_pair->At(1).reg();
6967 if (CanDeoptimize()) {
6968 compiler::Label* deopt =
6969 compiler->AddDeoptStub(deopt_id(), ICData::kDeoptUnboxInteger);
6970 ASSERT(to() == kUnboxedInt32);
6971 __ srai(
TMP, in_lo, XLEN - 1);
6972 __ bne(in_hi,
TMP, deopt);
6974 }
else if (from() == kUnboxedUint32 || from() == kUnboxedInt32) {
6975 ASSERT(to() == kUnboxedInt64);
6977 PairLocation* out_pair = locs()->out(0).AsPairLocation();
6978 Register out_lo = out_pair->At(0).reg();
6979 Register out_hi = out_pair->At(1).reg();
6982 if (from() == kUnboxedUint32) {
6985 ASSERT(from() == kUnboxedInt32);
6986 __ srai(out_hi, in, XLEN - 1);
6994 const bool is_nop_conversion =
6997 if (is_nop_conversion) {
6998 ASSERT(locs()->in(0).reg() == locs()->
out(0).reg());
7004 compiler::Label* deopt =
7007 :
compiler->AddDeoptStub(deopt_id(), ICData::kDeoptUnboxInteger);
7008 if (from() == kUnboxedInt32 && to() == kUnboxedUint32) {
7009 if (CanDeoptimize()) {
7011 __ bltz(
TMP, deopt);
7016 }
else if (from() == kUnboxedUint32 && to() == kUnboxedInt32) {
7017 if (CanDeoptimize()) {
7019 __ bltz(
TMP, deopt);
7024 }
else if (from() == kUnboxedInt64) {
7025 if (to() == kUnboxedInt32) {
7026 if (is_truncating() || out !=
value) {
7030 ASSERT(to() == kUnboxedUint32);
7031 if (is_truncating() || out !=
value) {
7035 __ srli(out, out, 32);
7038 if (CanDeoptimize()) {
7039 ASSERT(to() == kUnboxedInt32);
7040 __ CompareRegisters(out,
value);
7041 __ BranchIf(
NE, deopt);
7043 }
else if (to() == kUnboxedInt64) {
7044 if (from() == kUnboxedUint32) {
7047 __ srli(out, out, 32);
7049 ASSERT(from() == kUnboxedInt32);
7058LocationSummary* BitCastInstr::MakeLocationSummary(Zone* zone,
bool opt)
const {
7059 LocationSummary* summary =
7060 new (zone) LocationSummary(zone,
InputCount(),
7075 case kUnboxedDouble:
7095 case kUnboxedDouble:
7104void BitCastInstr::EmitNativeCode(FlowGraphCompiler*
compiler) {
7106 case kUnboxedFloat: {
7108 case kUnboxedInt32: {
7114 case kUnboxedInt64: {
7117 const Register dst0 = locs()->out(0).AsPairLocation()->At(0).reg();
7118 const Register dst1 = locs()->out(0).AsPairLocation()->At(1).reg();
7119 __ fmvxw(dst0, src);
7132 case kUnboxedDouble: {
7133 ASSERT(to() == kUnboxedInt64);
7136 const Register dst0 = locs()->out(0).AsPairLocation()->At(0).reg();
7137 const Register dst1 = locs()->out(0).AsPairLocation()->At(1).reg();
7139 __ fsd(src, compiler::Address(
SP, 0));
7140 __ lw(dst0, compiler::Address(
SP, 0));
7141 __ lw(dst1, compiler::Address(
SP, 4));
7149 case kUnboxedInt64: {
7151 case kUnboxedDouble: {
7154 const Register src0 = locs()->in(0).AsPairLocation()->At(0).reg();
7155 const Register src1 = locs()->in(0).AsPairLocation()->At(1).reg();
7157 __ sw(src0, compiler::Address(
SP, 0));
7158 __ sw(src1, compiler::Address(
SP, 4));
7159 __ fld(dst, compiler::Address(
SP, 0));
7167 case kUnboxedFloat: {
7170 const Register src0 = locs()->in(0).AsPairLocation()->At(0).reg();
7171 __ fmvwx(dst, src0);
7183 case kUnboxedInt32: {
7184 ASSERT(to() == kUnboxedFloat);
7195LocationSummary* StopInstr::MakeLocationSummary(Zone* zone,
bool opt)
const {
7199void StopInstr::EmitNativeCode(FlowGraphCompiler*
compiler) {
7203void GraphEntryInstr::EmitNativeCode(FlowGraphCompiler*
compiler) {
7204 BlockEntryInstr* entry = normal_entry();
7205 if (entry !=
nullptr) {
7206 if (!
compiler->CanFallThroughTo(entry)) {
7207 FATAL(
"Checked function entry must have no offset");
7210 entry = osr_entry();
7211 if (!
compiler->CanFallThroughTo(entry)) {
7217LocationSummary* GotoInstr::MakeLocationSummary(Zone* zone,
bool opt)
const {
7221void GotoInstr::EmitNativeCode(FlowGraphCompiler*
compiler) {
7223 if (FLAG_reorder_basic_blocks) {
7224 compiler->EmitEdgeCounter(block()->preorder_number());
7228 compiler->AddCurrentDescriptor(UntaggedPcDescriptors::kDeopt, GetDeoptId(),
7229 InstructionSource());
7231 if (HasParallelMove()) {
7232 parallel_move()->EmitNativeCode(
compiler);
7237 if (!
compiler->CanFallThroughTo(successor())) {
7242LocationSummary* IndirectGotoInstr::MakeLocationSummary(Zone* zone,
7244 const intptr_t kNumInputs = 1;
7245 const intptr_t kNumTemps = 2;
7247 LocationSummary* summary =
new (zone)
7257void IndirectGotoInstr::EmitNativeCode(FlowGraphCompiler*
compiler) {
7258 Register index_reg = locs()->in(0).reg();
7259 Register target_address_reg = locs()->temp(0).reg();
7260 Register offset_reg = locs()->temp(1).reg();
7262 ASSERT(RequiredInputRepresentation(0) == kTagged);
7263 __ LoadObject(offset_reg, offsets_);
7264 const auto element_address =
__ ElementAddressForRegIndex(
7265 false, kTypedDataInt32ArrayCid,
7267 false, offset_reg, index_reg,
TMP);
7268 __ lw(offset_reg, element_address);
7270 const intptr_t entry_offset =
__ CodeSize();
7271 intx_t imm = -entry_offset;
7272 intx_t lo =
ImmLo(imm);
7273 intx_t hi =
ImmHi(imm);
7274 __ auipc(target_address_reg, hi);
7275 __ add(target_address_reg, target_address_reg, offset_reg);
7276 __ jr(target_address_reg, lo);
7279LocationSummary* StrictCompareInstr::MakeLocationSummary(Zone* zone,
7281 const intptr_t kNumInputs = 2;
7282 const intptr_t kNumTemps = 0;
7283 if (needs_number_check()) {
7284 LocationSummary* locs =
new (zone)
7291 LocationSummary* locs =
new (zone)
7296 locs->set_in(1, locs->in(0).IsConstant()
7303Condition StrictCompareInstr::EmitComparisonCodeRegConstant(
7305 BranchLabels labels,
7307 const Object& obj) {
7308 return compiler->EmitEqualityRegConstCompare(reg, obj, needs_number_check(),
7313 compiler::Label is_true, is_false;
7314 BranchLabels labels = {&is_true, &is_false, &is_false};
7318 if (is_true.IsLinked() || is_false.IsLinked()) {
7320 EmitBranchOnCondition(
compiler, true_condition, labels);
7322 compiler::Label
done;
7346 BranchLabels labels =
compiler->CreateBranchLabels(branch);
7349 EmitBranchOnCondition(
compiler, true_condition, labels);
7353LocationSummary* BooleanNegateInstr::MakeLocationSummary(Zone* zone,
7359void BooleanNegateInstr::EmitNativeCode(FlowGraphCompiler*
compiler) {
7360 const Register input = locs()->in(0).reg();
7365LocationSummary* BoolToIntInstr::MakeLocationSummary(Zone* zone,
7371void BoolToIntInstr::EmitNativeCode(FlowGraphCompiler*
compiler) {
7372 const Register input = locs()->in(0).reg();
7380LocationSummary* IntToBoolInstr::MakeLocationSummary(Zone* zone,
7386void IntToBoolInstr::EmitNativeCode(FlowGraphCompiler*
compiler) {
7387 const Register input = locs()->in(0).reg();
7397 const intptr_t kNumInputs = (type_arguments() !=
nullptr) ? 1 : 0;
7398 const intptr_t kNumTemps = 0;
7399 LocationSummary* locs =
new (zone)
7401 if (type_arguments() !=
nullptr) {
7410 if (type_arguments() !=
nullptr) {
7411 TypeUsageInfo* type_usage_info =
compiler->thread()->type_usage_info();
7412 if (type_usage_info !=
nullptr) {
7414 type_arguments()->definition());
7419 compiler->GenerateStubCall(
source(), stub, UntaggedPcDescriptors::kOther,
7420 locs(), deopt_id(),
env());
7423void DebugStepCheckInstr::EmitNativeCode(FlowGraphCompiler*
compiler) {
7428 __ JumpAndLinkPatchable(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 float next(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)
static intptr_t type_arguments_offset()
static intptr_t InstanceSize()
static constexpr bool IsValidLength(intptr_t len)
static intptr_t length_offset()
static const Bool & False()
static const Bool & True()
static void Allocate(FlowGraphCompiler *compiler, Instruction *instruction, const Class &cls, Register result, Register temp)
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
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)
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)
ConstantInstr(const Object &value)
bool HasZeroRepresentation() const
static intptr_t num_variables_offset()
static intptr_t InstanceSize()
virtual Representation representation() const
static constexpr intptr_t kNone
static intptr_t guarded_cid_offset()
static intptr_t guarded_list_length_in_object_offset_offset()
static intptr_t is_nullable_offset()
static intptr_t guarded_list_length_offset()
ComparisonInstr * comparison() 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
intptr_t deopt_id() const
static LocationSummary * MakeCallSummary(Zone *zone, const Instruction *instr, LocationSummary *locs=nullptr)
ObjectStore * object_store() const
static IsolateGroup * Current()
virtual Representation RequiredInputRepresentation(intptr_t index) const
Register base_reg() const
virtual Representation representation() const
const LocalVariable & local() 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)
intptr_t stack_index() const
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)
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
Location location() const
static int ComputeArgcTag(const Function &function)
static uword LinkNativeCallEntry()
static Object & ZoneHandle()
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)
static constexpr intptr_t kBits
static SmiPtr New(intptr_t value)
static constexpr intptr_t kMaxValue
static intptr_t RawValue(intptr_t value)
const LocalVariable & local() 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
static bool IsEqualityOperator(Kind tok)
static int32_t Low32Bits(int64_t value)
static constexpr T Maximum(T x, T y)
static constexpr int ShiftForPowerOfTwo(T x)
static T Minimum(T x, T y)
static constexpr int CountOneBits32(uint32_t x)
static bool DoublesBitEqual(const double a, const double b)
static constexpr size_t HighestBit(int64_t v)
static constexpr bool IsPowerOfTwo(T x)
Definition * definition() 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)
FlutterSemanticsFlag flags
Dart_NativeFunction function
static float max(float r, float g, float b)
static float min(float r, float g, float b)
#define DEFINE_UNIMPLEMENTED_INSTRUCTION(Name)
#define DEFINE_BACKEND(Name, Args)
const intptr_t kResultIndex
word SmiValue(const dart::Object &a)
const Object & NullObject()
constexpr OperandSize kWordBytes
bool HasIntegerValue(const dart::Object &object, int64_t *value)
Location LocationAnyOrConstant(Value *value)
Location LocationRegisterOrConstant(Value *value)
const Register kWriteBarrierSlotReg
static Condition InvertCondition(Condition c)
const RegList kAbiVolatileCpuRegs
static constexpr int kSavedCallerPcSlotFromFp
bool IsTypedDataBaseClassId(intptr_t index)
const Register kExceptionObjectReg
static constexpr intptr_t kFalseOffsetFromNull
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 constexpr intptr_t kTrueOffsetFromNull
constexpr intptr_t kWordSizeLog2
static const ClassId kFirstErrorCid
static constexpr intptr_t kBoolValueBitPosition
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)
const Register CALLEE_SAVED_TEMP2
constexpr intptr_t kBitsPerInt64
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
static constexpr Register kInstanceOfResultReg
@ kResetToBootstrapNative