Skip to content

Commit 4e4d546

Browse files
zjiazV8 LUCI CQ
authored andcommitted
[loong64][compiler] Port some optimizations for write barrier
Port commit 25a1089 - [compiler] Invoke method for skipped indirect write barrier Port commit cc26a34 - [compiler] Save link register in write barrier verification Port commit 8112cb4 - [compiler] Reduce wb verification performance overhead Port commit d2b19ba - [compiler] Emit proper instruction on indirect write barrier Port commit a1d0bf6 - [codegen] Improve WB verification for allocation folding Change-Id: Ib0e77ef018c9466f7a9687c3b76763aa985a267e Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/6993339 Auto-Submit: Zhao Jiazhong <[email protected]> Reviewed-by: Darius Mercadier <[email protected]> Commit-Queue: Darius Mercadier <[email protected]> Cr-Commit-Position: refs/heads/main@{#102810}
1 parent 54a8366 commit 4e4d546

4 files changed

Lines changed: 164 additions & 23 deletions

File tree

src/codegen/loong64/macro-assembler-loong64.cc

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,58 @@ void MacroAssembler::PushStandardFrame(Register function_reg) {
142142
Add_d(fp, sp, Operand(offset));
143143
}
144144

145+
void MacroAssembler::PreCheckSkippedWriteBarrier(Register object,
146+
Register value,
147+
Register scratch, Label* ok) {
148+
ASM_CODE_COMMENT(this);
149+
DCHECK(!AreAliased(object, scratch));
150+
DCHECK(!AreAliased(value, scratch));
151+
152+
// The most common case: Static write barrier elimination is allowed on the
153+
// last young allocation.
154+
{
155+
UseScratchRegisterScope temps(this);
156+
Register scratch1 = temps.Acquire();
157+
Sub_d(scratch, object, kHeapObjectTag);
158+
Ld_d(scratch1, MemOperand(kRootRegister,
159+
IsolateData::last_young_allocation_offset()));
160+
Branch(ok, Condition::kEqual, scratch, Operand(scratch1));
161+
}
162+
163+
// Write barier can also be removed if value is in read-only space.
164+
CheckPageFlag(value, MemoryChunk::kIsInReadOnlyHeapMask, ne, ok);
165+
166+
Label not_ok;
167+
168+
// Handle allocation folding, allow WB removal if:
169+
// LAB start <= last_young_allocation_ < (object address+1) < LAB top
170+
// Note that object has tag bit set, so object == object address+1.
171+
{
172+
UseScratchRegisterScope temps(this);
173+
Register scratch1 = temps.Acquire();
174+
175+
// Check LAB start <= last_young_allocation_.
176+
Ld_d(scratch, MemOperand(kRootRegister,
177+
IsolateData::new_allocation_info_start_offset()));
178+
Ld_d(scratch1, MemOperand(kRootRegister,
179+
IsolateData::last_young_allocation_offset()));
180+
Branch(&not_ok, Condition::kUnsignedGreaterThan, scratch,
181+
Operand(scratch1));
182+
183+
// Check last_young_allocation_ < (object address+1).
184+
Branch(&not_ok, Condition::kUnsignedGreaterThanEqual, scratch1,
185+
Operand(object));
186+
187+
// Check (object address+1) < LAB top.
188+
Ld_d(scratch, MemOperand(kRootRegister,
189+
IsolateData::new_allocation_info_top_offset()));
190+
Branch(ok, Condition::kUnsignedLessThan, object, Operand(scratch));
191+
}
192+
193+
// Slow path: Potentially check more cases in C++.
194+
bind(&not_ok);
195+
}
196+
145197
// Clobbers object, dst, value, and ra, if (ra_status == kRAHasBeenSaved)
146198
// The register 'object' contains a heap object pointer. The heap object
147199
// tag is shifted away.
@@ -582,11 +634,33 @@ void MacroAssembler::CallVerifySkippedWriteBarrierStubSaveRegisters(
582634
void MacroAssembler::CallVerifySkippedWriteBarrierStub(Register object,
583635
Register value) {
584636
ASM_CODE_COMMENT(this);
637+
UseScratchRegisterScope temps(this);
638+
Register scratch = temps.Acquire();
639+
PrepareCallCFunction(2, scratch);
585640
MovePair(kCArgRegs[0], object, kCArgRegs[1], value);
586641
CallCFunction(ExternalReference::verify_skipped_write_barrier(), 2,
587642
SetIsolateDataSlots::kNo);
588643
}
589644

645+
void MacroAssembler::CallVerifySkippedIndirectWriteBarrierStubSaveRegisters(
646+
Register object, Register value, SaveFPRegsMode fp_mode) {
647+
ASM_CODE_COMMENT(this);
648+
PushCallerSaved(fp_mode);
649+
CallVerifySkippedIndirectWriteBarrierStub(object, value);
650+
PopCallerSaved(fp_mode);
651+
}
652+
653+
void MacroAssembler::CallVerifySkippedIndirectWriteBarrierStub(Register object,
654+
Register value) {
655+
ASM_CODE_COMMENT(this);
656+
UseScratchRegisterScope temps(this);
657+
Register scratch = temps.Acquire();
658+
PrepareCallCFunction(2, scratch);
659+
MovePair(kCArgRegs[0], object, kCArgRegs[1], value);
660+
CallCFunction(ExternalReference::verify_skipped_indirect_write_barrier(), 2,
661+
SetIsolateDataSlots::kNo);
662+
}
663+
590664
void MacroAssembler::MoveObjectAndSlot(Register dst_object, Register dst_slot,
591665
Register object, Operand offset) {
592666
ASM_CODE_COMMENT(this);

src/codegen/loong64/macro-assembler-loong64.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -181,6 +181,9 @@ class V8_EXPORT_PRIVATE MacroAssembler : public MacroAssemblerBase {
181181
void LoadRootRelative(Register destination, int32_t offset) final;
182182
void StoreRootRelative(int32_t offset, Register value) final;
183183

184+
void PreCheckSkippedWriteBarrier(Register object, Register value,
185+
Register scratch, Label* ok);
186+
184187
// Operand pointing to an external reference.
185188
// May emit code to set up the scratch register. The operand is
186189
// only guaranteed to be correct as long as the scratch register
@@ -360,6 +363,11 @@ class V8_EXPORT_PRIVATE MacroAssembler : public MacroAssemblerBase {
360363
SaveFPRegsMode fp_mode);
361364
void CallVerifySkippedWriteBarrierStub(Register object, Register value);
362365

366+
void CallVerifySkippedIndirectWriteBarrierStubSaveRegisters(
367+
Register object, Register value, SaveFPRegsMode fp_mode);
368+
void CallVerifySkippedIndirectWriteBarrierStub(Register object,
369+
Register value);
370+
363371
// For a given |object| and |offset|:
364372
// - Move |object| to |dst_object|.
365373
// - Compute the address of the slot pointed to by |offset| in |object| and

src/compiler/backend/loong64/code-generator-loong64.cc

Lines changed: 62 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -156,7 +156,7 @@ class OutOfLineRecordWrite final : public OutOfLineCode {
156156
#if V8_ENABLE_WEBASSEMBLY
157157
stub_mode_(stub_mode),
158158
#endif // V8_ENABLE_WEBASSEMBLY
159-
must_save_lr_(!gen->frame_access_state()->has_frame()),
159+
must_save_ra_(!gen->frame_access_state()->has_frame()),
160160
zone_(gen->zone()),
161161
indirect_pointer_tag_(indirect_pointer_tag) {
162162
}
@@ -175,7 +175,7 @@ class OutOfLineRecordWrite final : public OutOfLineCode {
175175
SaveFPRegsMode const save_fp_mode = frame()->DidAllocateDoubleRegisters()
176176
? SaveFPRegsMode::kSave
177177
: SaveFPRegsMode::kIgnore;
178-
if (must_save_lr_) {
178+
if (must_save_ra_) {
179179
// We need to save and restore ra if the frame was elided.
180180
__ Push(ra);
181181
}
@@ -196,7 +196,7 @@ class OutOfLineRecordWrite final : public OutOfLineCode {
196196
} else {
197197
__ CallRecordWriteStubSaveRegisters(object_, offset_, save_fp_mode);
198198
}
199-
if (must_save_lr_) {
199+
if (must_save_ra_) {
200200
__ Pop(ra);
201201
}
202202
}
@@ -209,7 +209,7 @@ class OutOfLineRecordWrite final : public OutOfLineCode {
209209
#if V8_ENABLE_WEBASSEMBLY
210210
StubCallMode const stub_mode_;
211211
#endif // V8_ENABLE_WEBASSEMBLY
212-
bool must_save_lr_;
212+
bool must_save_ra_;
213213
Zone* zone_;
214214
IndirectPointerTag indirect_pointer_tag_;
215215
};
@@ -294,23 +294,62 @@ void RecordTrapInfoIfNeeded(Zone* zone, CodeGenerator* codegen,
294294
class OutOfLineVerifySkippedWriteBarrier final : public OutOfLineCode {
295295
public:
296296
OutOfLineVerifySkippedWriteBarrier(CodeGenerator* gen, Register object,
297-
Register value)
297+
Register value, Register scratch)
298298
: OutOfLineCode(gen),
299299
object_(object),
300300
value_(value),
301+
scratch_(scratch),
302+
must_save_ra_(!gen->frame_access_state()->has_frame()),
301303
zone_(gen->zone()) {}
302304

303305
void Generate() final {
304306
if (COMPRESS_POINTERS_BOOL) {
305307
__ DecompressTagged(value_, value_);
306308
}
307309

310+
if (must_save_ra_) {
311+
// We need to save and restore ra if the frame was elided.
312+
__ Push(ra);
313+
}
314+
315+
__ PreCheckSkippedWriteBarrier(object_, value_, scratch_, exit());
316+
308317
SaveFPRegsMode const save_fp_mode = frame()->DidAllocateDoubleRegisters()
309318
? SaveFPRegsMode::kSave
310319
: SaveFPRegsMode::kIgnore;
311320

312321
__ CallVerifySkippedWriteBarrierStubSaveRegisters(object_, value_,
313322
save_fp_mode);
323+
324+
if (must_save_ra_) {
325+
__ Pop(ra);
326+
}
327+
}
328+
329+
private:
330+
Register const object_;
331+
Register const value_;
332+
Register const scratch_;
333+
const bool must_save_ra_;
334+
Zone* zone_;
335+
};
336+
337+
class OutOfLineVerifySkippedIndirectWriteBarrier final : public OutOfLineCode {
338+
public:
339+
OutOfLineVerifySkippedIndirectWriteBarrier(CodeGenerator* gen,
340+
Register object, Register value)
341+
: OutOfLineCode(gen),
342+
object_(object),
343+
value_(value),
344+
zone_(gen->zone()) {}
345+
346+
void Generate() final {
347+
SaveFPRegsMode const save_fp_mode = frame()->DidAllocateDoubleRegisters()
348+
? SaveFPRegsMode::kSave
349+
: SaveFPRegsMode::kIgnore;
350+
351+
__ CallVerifySkippedIndirectWriteBarrierStubSaveRegisters(object_, value_,
352+
save_fp_mode);
314353
}
315354

316355
private:
@@ -1025,12 +1064,12 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
10251064
Operand(kClearedWeakHeapObjectLower32));
10261065
}
10271066

1028-
if (v8_flags.verify_write_barriers) {
1029-
auto ool = zone()->New<OutOfLineVerifySkippedWriteBarrier>(this, object,
1030-
value);
1031-
__ JumpIfNotSmi(value, ool->entry());
1032-
__ bind(ool->exit());
1033-
}
1067+
DCHECK(v8_flags.verify_write_barriers);
1068+
Register scratch = i.TempRegister(0);
1069+
auto ool = zone()->New<OutOfLineVerifySkippedWriteBarrier>(
1070+
this, object, value, scratch);
1071+
__ JumpIfNotSmi(value, ool->entry());
1072+
__ bind(ool->exit());
10341073

10351074
MacroAssemblerBase::BlockTrampolinePoolScope block_trampoline_pool(
10361075
masm());
@@ -1085,12 +1124,12 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
10851124
Register temp = i.TempRegister(0);
10861125
__ Add_d(temp, object, offset);
10871126

1088-
if (v8_flags.verify_write_barriers) {
1089-
auto ool = zone()->New<OutOfLineVerifySkippedWriteBarrier>(this, object,
1090-
value);
1091-
__ JumpIfNotSmi(value, ool->entry());
1092-
__ bind(ool->exit());
1093-
}
1127+
DCHECK(v8_flags.verify_write_barriers);
1128+
Register scratch = i.TempRegister(1);
1129+
auto ool = zone()->New<OutOfLineVerifySkippedWriteBarrier>(
1130+
this, object, value, scratch);
1131+
__ JumpIfNotSmi(value, ool->entry());
1132+
__ bind(ool->exit());
10941133

10951134
MacroAssemblerBase::BlockTrampolinePoolScope block_trampoline_pool(
10961135
masm());
@@ -1150,6 +1189,12 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
11501189
DCHECK(IsValidIndirectPointerTag(tag));
11511190
#endif // DEBUG
11521191

1192+
DCHECK(v8_flags.verify_write_barriers);
1193+
auto ool = zone()->New<OutOfLineVerifySkippedIndirectWriteBarrier>(
1194+
this, object, value);
1195+
__ jmp(ool->entry());
1196+
__ bind(ool->exit());
1197+
11531198
MacroAssemblerBase::BlockTrampolinePoolScope block_trampoline_pool(
11541199
masm());
11551200
Operand offset(0);

src/compiler/backend/loong64/instruction-selector-loong64.cc

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,7 @@ class Loong64OperandGenerator final : public OperandGenerator {
8989
bool CanBeImmediate(int64_t value, InstructionCode opcode) {
9090
switch (ArchOpcodeField::decode(opcode)) {
9191
case kArchAtomicStoreWithWriteBarrier:
92+
case kArchAtomicStoreSkippedWriteBarrier:
9293
return false;
9394
case kLoong64Cmp32:
9495
case kLoong64Cmp64:
@@ -619,7 +620,9 @@ void InstructionSelector::VisitStore(OpIndex node) {
619620
DCHECK(write_barrier_kind == kIndirectPointerWriteBarrier ||
620621
write_barrier_kind == kSkippedWriteBarrier);
621622
// In this case we need to add the IndirectPointerTag as additional input.
622-
code = kArchStoreIndirectWithWriteBarrier;
623+
code = write_barrier_kind == kSkippedWriteBarrier
624+
? kArchStoreIndirectSkippedWriteBarrier
625+
: kArchStoreIndirectWithWriteBarrier;
623626
code |= RecordWriteModeField::encode(
624627
RecordWriteMode::kValueIsIndirectPointer);
625628
IndirectPointerTag tag = store_view.indirect_pointer_tag();
@@ -636,7 +639,13 @@ void InstructionSelector::VisitStore(OpIndex node) {
636639
if (store_view.is_store_trap_on_null()) {
637640
code |= AccessModeField::encode(kMemoryAccessProtectedNullDereference);
638641
}
639-
Emit(code, 0, nullptr, input_count, inputs);
642+
643+
InstructionOperand temps[1];
644+
size_t temp_count = 0;
645+
if (write_barrier_kind == kSkippedWriteBarrier) {
646+
temps[temp_count++] = g.TempRegister();
647+
}
648+
Emit(code, 0, nullptr, input_count, inputs, temp_count, temps);
640649
return;
641650
}
642651

@@ -1794,6 +1803,10 @@ void VisitAtomicStore(InstructionSelector* selector, OpIndex node,
17941803
write_barrier_kind = kFullWriteBarrier;
17951804
}
17961805

1806+
InstructionOperand inputs[] = {g.UseRegister(base), g.UseRegister(index),
1807+
g.UseRegisterOrImmediateZero(value)};
1808+
InstructionOperand temps[2] = {};
1809+
size_t temp_count = 0;
17971810
InstructionCode code;
17981811

17991812
if (write_barrier_kind != kNoWriteBarrier &&
@@ -1804,6 +1817,8 @@ void VisitAtomicStore(InstructionSelector* selector, OpIndex node,
18041817
if (write_barrier_kind == kSkippedWriteBarrier) {
18051818
code = kArchAtomicStoreSkippedWriteBarrier;
18061819
code |= RecordWriteModeField::encode(RecordWriteMode::kValueIsAny);
1820+
temps[temp_count++] = g.TempRegister();
1821+
temps[temp_count++] = g.TempRegister();
18071822
} else {
18081823
RecordWriteMode record_write_mode =
18091824
WriteBarrierKindToRecordWriteMode(write_barrier_kind);
@@ -1849,15 +1864,14 @@ void VisitAtomicStore(InstructionSelector* selector, OpIndex node,
18491864
}
18501865

18511866
if (g.CanBeImmediate(index, code)) {
1867+
inputs[1] = g.UseImmediate(index);
18521868
selector->Emit(code | AddressingModeField::encode(kMode_MRI) |
18531869
AtomicWidthField::encode(width),
1854-
g.NoOutput(), g.UseRegister(base), g.UseImmediate(index),
1855-
g.UseRegisterOrImmediateZero(value));
1870+
0, nullptr, arraysize(inputs), inputs, temp_count, temps);
18561871
} else {
18571872
selector->Emit(code | AddressingModeField::encode(kMode_MRR) |
18581873
AtomicWidthField::encode(width),
1859-
g.NoOutput(), g.UseRegister(base), g.UseRegister(index),
1860-
g.UseRegisterOrImmediateZero(value));
1874+
0, nullptr, arraysize(inputs), inputs, temp_count, temps);
18611875
}
18621876
}
18631877

0 commit comments

Comments
 (0)