Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.

Commit 1210d27

Browse files
askeksacommit-bot@chromium.org
authored andcommitted
[vm] Distinguish between bool objects by a single bit in their pointers.
Allocate the canonical true and false objects right after the null object such that their pointers are the same except for a single bit. This enables a number of optimizations: - Test of a bool value becomes a bit test when it is known that the value is a bool. on ARM64, this bit test can be combined with the branch. - Negation of a bool value becomes an xor when it is known that the value is a bool. - Load of a bool value becomes an immediate add with the null register on ARM64. This is a reland of f8ead09 Change-Id: Iadb2169f80d3731153df3a93772f6142c3197260 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/142375 Reviewed-by: Martin Kustermann <[email protected]> Commit-Queue: Aske Simon Christensen <[email protected]>
1 parent ad1d29c commit 1210d27

20 files changed

+249
-40
lines changed

runtime/vm/compiler/assembler/assembler_arm64.cc

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -470,6 +470,14 @@ void Assembler::LoadObjectHelper(Register dst,
470470
mov(dst, NULL_REG);
471471
return;
472472
}
473+
if (IsSameObject(CastHandle<Object>(compiler::TrueObject()), object)) {
474+
AddImmediate(dst, NULL_REG, kTrueOffsetFromNull);
475+
return;
476+
}
477+
if (IsSameObject(CastHandle<Object>(compiler::FalseObject()), object)) {
478+
AddImmediate(dst, NULL_REG, kFalseOffsetFromNull);
479+
return;
480+
}
473481
word offset = 0;
474482
if (target::CanLoadFromThread(object, &offset)) {
475483
ldr(dst, Address(THR, offset));

runtime/vm/compiler/backend/flow_graph.cc

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1624,6 +1624,9 @@ void FlowGraph::RemoveRedefinitions(bool keep_checks) {
16241624
} else if (auto check = instruction->AsAssertAssignable()) {
16251625
check->ReplaceUsesWith(check->value()->definition());
16261626
check->ClearSSATempIndex();
1627+
} else if (auto check = instruction->AsAssertBoolean()) {
1628+
check->ReplaceUsesWith(check->value()->definition());
1629+
check->ClearSSATempIndex();
16271630
}
16281631
}
16291632
}

runtime/vm/compiler/backend/flow_graph_compiler.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -744,6 +744,7 @@ class FlowGraphCompiler : public ValueObject {
744744
bool needs_number_check,
745745
TokenPosition token_pos,
746746
intptr_t deopt_id);
747+
Condition EmitBoolTest(Register value, BranchLabels labels, bool invert);
747748

748749
bool NeedsEdgeCounter(BlockEntryInstr* block);
749750

runtime/vm/compiler/backend/flow_graph_compiler_arm.cc

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -214,8 +214,11 @@ void FlowGraphCompiler::GenerateBoolToJump(Register bool_register,
214214
compiler::Label fall_through;
215215
__ CompareObject(bool_register, Object::null_object());
216216
__ b(&fall_through, EQ);
217-
__ CompareObject(bool_register, Bool::True());
218-
__ b(is_true, EQ);
217+
BranchLabels labels = {is_true, is_false, &fall_through};
218+
Condition true_condition =
219+
EmitBoolTest(bool_register, labels, /*invert=*/false);
220+
ASSERT(true_condition != kInvalidCondition);
221+
__ b(is_true, true_condition);
219222
__ b(is_false);
220223
__ Bind(&fall_through);
221224
}
@@ -1338,6 +1341,15 @@ Condition FlowGraphCompiler::EmitEqualityRegRegCompare(Register left,
13381341
return EQ;
13391342
}
13401343

