Skip to content

Commit 51f4d2e

Browse files
backesCommit Bot
authored andcommitted
[base] Generalize bits::CountPopulation
This makes the function constexpr and implements it for arbitrary unsigned integer types (up to 64 bits, but this can be extended if needed). R=mstarzinger@chromium.org Bug: v8:6600, v8:6921 Change-Id: I86d427238fadd55abb5a27f31ed648d4b02fc358 Reviewed-on: https://chromium-review.googlesource.com/718457 Commit-Queue: Clemens Hammacher <clemensh@chromium.org> Reviewed-by: Michael Starzinger <mstarzinger@chromium.org> Cr-Commit-Position: refs/heads/master@{#48696}
1 parent 6cfc2d3 commit 51f4d2e

20 files changed

Lines changed: 94 additions & 96 deletions

src/arm64/utils-arm64.cc

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -105,10 +105,10 @@ int CountTrailingZeros(uint64_t value, int width) {
105105
int CountSetBits(uint64_t value, int width) {
106106
DCHECK((width == 32) || (width == 64));
107107
if (width == 64) {
108-
return static_cast<int>(base::bits::CountPopulation64(value));
108+
return static_cast<int>(base::bits::CountPopulation(value));
109109
}
110-
return static_cast<int>(base::bits::CountPopulation32(
111-
static_cast<uint32_t>(value & 0xfffffffff)));
110+
return static_cast<int>(
111+
base::bits::CountPopulation(static_cast<uint32_t>(value & 0xfffffffff)));
112112
}
113113

114114
int LowestSetBitPosition(uint64_t value) {

src/base/bits.h

Lines changed: 22 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -54,33 +54,32 @@ namespace bits {
5454
return Name##64(value); \
5555
}
5656

57-
// CountPopulation32(value) returns the number of bits set in |value|.
58-
inline unsigned CountPopulation32(uint32_t value) {
57+
// CountPopulation(value) returns the number of bits set in |value|.
58+
template <typename T>
59+
constexpr inline
60+
typename std::enable_if<std::is_unsigned<T>::value && sizeof(T) <= 8,
61+
unsigned>::type
62+
CountPopulation(T value) {
5963
#if V8_HAS_BUILTIN_POPCOUNT
60-
return __builtin_popcount(value);
64+
return sizeof(T) == 8 ? __builtin_popcountll(static_cast<uint64_t>(value))
65+
: __builtin_popcount(static_cast<uint32_t>(value));
6166
#else
62-
value = ((value >> 1) & 0x55555555) + (value & 0x55555555);
63-
value = ((value >> 2) & 0x33333333) + (value & 0x33333333);
64-
value = ((value >> 4) & 0x0f0f0f0f) + (value & 0x0f0f0f0f);
65-
value = ((value >> 8) & 0x00ff00ff) + (value & 0x00ff00ff);
66-
value = ((value >> 16) & 0x0000ffff) + (value & 0x0000ffff);
67+
constexpr uint64_t mask[] = {0x5555555555555555, 0x3333333333333333,
68+
0x0f0f0f0f0f0f0f0f, 0x00ff00ff00ff00ff,
69+
0x0000ffff0000ffff, 0x00000000ffffffff};
70+
value = ((value >> 1) & mask[0]) + (value & mask[0]);
71+
value = ((value >> 2) & mask[1]) + (value & mask[1]);
72+
value = ((value >> 4) & mask[2]) + (value & mask[2]);
73+
if (sizeof(T) > 1)
74+
value = ((value >> (sizeof(T) > 1 ? 8 : 0)) & mask[3]) + (value & mask[3]);
75+
if (sizeof(T) > 2)
76+
value = ((value >> (sizeof(T) > 2 ? 16 : 0)) & mask[4]) + (value & mask[4]);
77+
if (sizeof(T) > 4)
78+
value = ((value >> (sizeof(T) > 4 ? 32 : 0)) & mask[5]) + (value & mask[5]);
6779
return static_cast<unsigned>(value);
6880
#endif
6981
}
7082

71-
72-
// CountPopulation64(value) returns the number of bits set in |value|.
73-
inline unsigned CountPopulation64(uint64_t value) {
74-
#if V8_HAS_BUILTIN_POPCOUNT
75-
return __builtin_popcountll(value);
76-
#else
77-
return CountPopulation32(static_cast<uint32_t>(value)) +
78-
CountPopulation32(static_cast<uint32_t>(value >> 32));
79-
#endif
80-
}
81-
82-
DEFINE_32_64_OVERLOADS(CountPopulation)
83-
8483
// CountLeadingZeros32(value) returns the number of zero bits following the most
8584
// significant 1 bit in |value| if |value| is non-zero, otherwise it returns 32.
8685
inline unsigned CountLeadingZeros32(uint32_t value) {
@@ -96,7 +95,7 @@ inline unsigned CountLeadingZeros32(uint32_t value) {
9695
value = value | (value >> 4);
9796
value = value | (value >> 8);
9897
value = value | (value >> 16);
99-
return CountPopulation32(~value);
98+
return CountPopulation(~value);
10099
#endif
101100
}
102101

@@ -113,7 +112,7 @@ inline unsigned CountLeadingZeros64(uint64_t value) {
113112
value = value | (value >> 8);
114113
value = value | (value >> 16);
115114
value = value | (value >> 32);
116-
return CountPopulation64(~value);
115+
return CountPopulation(~value);
117116
#endif
118117
}
119118

src/compiler/arm/code-generator-arm.cc

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2792,15 +2792,14 @@ void CodeGenerator::FinishFrame(Frame* frame) {
27922792
STATIC_ASSERT(DwVfpRegister::kNumRegisters == 32);
27932793
uint32_t last = base::bits::CountLeadingZeros32(saves_fp) - 1;
27942794
uint32_t first = base::bits::CountTrailingZeros32(saves_fp);
2795-
DCHECK_EQ((last - first + 1), base::bits::CountPopulation32(saves_fp));
2795+
DCHECK_EQ((last - first + 1), base::bits::CountPopulation(saves_fp));
27962796
frame->AllocateSavedCalleeRegisterSlots((last - first + 1) *
27972797
(kDoubleSize / kPointerSize));
27982798
}
27992799
const RegList saves = descriptor->CalleeSavedRegisters();
28002800
if (saves != 0) {
28012801
// Save callee-saved registers.
2802-
frame->AllocateSavedCalleeRegisterSlots(
2803-
base::bits::CountPopulation32(saves));
2802+
frame->AllocateSavedCalleeRegisterSlots(base::bits::CountPopulation(saves));
28042803
}
28052804
}
28062805

@@ -2890,7 +2889,7 @@ void CodeGenerator::AssembleConstructFrame() {
28902889
STATIC_ASSERT(DwVfpRegister::kNumRegisters == 32);
28912890
uint32_t last = base::bits::CountLeadingZeros32(saves_fp) - 1;
28922891
uint32_t first = base::bits::CountTrailingZeros32(saves_fp);
2893-
DCHECK_EQ((last - first + 1), base::bits::CountPopulation32(saves_fp));
2892+
DCHECK_EQ((last - first + 1), base::bits::CountPopulation(saves_fp));
28942893
__ vstm(db_w, sp, DwVfpRegister::from_code(first),
28952894
DwVfpRegister::from_code(last));
28962895
}

src/compiler/arm/instruction-selector-arm.cc

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -858,7 +858,7 @@ void InstructionSelector::VisitWord32And(Node* node) {
858858
}
859859
if (m.right().HasValue()) {
860860
uint32_t const value = m.right().Value();
861-
uint32_t width = base::bits::CountPopulation32(value);
861+
uint32_t width = base::bits::CountPopulation(value);
862862
uint32_t leading_zeros = base::bits::CountLeadingZeros32(value);
863863

864864
// Try to merge SHR operations on the left hand input into this AND.
@@ -1029,7 +1029,7 @@ void InstructionSelector::VisitWord32Shr(Node* node) {
10291029
Int32BinopMatcher mleft(m.left().node());
10301030
if (mleft.right().HasValue()) {
10311031
uint32_t value = (mleft.right().Value() >> lsb) << lsb;
1032-
uint32_t width = base::bits::CountPopulation32(value);
1032+
uint32_t width = base::bits::CountPopulation(value);
10331033
uint32_t msb = base::bits::CountLeadingZeros32(value);
10341034
if (msb + width + lsb == 32) {
10351035
DCHECK_EQ(lsb, base::bits::CountTrailingZeros32(value));

src/compiler/arm64/instruction-selector-arm64.cc

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -938,7 +938,7 @@ void InstructionSelector::VisitWord32And(Node* node) {
938938
if (m.left().IsWord32Shr() && CanCover(node, m.left().node()) &&
939939
m.right().HasValue()) {
940940
uint32_t mask = m.right().Value();
941-
uint32_t mask_width = base::bits::CountPopulation32(mask);
941+
uint32_t mask_width = base::bits::CountPopulation(mask);
942942
uint32_t mask_msb = base::bits::CountLeadingZeros32(mask);
943943
if ((mask_width != 0) && (mask_width != 32) &&
944944
(mask_msb + mask_width == 32)) {
@@ -979,7 +979,7 @@ void InstructionSelector::VisitWord64And(Node* node) {
979979
if (m.left().IsWord64Shr() && CanCover(node, m.left().node()) &&
980980
m.right().HasValue()) {
981981
uint64_t mask = m.right().Value();
982-
uint64_t mask_width = base::bits::CountPopulation64(mask);
982+
uint64_t mask_width = base::bits::CountPopulation(mask);
983983
uint64_t mask_msb = base::bits::CountLeadingZeros64(mask);
984984
if ((mask_width != 0) && (mask_width != 64) &&
985985
(mask_msb + mask_width == 64)) {
@@ -1054,7 +1054,7 @@ void InstructionSelector::VisitWord32Shl(Node* node) {
10541054
Int32BinopMatcher mleft(m.left().node());
10551055
if (mleft.right().HasValue()) {
10561056
uint32_t mask = mleft.right().Value();
1057-
uint32_t mask_width = base::bits::CountPopulation32(mask);
1057+
uint32_t mask_width = base::bits::CountPopulation(mask);
10581058
uint32_t mask_msb = base::bits::CountLeadingZeros32(mask);
10591059
if ((mask_width != 0) && (mask_msb + mask_width == 32)) {
10601060
uint32_t shift = m.right().Value();
@@ -1138,7 +1138,7 @@ void InstructionSelector::VisitWord32Shr(Node* node) {
11381138
// Select Ubfx for Shr(And(x, mask), imm) where the result of the mask is
11391139
// shifted into the least-significant bits.
11401140
uint32_t mask = (mleft.right().Value() >> lsb) << lsb;
1141-
unsigned mask_width = base::bits::CountPopulation32(mask);
1141+
unsigned mask_width = base::bits::CountPopulation(mask);
11421142
unsigned mask_msb = base::bits::CountLeadingZeros32(mask);
11431143
if ((mask_msb + mask_width + lsb) == 32) {
11441144
Arm64OperandGenerator g(this);
@@ -1182,7 +1182,7 @@ void InstructionSelector::VisitWord64Shr(Node* node) {
11821182
// Select Ubfx for Shr(And(x, mask), imm) where the result of the mask is
11831183
// shifted into the least-significant bits.
11841184
uint64_t mask = (mleft.right().Value() >> lsb) << lsb;
1185-
unsigned mask_width = base::bits::CountPopulation64(mask);
1185+
unsigned mask_width = base::bits::CountPopulation(mask);
11861186
unsigned mask_msb = base::bits::CountLeadingZeros64(mask);
11871187
if ((mask_msb + mask_width + lsb) == 64) {
11881188
Arm64OperandGenerator g(this);

src/compiler/mips/code-generator-mips.cc

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3365,15 +3365,15 @@ void CodeGenerator::FinishFrame(Frame* frame) {
33653365
}
33663366

33673367
if (saves_fpu != 0) {
3368-
int count = base::bits::CountPopulation32(saves_fpu);
3368+
int count = base::bits::CountPopulation(saves_fpu);
33693369
DCHECK_EQ(kNumCalleeSavedFPU, count);
33703370
frame->AllocateSavedCalleeRegisterSlots(count *
33713371
(kDoubleSize / kPointerSize));
33723372
}
33733373

33743374
const RegList saves = descriptor->CalleeSavedRegisters();
33753375
if (saves != 0) {
3376-
int count = base::bits::CountPopulation32(saves);
3376+
int count = base::bits::CountPopulation(saves);
33773377
DCHECK_EQ(kNumCalleeSaved, count + 1);
33783378
frame->AllocateSavedCalleeRegisterSlots(count);
33793379
}
@@ -3425,7 +3425,7 @@ void CodeGenerator::AssembleConstructFrame() {
34253425
if (saves != 0) {
34263426
// Save callee-saved registers.
34273427
__ MultiPush(saves);
3428-
DCHECK_EQ(kNumCalleeSaved, base::bits::CountPopulation32(saves) + 1);
3428+
DCHECK_EQ(kNumCalleeSaved, base::bits::CountPopulation(saves) + 1);
34293429
}
34303430
}
34313431

src/compiler/mips/instruction-selector-mips.cc

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -421,7 +421,7 @@ void InstructionSelector::VisitWord32And(Node* node) {
421421
if (m.left().IsWord32Shr() && CanCover(node, m.left().node()) &&
422422
m.right().HasValue()) {
423423
uint32_t mask = m.right().Value();
424-
uint32_t mask_width = base::bits::CountPopulation32(mask);
424+
uint32_t mask_width = base::bits::CountPopulation(mask);
425425
uint32_t mask_msb = base::bits::CountLeadingZeros32(mask);
426426
if ((mask_width != 0) && (mask_msb + mask_width == 32)) {
427427
// The mask must be contiguous, and occupy the least-significant bits.
@@ -454,7 +454,7 @@ void InstructionSelector::VisitWord32And(Node* node) {
454454
}
455455
if (m.right().HasValue()) {
456456
uint32_t mask = m.right().Value();
457-
uint32_t shift = base::bits::CountPopulation32(~mask);
457+
uint32_t shift = base::bits::CountPopulation(~mask);
458458
uint32_t msb = base::bits::CountLeadingZeros32(~mask);
459459
if (shift != 0 && shift != 32 && msb + shift == 32) {
460460
// Insert zeros for (x >> K) << K => x & ~(2^K - 1) expression reduction
@@ -507,7 +507,7 @@ void InstructionSelector::VisitWord32Shl(Node* node) {
507507
// contiguous, and the shift immediate non-zero.
508508
if (mleft.right().HasValue()) {
509509
uint32_t mask = mleft.right().Value();
510-
uint32_t mask_width = base::bits::CountPopulation32(mask);
510+
uint32_t mask_width = base::bits::CountPopulation(mask);
511511
uint32_t mask_msb = base::bits::CountLeadingZeros32(mask);
512512
if ((mask_width != 0) && (mask_msb + mask_width == 32)) {
513513
uint32_t shift = m.right().Value();
@@ -537,7 +537,7 @@ void InstructionSelector::VisitWord32Shr(Node* node) {
537537
// Select Ext for Shr(And(x, mask), imm) where the result of the mask is
538538
// shifted into the least-significant bits.
539539
uint32_t mask = (mleft.right().Value() >> lsb) << lsb;
540-
unsigned mask_width = base::bits::CountPopulation32(mask);
540+
unsigned mask_width = base::bits::CountPopulation(mask);
541541
unsigned mask_msb = base::bits::CountLeadingZeros32(mask);
542542
if ((mask_msb + mask_width + lsb) == 32) {
543543
MipsOperandGenerator g(this);

src/compiler/mips64/code-generator-mips64.cc

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3666,15 +3666,15 @@ void CodeGenerator::FinishFrame(Frame* frame) {
36663666

36673667
const RegList saves_fpu = descriptor->CalleeSavedFPRegisters();
36683668
if (saves_fpu != 0) {
3669-
int count = base::bits::CountPopulation32(saves_fpu);
3669+
int count = base::bits::CountPopulation(saves_fpu);
36703670
DCHECK_EQ(kNumCalleeSavedFPU, count);
36713671
frame->AllocateSavedCalleeRegisterSlots(count *
36723672
(kDoubleSize / kPointerSize));
36733673
}
36743674

36753675
const RegList saves = descriptor->CalleeSavedRegisters();
36763676
if (saves != 0) {
3677-
int count = base::bits::CountPopulation32(saves);
3677+
int count = base::bits::CountPopulation(saves);
36783678
DCHECK_EQ(kNumCalleeSaved, count + 1);
36793679
frame->AllocateSavedCalleeRegisterSlots(count);
36803680
}
@@ -3721,14 +3721,14 @@ void CodeGenerator::AssembleConstructFrame() {
37213721
if (saves_fpu != 0) {
37223722
// Save callee-saved FPU registers.
37233723
__ MultiPushFPU(saves_fpu);
3724-
DCHECK_EQ(kNumCalleeSavedFPU, base::bits::CountPopulation32(saves_fpu));
3724+
DCHECK_EQ(kNumCalleeSavedFPU, base::bits::CountPopulation(saves_fpu));
37253725
}
37263726

37273727
const RegList saves = descriptor->CalleeSavedRegisters();
37283728
if (saves != 0) {
37293729
// Save callee-saved registers.
37303730
__ MultiPush(saves);
3731-
DCHECK_EQ(kNumCalleeSaved, base::bits::CountPopulation32(saves) + 1);
3731+
DCHECK_EQ(kNumCalleeSaved, base::bits::CountPopulation(saves) + 1);
37323732
}
37333733
}
37343734

src/compiler/mips64/instruction-selector-mips64.cc

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -529,7 +529,7 @@ void InstructionSelector::VisitWord32And(Node* node) {
529529
if (m.left().IsWord32Shr() && CanCover(node, m.left().node()) &&
530530
m.right().HasValue()) {
531531
uint32_t mask = m.right().Value();
532-
uint32_t mask_width = base::bits::CountPopulation32(mask);
532+
uint32_t mask_width = base::bits::CountPopulation(mask);
533533
uint32_t mask_msb = base::bits::CountLeadingZeros32(mask);
534534
if ((mask_width != 0) && (mask_msb + mask_width == 32)) {
535535
// The mask must be contiguous, and occupy the least-significant bits.
@@ -558,7 +558,7 @@ void InstructionSelector::VisitWord32And(Node* node) {
558558
}
559559
if (m.right().HasValue()) {
560560
uint32_t mask = m.right().Value();
561-
uint32_t shift = base::bits::CountPopulation32(~mask);
561+
uint32_t shift = base::bits::CountPopulation(~mask);
562562
uint32_t msb = base::bits::CountLeadingZeros32(~mask);
563563
if (shift != 0 && shift != 32 && msb + shift == 32) {
564564
// Insert zeros for (x >> K) << K => x & ~(2^K - 1) expression reduction
@@ -579,7 +579,7 @@ void InstructionSelector::VisitWord64And(Node* node) {
579579
if (m.left().IsWord64Shr() && CanCover(node, m.left().node()) &&
580580
m.right().HasValue()) {
581581
uint64_t mask = m.right().Value();
582-
uint32_t mask_width = base::bits::CountPopulation64(mask);
582+
uint32_t mask_width = base::bits::CountPopulation(mask);
583583
uint32_t mask_msb = base::bits::CountLeadingZeros64(mask);
584584
if ((mask_width != 0) && (mask_msb + mask_width == 64)) {
585585
// The mask must be contiguous, and occupy the least-significant bits.
@@ -612,7 +612,7 @@ void InstructionSelector::VisitWord64And(Node* node) {
612612
}
613613
if (m.right().HasValue()) {
614614
uint64_t mask = m.right().Value();
615-
uint32_t shift = base::bits::CountPopulation64(~mask);
615+
uint32_t shift = base::bits::CountPopulation(~mask);
616616
uint32_t msb = base::bits::CountLeadingZeros64(~mask);
617617
if (shift != 0 && shift < 32 && msb + shift == 64) {
618618
// Insert zeros for (x >> K) << K => x & ~(2^K - 1) expression reduction
@@ -696,7 +696,7 @@ void InstructionSelector::VisitWord32Shl(Node* node) {
696696
// contiguous, and the shift immediate non-zero.
697697
if (mleft.right().HasValue()) {
698698
uint32_t mask = mleft.right().Value();
699-
uint32_t mask_width = base::bits::CountPopulation32(mask);
699+
uint32_t mask_width = base::bits::CountPopulation(mask);
700700
uint32_t mask_msb = base::bits::CountLeadingZeros32(mask);
701701
if ((mask_width != 0) && (mask_msb + mask_width == 32)) {
702702
uint32_t shift = m.right().Value();
@@ -726,7 +726,7 @@ void InstructionSelector::VisitWord32Shr(Node* node) {
726726
// Select Ext for Shr(And(x, mask), imm) where the result of the mask is
727727
// shifted into the least-significant bits.
728728
uint32_t mask = (mleft.right().Value() >> lsb) << lsb;
729-
unsigned mask_width = base::bits::CountPopulation32(mask);
729+
unsigned mask_width = base::bits::CountPopulation(mask);
730730
unsigned mask_msb = base::bits::CountLeadingZeros32(mask);
731731
if ((mask_msb + mask_width + lsb) == 32) {
732732
Mips64OperandGenerator g(this);
@@ -788,7 +788,7 @@ void InstructionSelector::VisitWord64Shl(Node* node) {
788788
Int64BinopMatcher mleft(m.left().node());
789789
if (mleft.right().HasValue()) {
790790
uint64_t mask = mleft.right().Value();
791-
uint32_t mask_width = base::bits::CountPopulation64(mask);
791+
uint32_t mask_width = base::bits::CountPopulation(mask);
792792
uint32_t mask_msb = base::bits::CountLeadingZeros64(mask);
793793
if ((mask_width != 0) && (mask_msb + mask_width == 64)) {
794794
uint64_t shift = m.right().Value();
@@ -819,7 +819,7 @@ void InstructionSelector::VisitWord64Shr(Node* node) {
819819
// Select Dext for Shr(And(x, mask), imm) where the result of the mask is
820820
// shifted into the least-significant bits.
821821
uint64_t mask = (mleft.right().Value() >> lsb) << lsb;
822-
unsigned mask_width = base::bits::CountPopulation64(mask);
822+
unsigned mask_width = base::bits::CountPopulation(mask);
823823
unsigned mask_msb = base::bits::CountLeadingZeros64(mask);
824824
if ((mask_msb + mask_width + lsb) == 64) {
825825
Mips64OperandGenerator g(this);

src/compiler/ppc/code-generator-ppc.cc

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2301,7 +2301,7 @@ void CodeGenerator::FinishFrame(Frame* frame) {
23012301
if (double_saves != 0) {
23022302
frame->AlignSavedCalleeRegisterSlots();
23032303
DCHECK_EQ(kNumCalleeSavedDoubles,
2304-
base::bits::CountPopulation32(double_saves));
2304+
base::bits::CountPopulation(double_saves));
23052305
frame->AllocateSavedCalleeRegisterSlots(kNumCalleeSavedDoubles *
23062306
(kDoubleSize / kPointerSize));
23072307
}
@@ -2314,7 +2314,7 @@ void CodeGenerator::FinishFrame(Frame* frame) {
23142314
// register save area does not include the fp or constant pool pointer.
23152315
const int num_saves =
23162316
kNumCalleeSaved - 1 - (FLAG_enable_embedded_constant_pool ? 1 : 0);
2317-
DCHECK(num_saves == base::bits::CountPopulation32(saves));
2317+
DCHECK(num_saves == base::bits::CountPopulation(saves));
23182318
frame->AllocateSavedCalleeRegisterSlots(num_saves);
23192319
}
23202320
}
@@ -2370,7 +2370,7 @@ void CodeGenerator::AssembleConstructFrame() {
23702370
if (double_saves != 0) {
23712371
__ MultiPushDoubles(double_saves);
23722372
DCHECK_EQ(kNumCalleeSavedDoubles,
2373-
base::bits::CountPopulation32(double_saves));
2373+
base::bits::CountPopulation(double_saves));
23742374
}
23752375

23762376
// Save callee-saved registers.

0 commit comments

Comments
 (0)