Prevent overflow for AOT hotness counters
Previous, the addition did not have a check for overflow and might wrap
around since the counter is only 16 bits.
Modified the test to exercise this.
The slowdown from fixing the overflow is 2% average on golem arm32/64.
Overall this brings the slowdown from the counter to ~15% from ~13%.
The benchmarks that regress the most are loopy ones that I would
consider non-representative. Code size increases by 0.6%.
Bug: 139883463
Test: test/run-test --host --64 --prebuild 674-hotness-compiled
Test: test/run-test --host --prebuild 674-hotness-compiled
Test: test/run-test --64 --prebuild 674-hotness-compiled
Test: test/run-test ---prebuild 674-hotness-compiled
Change-Id: Icf0ab2aedbc40ab10c9d952ce0f9c7b5e5feaf15
diff --git a/compiler/optimizing/code_generator_arm64.cc b/compiler/optimizing/code_generator_arm64.cc
index a299ece..269b4e9 100644
--- a/compiler/optimizing/code_generator_arm64.cc
+++ b/compiler/optimizing/code_generator_arm64.cc
@@ -1068,8 +1068,10 @@
if (GetCompilerOptions().CountHotnessInCompiledCode()) {
UseScratchRegisterScope temps(masm);
Register temp = temps.AcquireX();
- __ Ldrh(temp, MemOperand(kArtMethodRegister, ArtMethod::HotnessCountOffset().Int32Value()));
- __ Add(temp, temp, 1);
+ __ Ldrsh(temp, MemOperand(kArtMethodRegister, ArtMethod::HotnessCountOffset().Int32Value()));
+ __ Adds(temp, temp, 1);
+ // Subtract carry if it overflowed.
+ __ Sbc(temp, temp, xzr);
__ Strh(temp, MemOperand(kArtMethodRegister, ArtMethod::HotnessCountOffset().Int32Value()));
}
@@ -3175,8 +3177,10 @@
Register temp1 = temps.AcquireX();
Register temp2 = temps.AcquireX();
__ Ldr(temp1, MemOperand(sp, 0));
- __ Ldrh(temp2, MemOperand(temp1, ArtMethod::HotnessCountOffset().Int32Value()));
- __ Add(temp2, temp2, 1);
+ __ Ldrsh(temp2, MemOperand(temp1, ArtMethod::HotnessCountOffset().Int32Value()));
+ __ Adds(temp2, temp2, 1);
+ // Subtract carry if it overflowed.
+ __ Sbc(temp2, temp2, xzr);
__ Strh(temp2, MemOperand(temp1, ArtMethod::HotnessCountOffset().Int32Value()));
}
GenerateSuspendCheck(info->GetSuspendCheck(), successor);