1344+
Condition FlowGraphCompiler::EmitBoolTest(Register value,
1345+
BranchLabels labels,
1346+
bool invert) {
1347+
__ Comment("BoolTest");
1348+
__ tst(value,
1349+
compiler::Operand(compiler::target::ObjectAlignment::kBoolValueMask));
1350+
return invert ? NE : EQ;
1351+
}
1352+
13411353
// This function must be in sync with FlowGraphCompiler::RecordSafepoint and
13421354
// FlowGraphCompiler::SlowPathEnvironmentFor.
13431355
void FlowGraphCompiler::SaveLiveRegisters(LocationSummary* locs) {

runtime/vm/compiler/backend/flow_graph_compiler_arm64.cc

Lines changed: 34 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -206,9 +206,10 @@ void FlowGraphCompiler::GenerateBoolToJump(Register bool_register,
206206
compiler::Label fall_through;
207207
__ CompareObject(bool_register, Object::null_object());
208208
__ b(&fall_through, EQ);
209-
__ CompareObject(bool_register, Bool::True());
210-
__ b(is_true, EQ);
211-
__ b(is_false);
209+
BranchLabels labels = {is_true, is_false, &fall_through};
210+
Condition true_condition =
211+
EmitBoolTest(bool_register, labels, /*invert=*/false);
212+
ASSERT(true_condition == kInvalidCondition);
212213
__ Bind(&fall_through);
213214
}
214215

@@ -1289,6 +1290,36 @@ Condition FlowGraphCompiler::EmitEqualityRegRegCompare(Register left,
12891290
return EQ;
12901291
}
12911292

1293+
Condition FlowGraphCompiler::EmitBoolTest(Register value,
1294+
BranchLabels labels,
1295+
bool invert) {
1296+
__ Comment("BoolTest");
1297+
if (labels.true_label == nullptr || labels.false_label == nullptr) {
1298+
__ tsti(value, compiler::Immediate(
1299+
compiler::target::ObjectAlignment::kBoolValueMask));
1300+
return invert ? NE : EQ;
1301+
}
1302+
const intptr_t bool_bit =
1303+
compiler::target::ObjectAlignment::kBoolValueBitPosition;
1304+
if (labels.fall_through == labels.false_label) {
1305+
if (invert) {
1306+
__ tbnz(labels.true_label, value, bool_bit);
1307+
} else {
1308+
__ tbz(labels.true_label, value, bool_bit);
1309+
}
1310+
} else {
1311+
if (invert) {
1312+
__ tbz(labels.false_label, value, bool_bit);
1313+
} else {
1314+
__ tbnz(labels.false_label, value, bool_bit);
1315+
}
1316+
if (labels.fall_through != labels.true_label) {
1317+
__ b(labels.true_label);
1318+
}
1319+
}
1320+
return kInvalidCondition;
1321+
}
1322+
12921323
// This function must be in sync with FlowGraphCompiler::RecordSafepoint and
12931324
// FlowGraphCompiler::SlowPathEnvironmentFor.
12941325
void FlowGraphCompiler::SaveLiveRegisters(LocationSummary* locs) {

runtime/vm/compiler/backend/flow_graph_compiler_ia32.cc

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -185,8 +185,11 @@ void FlowGraphCompiler::GenerateBoolToJump(Register bool_register,
185185
compiler::Label fall_through;
186186
__ cmpl(bool_register, raw_null);
187187
__ j(EQUAL, &fall_through, compiler::Assembler::kNearJump);
188-
__ CompareObject(bool_register, Bool::True());
189-
__ j(EQUAL, is_true);
188+
BranchLabels labels = {is_true, is_false, &fall_through};
189+
Condition true_condition =
190+
EmitBoolTest(bool_register, labels, /*invert=*/false);
191+
ASSERT(true_condition != kInvalidCondition);
192+
__ j(true_condition, is_true);
190193
__ jmp(is_false);
191194
__ Bind(&fall_through);
192195
}
@@ -1097,6 +1100,15 @@ Condition FlowGraphCompiler::EmitEqualityRegRegCompare(Register left,
10971100
return EQUAL;
10981101
}
10991102

1103+
Condition FlowGraphCompiler::EmitBoolTest(Register value,
1104+
BranchLabels labels,
1105+
bool invert) {
1106+
__ Comment("BoolTest");
1107+
__ testl(value, compiler::Immediate(
1108+
compiler::target::ObjectAlignment::kBoolValueMask));
1109+
return invert ? NOT_EQUAL : EQUAL;
1110+
}
1111+
11001112
// This function must be in sync with FlowGraphCompiler::RecordSafepoint and
11011113
// FlowGraphCompiler::SlowPathEnvironmentFor.
11021114
void FlowGraphCompiler::SaveLiveRegisters(LocationSummary* locs) {

runtime/vm/compiler/backend/flow_graph_compiler_x64.cc

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -207,8 +207,11 @@ void FlowGraphCompiler::GenerateBoolToJump(Register bool_register,
207207
compiler::Label fall_through;
208208
__ CompareObject(bool_register, Object::null_object());
209209
__ j(EQUAL, &fall_through, compiler::Assembler::kNearJump);
210-
__ CompareObject(bool_register, Bool::True());
211-
__ j(EQUAL, is_true);
210+
BranchLabels labels = {is_true, is_false, &fall_through};
211+
Condition true_condition =
212+
EmitBoolTest(bool_register, labels, /*invert=*/false);
213+
ASSERT(true_condition != kInvalidCondition);
214+
__ j(true_condition, is_true);
212215
__ jmp(is_false);
213216
__ Bind(&fall_through);
214217
}
@@ -1281,6 +1284,15 @@ Condition FlowGraphCompiler::EmitEqualityRegRegCompare(Register left,
12811284
return EQUAL;
12821285
}
12831286

1287+
Condition FlowGraphCompiler::EmitBoolTest(Register value,
1288+
BranchLabels labels,
1289+
bool invert) {
1290+
__ Comment("BoolTest");
1291+
__ testq(value, compiler::Immediate(
1292+
compiler::target::ObjectAlignment::kBoolValueMask));
1293+
return invert ? NOT_EQUAL : EQUAL;
1294+
}
1295+
12841296
// This function must be in sync with FlowGraphCompiler::RecordSafepoint and
12851297
// FlowGraphCompiler::SlowPathEnvironmentFor.
12861298
void FlowGraphCompiler::SaveLiveRegisters(LocationSummary* locs) {

runtime/vm/compiler/backend/il.cc

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -515,6 +515,10 @@ Value* AssertAssignableInstr::RedefinedValue() const {
515515
return value();
516516
}
517517

518+
Value* AssertBooleanInstr::RedefinedValue() const {
519+
return value();
520+
}
521+
518522
Value* CheckBoundBase::RedefinedValue() const {
519523
return index();
520524
}
@@ -4326,9 +4330,17 @@ Condition StrictCompareInstr::EmitComparisonCode(FlowGraphCompiler* compiler,
43264330
ASSERT(!left.IsConstant() || !right.IsConstant());
43274331
Condition true_condition;
43284332
if (left.IsConstant()) {
4333+
if (TryEmitBoolTest(compiler, labels, 1, left.constant(),
4334+
&true_condition)) {
4335+
return true_condition;
4336+
}
43294337
true_condition = EmitComparisonCodeRegConstant(
43304338
compiler, labels, right.reg(), left.constant());
43314339
} else if (right.IsConstant()) {
4340+
if (TryEmitBoolTest(compiler, labels, 0, right.constant(),
4341+
&true_condition)) {
4342+
return true_condition;
4343+
}
43324344
true_condition = EmitComparisonCodeRegConstant(compiler, labels, left.reg(),
43334345
right.constant());
43344346
} else {
@@ -4340,6 +4352,21 @@ Condition StrictCompareInstr::EmitComparisonCode(FlowGraphCompiler* compiler,
43404352
: true_condition;
43414353
}
43424354

4355+
bool StrictCompareInstr::TryEmitBoolTest(FlowGraphCompiler* compiler,
4356+
BranchLabels labels,
4357+
intptr_t input_index,
4358+
const Object& obj,
4359+
Condition* true_condition_out) {
4360+
CompileType* input_type = InputAt(input_index)->Type();
4361+
if (input_type->ToCid() == kBoolCid && obj.GetClassId() == kBoolCid) {
4362+
bool invert = (kind() != Token::kEQ_STRICT) ^ !Bool::Cast(obj).value();
4363+
*true_condition_out =
4364+
compiler->EmitBoolTest(locs()->in(input_index).reg(), labels, invert);
4365+
return true;
4366+
}
4367+
return false;
4368+
}
4369+
43434370
LocationSummary* LoadClassIdInstr::MakeLocationSummary(Zone* zone,
43444371
bool opt) const {
43454372
const intptr_t kNumInputs = 1;

runtime/vm/compiler/backend/il.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3587,6 +3587,8 @@ class AssertBooleanInstr : public TemplateDefinition<1, Throws, Pure> {
35873587

35883588
virtual bool AttributesEqual(Instruction* other) const { return true; }
35893589

3590+
virtual Value* RedefinedValue() const;
3591+
35903592
PRINT_OPERANDS_TO_SUPPORT
35913593

35923594
private:
@@ -4230,6 +4232,11 @@ class StrictCompareInstr : public TemplateComparison<2, NoThrow, Pure> {
42304232
BranchLabels labels,
42314233
Register reg,
42324234
const Object& obj);
4235+
bool TryEmitBoolTest(FlowGraphCompiler* compiler,
4236+
BranchLabels labels,
4237+
intptr_t input_index,
4238+
const Object& obj,
4239+
Condition* condition_out);
42334240

42344241
// True if the comparison must check for double or Mint and
42354242
// use value comparison instead.

runtime/vm/compiler/backend/il_arm.cc

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7528,12 +7528,18 @@ LocationSummary* BooleanNegateInstr::MakeLocationSummary(Zone* zone,
75287528
}
75297529

75307530
void BooleanNegateInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
7531-
const Register value = locs()->in(0).reg();
7531+
const Register input = locs()->in(0).reg();
75327532
const Register result = locs()->out(0).reg();
75337533

7534-
__ LoadObject(result, Bool::True());
7535-
__ cmp(result, compiler::Operand(value));
7536-
__ LoadObject(result, Bool::False(), EQ);
7534+
if (value()->Type()->ToCid() == kBoolCid) {
7535+
__ eor(
7536+
result, input,
7537+
compiler::Operand(compiler::target::ObjectAlignment::kBoolValueMask));
7538+
} else {
7539+
__ LoadObject(result, Bool::True());
7540+
__ cmp(result, compiler::Operand(input));
7541+
__ LoadObject(result, Bool::False(), EQ);
7542+
}
75377543
}
75387544

75397545
LocationSummary* AllocateObjectInstr::MakeLocationSummary(Zone* zone,

0 commit comments

Comments
 (0)