Skip to content
This repository has been archived by the owner. It is now read-only.
Permalink
Browse files
8257815: Replace global log2 functions with efficient implementations
Reviewed-by: kbarrett, stefank
  • Loading branch information
cl4es committed Jan 4, 2021
1 parent f80c63b commit 9d160aa1b7ca0260a6e42c554b3afb1e34513c96
Showing with 182 additions and 208 deletions.
  1. +1 −1 src/hotspot/cpu/aarch64/c1_LIRAssembler_aarch64.cpp
  2. +1 −1 src/hotspot/cpu/aarch64/gc/z/zGlobals_aarch64.cpp
  3. +2 −2 src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp
  4. +1 −1 src/hotspot/cpu/arm/c1_LIRAssembler_arm.cpp
  5. +2 −2 src/hotspot/cpu/arm/c1_LIRGenerator_arm.cpp
  6. +3 −3 src/hotspot/cpu/ppc/assembler_ppc.cpp
  7. +1 −1 src/hotspot/cpu/ppc/c1_LIRAssembler_ppc.cpp
  8. +2 −2 src/hotspot/cpu/ppc/c1_LIRGenerator_ppc.cpp
  9. +1 −1 src/hotspot/cpu/ppc/macroAssembler_ppc.inline.hpp
  10. +18 −21 src/hotspot/cpu/ppc/ppc.ad
  11. +3 −3 src/hotspot/cpu/ppc/templateTable_ppc_64.cpp
  12. +2 −2 src/hotspot/cpu/s390/c1_LIRAssembler_s390.cpp
  13. +2 −2 src/hotspot/cpu/s390/c1_LIRGenerator_s390.cpp
  14. +1 −1 src/hotspot/cpu/x86/c1_LIRAssembler_x86.cpp
  15. +2 −2 src/hotspot/cpu/x86/c1_LIRGenerator_x86.cpp
  16. +1 −1 src/hotspot/cpu/x86/gc/z/zGlobals_x86.cpp
  17. +1 −1 src/hotspot/cpu/x86/interp_masm_x86.cpp
  18. +1 −1 src/hotspot/cpu/x86/vm_version_x86.cpp
  19. +4 −4 src/hotspot/cpu/x86/x86_64.ad
  20. +1 −1 src/hotspot/share/compiler/compilationPolicy.cpp
  21. +2 −7 src/hotspot/share/compiler/compilerDefinitions.cpp
  22. +2 −2 src/hotspot/share/compiler/tieredThresholdPolicy.cpp
  23. +1 −1 src/hotspot/share/gc/g1/g1BiasedArray.hpp
  24. +2 −1 src/hotspot/share/gc/g1/g1FreeIdSet.cpp
  25. +3 −2 src/hotspot/share/gc/g1/g1RemSet.cpp
  26. +2 −2 src/hotspot/share/gc/g1/heapRegion.cpp
  27. +2 −1 src/hotspot/share/gc/g1/heapRegionRemSet.cpp
  28. +2 −1 src/hotspot/share/gc/shared/partialArrayTaskStepper.cpp
  29. +2 −1 src/hotspot/share/gc/shenandoah/shenandoahConcurrentMark.inline.hpp
  30. +2 −1 src/hotspot/share/gc/shenandoah/shenandoahHeapRegion.cpp
  31. +1 −1 src/hotspot/share/gc/shenandoah/shenandoahNumberSeq.cpp
  32. +1 −1 src/hotspot/share/gc/z/zHeuristics.cpp
  33. +8 −8 src/hotspot/share/opto/divnode.cpp
  34. +15 −17 src/hotspot/share/opto/mulnode.cpp
  35. +1 −1 src/hotspot/share/opto/parse2.cpp
  36. +1 −1 src/hotspot/share/opto/vectorIntrinsics.cpp
  37. +0 −53 src/hotspot/share/utilities/globalDefinitions.hpp
  38. +1 −2 src/hotspot/share/utilities/hashtable.cpp
  39. +42 −17 src/hotspot/share/utilities/powerOfTwo.hpp
  40. +0 −35 test/hotspot/gtest/utilities/test_globalDefinitions.cpp
  41. +42 −0 test/hotspot/gtest/utilities/test_powerOfTwo.cpp
@@ -1772,7 +1772,7 @@ void LIR_Assembler::arith_op(LIR_Code code, LIR_Opr left, LIR_Opr right, LIR_Opr
// move lreg_lo to dreg if divisor is 1
__ mov(dreg, lreg_lo);
} else {
unsigned int shift = exact_log2_long(c);
unsigned int shift = log2i_exact(c);
// use rscratch1 as intermediate result register
__ asr(rscratch1, lreg_lo, 63);
__ add(rscratch1, lreg_lo, rscratch1, Assembler::LSR, 64 - shift);
@@ -200,7 +200,7 @@ size_t ZPlatformAddressOffsetBits() {
const size_t max_address_offset_bits = valid_max_address_offset_bits - 3;
const size_t min_address_offset_bits = max_address_offset_bits - 2;
const size_t address_offset = round_up_power_of_2(MaxHeapSize * ZVirtualToPhysicalRatio);
const size_t address_offset_bits = log2_intptr(address_offset);
const size_t address_offset_bits = log2i_exact(address_offset);
return clamp(address_offset_bits, min_address_offset_bits, max_address_offset_bits);
}

@@ -302,7 +302,7 @@ void MacroAssembler::safepoint_poll(Label& slow_path, bool at_return, bool acqui
cmp(in_nmethod ? sp : rfp, rscratch1);
br(Assembler::HI, slow_path);
} else {
tbnz(rscratch1, exact_log2(SafepointMechanism::poll_bit()), slow_path);
tbnz(rscratch1, log2i_exact(SafepointMechanism::poll_bit()), slow_path);
}
}

@@ -3996,7 +3996,7 @@ MacroAssembler::KlassDecodeMode MacroAssembler::klass_decode_mode() {
if (operand_valid_for_logical_immediate(
/*is32*/false, (uint64_t)CompressedKlassPointers::base())) {
const uint64_t range_mask =
(1ULL << log2_intptr(CompressedKlassPointers::range())) - 1;
(1ULL << log2i(CompressedKlassPointers::range())) - 1;
if (((uint64_t)CompressedKlassPointers::base() & range_mask) == 0) {
return (_klass_decode_mode = KlassDecodeXor);
}
@@ -848,7 +848,7 @@ void LIR_Assembler::emit_op3(LIR_Op3* op) {
__ add_32(dest, left, AsmOperand(left, lsr, 31));
__ asr_32(dest, dest, 1);
} else if (c != (int) 0x80000000) {
int power = log2_intptr(c);
int power = log2i_exact(c);
__ asr_32(Rtemp, left, 31);
__ add_32(dest, left, AsmOperand(Rtemp, lsr, 32-power)); // dest = left + (left < 0 ? 2^power - 1 : 0);
__ asr_32(dest, dest, power); // dest = dest >>> power;
@@ -329,12 +329,12 @@ void LIRGenerator::cmp_reg_mem(LIR_Condition condition, LIR_Opr reg, LIR_Opr bas
bool LIRGenerator::strength_reduce_multiply(LIR_Opr left, jint c, LIR_Opr result, LIR_Opr tmp) {
assert(left != result, "should be different registers");
if (is_power_of_2(c + 1)) {
LIR_Address::Scale scale = (LIR_Address::Scale) log2_intptr(c + 1);
LIR_Address::Scale scale = (LIR_Address::Scale) log2i_exact(c + 1);
LIR_Address* addr = new LIR_Address(left, left, scale, 0, T_INT);
__ sub(LIR_OprFact::address(addr), left, result); // rsb with shifted register
return true;
} else if (is_power_of_2(c - 1)) {
LIR_Address::Scale scale = (LIR_Address::Scale) log2_intptr(c - 1);
LIR_Address::Scale scale = (LIR_Address::Scale) log2i_exact(c - 1);
LIR_Address* addr = new LIR_Address(left, left, scale, 0, T_INT);
__ add(left, LIR_OprFact::address(addr), result); // add with shifted register
return true;
@@ -81,13 +81,13 @@ int Assembler::branch_destination(int inst, int pos) {
void Assembler::andi(Register a, Register s, const long ui16) {
if (is_power_of_2(((jlong) ui16)+1)) {
// pow2minus1
clrldi(a, s, 64-log2_long((((jlong) ui16)+1)));
clrldi(a, s, 64 - log2i_exact((((jlong) ui16)+1)));
} else if (is_power_of_2((jlong) ui16)) {
// pow2
rlwinm(a, s, 0, 31-log2_long((jlong) ui16), 31-log2_long((jlong) ui16));
rlwinm(a, s, 0, 31 - log2i_exact((jlong) ui16), 31 - log2i_exact((jlong) ui16));
} else if (is_power_of_2((jlong)-ui16)) {
// negpow2
clrrdi(a, s, log2_long((jlong)-ui16));
clrrdi(a, s, log2i_exact((jlong)-ui16));
} else {
assert(is_uimm(ui16, 16), "must be 16-bit unsigned immediate");
andi_(a, s, ui16);
@@ -341,7 +341,7 @@ void LIR_Assembler::arithmetic_idiv(LIR_Code code, LIR_Opr left, LIR_Opr right,

} else if (is_power_of_2(divisor)) {
// Convert division by a power of two into some shifts and logical operations.
int log2 = log2_intptr(divisor);
int log2 = log2i_exact(divisor);

// Round towards 0.
if (divisor == 2) {
@@ -293,11 +293,11 @@ void LIRGenerator::cmp_reg_mem(LIR_Condition condition, LIR_Opr reg, LIR_Opr bas
bool LIRGenerator::strength_reduce_multiply(LIR_Opr left, jint c, LIR_Opr result, LIR_Opr tmp) {
assert(left != result, "should be different registers");
if (is_power_of_2(c + 1)) {
__ shift_left(left, log2_int(c + 1), result);
__ shift_left(left, log2i_exact(c + 1), result);
__ sub(result, left, result);
return true;
} else if (is_power_of_2(c - 1)) {
__ shift_left(left, log2_int(c - 1), result);
__ shift_left(left, log2i_exact(c - 1), result);
__ add(result, left, result);
return true;
}
@@ -59,7 +59,7 @@ inline int MacroAssembler::get_ld_largeoffset_offset(address a) {
inline void MacroAssembler::round_to(Register r, int modulus) {
assert(is_power_of_2((jlong)modulus), "must be power of 2");
addi(r, r, modulus-1);
clrrdi(r, r, log2_long((jlong)modulus));
clrrdi(r, r, log2i_exact((jlong)modulus));
}

// Move register if destination register and target register are different.
@@ -4042,23 +4042,23 @@ operand immIhi16() %{
%}

operand immInegpow2() %{
predicate(is_power_of_2((jlong) (julong) (juint) (-(n->get_int()))));
predicate(is_power_of_2(-(juint)(n->get_int())));
match(ConI);
op_cost(0);
format %{ %}
interface(CONST_INTER);
%}

operand immIpow2minus1() %{
predicate(is_power_of_2((((jlong) (n->get_int()))+1)));
predicate(is_power_of_2((juint)(n->get_int()) + 1u));
match(ConI);
op_cost(0);
format %{ %}
interface(CONST_INTER);
%}

operand immIpowerOf2() %{
predicate(is_power_of_2((((jlong) (julong) (juint) (n->get_int())))));
predicate(is_power_of_2((juint)(n->get_int())));
match(ConI);
op_cost(0);
format %{ %}
@@ -4292,16 +4292,15 @@ operand immLhighest16() %{
%}

operand immLnegpow2() %{
predicate(is_power_of_2((jlong)-(n->get_long())));
predicate(is_power_of_2(-(julong)(n->get_long())));
match(ConL);
op_cost(0);
format %{ %}
interface(CONST_INTER);
%}

operand immLpow2minus1() %{
predicate(is_power_of_2((((jlong) (n->get_long()))+1)) &&
(n->get_long() != (jlong)0xffffffffffffffffL));
predicate(is_power_of_2((julong)(n->get_long()) + 1ull));
match(ConL);
op_cost(0);
format %{ %}
@@ -9076,9 +9075,8 @@ instruct lShiftI_andI_immInegpow2_imm5(iRegIdst dst, iRegIsrc src1, immInegpow2
format %{ "RLWINM $dst, lShiftI(AndI($src1, $src2), $src3)" %}
size(4);
ins_encode %{
long src2 = $src2$$constant;
long src3 = $src3$$constant;
long maskbits = src3 + log2_long((jlong) (julong) (juint) -src2);
long maskbits = src3 + log2i_exact(-(juint)$src2$$constant);
if (maskbits >= 32) {
__ li($dst$$Register, 0); // addi
} else {
@@ -9096,9 +9094,8 @@ instruct lShiftI_andI_immInegpow2_rShiftI_imm5(iRegIdst dst, iRegIsrc src1, immI
format %{ "RLWINM $dst, lShiftI(AndI(RShiftI($src1, $src3), $src2), $src3)" %}
size(4);
ins_encode %{
long src2 = $src2$$constant;
long src3 = $src3$$constant;
long maskbits = src3 + log2_long((jlong) (julong) (juint) -src2);
long maskbits = src3 + log2i_exact(-(juint)$src2$$constant);
if (maskbits >= 32) {
__ li($dst$$Register, 0); // addi
} else {
@@ -9366,7 +9363,7 @@ instruct andI_urShiftI_regI_immI_immIpow2minus1(iRegIdst dst, iRegIsrc src1, imm
size(4);
ins_encode %{
int rshift = ($src2$$constant) & 0x1f;
int length = log2_long(((jlong) $src3$$constant) + 1);
int length = log2i_exact((juint)$src3$$constant + 1u);
if (rshift + length > 32) {
// if necessary, adjust mask to omit rotated bits.
length = 32 - rshift;
@@ -9384,7 +9381,7 @@ instruct andL_urShiftL_regL_immI_immLpow2minus1(iRegLdst dst, iRegLsrc src1, imm
size(4);
ins_encode %{
int rshift = ($src2$$constant) & 0x3f;
int length = log2_long(((jlong) $src3$$constant) + 1);
int length = log2i_exact((julong)$src3$$constant + 1ull);
if (rshift + length > 64) {
// if necessary, adjust mask to omit rotated bits.
length = 64 - rshift;
@@ -9788,7 +9785,7 @@ instruct andI_reg_immInegpow2(iRegIdst dst, iRegIsrc src1, immInegpow2 src2) %{
format %{ "ANDWI $dst, $src1, $src2" %}
size(4);
ins_encode %{
__ clrrdi($dst$$Register, $src1$$Register, log2_long((jlong)(julong)(juint)-($src2$$constant)));
__ clrrdi($dst$$Register, $src1$$Register, log2i_exact(-(juint)$src2$$constant));
%}
ins_pipe(pipe_class_default);
%}
@@ -9798,7 +9795,7 @@ instruct andI_reg_immIpow2minus1(iRegIdst dst, iRegIsrc src1, immIpow2minus1 src
format %{ "ANDWI $dst, $src1, $src2" %}
size(4);
ins_encode %{
__ clrldi($dst$$Register, $src1$$Register, 64-log2_long((((jlong) $src2$$constant)+1)));
__ clrldi($dst$$Register, $src1$$Register, 64 - log2i_exact((juint)$src2$$constant + 1u));
%}
ins_pipe(pipe_class_default);
%}
@@ -9809,8 +9806,8 @@ instruct andI_reg_immIpowerOf2(iRegIdst dst, iRegIsrc src1, immIpowerOf2 src2) %
format %{ "ANDWI $dst, $src1, $src2" %}
size(4);
ins_encode %{
__ rlwinm($dst$$Register, $src1$$Register, 0,
(31-log2_long((jlong) $src2$$constant)) & 0x1f, (31-log2_long((jlong) $src2$$constant)) & 0x1f);
int bitpos = 31 - log2i_exact((juint)$src2$$constant);
__ rlwinm($dst$$Register, $src1$$Register, 0, bitpos, bitpos);
%}
ins_pipe(pipe_class_default);
%}
@@ -9848,7 +9845,7 @@ instruct andL_reg_immLnegpow2(iRegLdst dst, iRegLsrc src1, immLnegpow2 src2) %{
format %{ "ANDDI $dst, $src1, $src2" %}
size(4);
ins_encode %{
__ clrrdi($dst$$Register, $src1$$Register, log2_long((jlong)-$src2$$constant));
__ clrrdi($dst$$Register, $src1$$Register, log2i_exact(-(julong)$src2$$constant));
%}
ins_pipe(pipe_class_default);
%}
@@ -9858,7 +9855,7 @@ instruct andL_reg_immLpow2minus1(iRegLdst dst, iRegLsrc src1, immLpow2minus1 src
format %{ "ANDDI $dst, $src1, $src2" %}
size(4);
ins_encode %{
__ clrldi($dst$$Register, $src1$$Register, 64-log2_long((((jlong) $src2$$constant)+1)));
__ clrldi($dst$$Register, $src1$$Register, 64 - log2i_exact((julong)$src2$$constant + 1ull));
%}
ins_pipe(pipe_class_default);
%}
@@ -9871,7 +9868,7 @@ instruct convL2I_andL_reg_immLpow2minus1(iRegIdst dst, iRegLsrc src1, immLpow2mi
format %{ "ANDDI $dst, $src1, $src2 \t// long + l2i" %}
size(4);
ins_encode %{
__ clrldi($dst$$Register, $src1$$Register, 64-log2_long((((jlong) $src2$$constant)+1)));
__ clrldi($dst$$Register, $src1$$Register, 64 - log2i_exact((julong)$src2$$constant + 1ull));
%}
ins_pipe(pipe_class_default);
%}
@@ -10459,7 +10456,7 @@ instruct convI2Bool_andI_reg_immIpowerOf2(iRegIdst dst, iRegIsrc src, immIpowerO
format %{ "RLWINM $dst, $src, $mask \t// convI2B(AndI($src, $mask))" %}
size(4);
ins_encode %{
__ rlwinm($dst$$Register, $src$$Register, (32-log2_long((jlong)$mask$$constant)) & 0x1f, 31, 31);
__ rlwinm($dst$$Register, $src$$Register, 32 - log2i_exact((juint)($mask$$constant)), 31, 31);
%}
ins_pipe(pipe_class_default);
%}
@@ -12154,7 +12151,7 @@ instruct align_addr(iRegPdst dst, iRegPsrc src, immLnegpow2 mask) %{
format %{ "ANDDI $dst, $src, $mask \t// next aligned address" %}
size(4);
ins_encode %{
__ clrrdi($dst$$Register, $src$$Register, log2_long((jlong)-$mask$$constant));
__ clrrdi($dst$$Register, $src$$Register, log2i_exact(-(julong)$mask$$constant));
%}
ins_pipe(pipe_class_default);
%}
@@ -1897,7 +1897,7 @@ void TemplateTable::tableswitch() {

// Align bcp.
__ addi(Rdef_offset_addr, R14_bcp, BytesPerInt);
__ clrrdi(Rdef_offset_addr, Rdef_offset_addr, log2_long((jlong)BytesPerInt));
__ clrrdi(Rdef_offset_addr, Rdef_offset_addr, LogBytesPerInt);

// Load lo & hi.
__ get_u4(Rlow_byte, Rdef_offset_addr, BytesPerInt, InterpreterMacroAssembler::Unsigned);
@@ -1956,7 +1956,7 @@ void TemplateTable::fast_linearswitch() {

// Align bcp.
__ addi(Rdef_offset_addr, R14_bcp, BytesPerInt);
__ clrrdi(Rdef_offset_addr, Rdef_offset_addr, log2_long((jlong)BytesPerInt));
__ clrrdi(Rdef_offset_addr, Rdef_offset_addr, LogBytesPerInt);

// Setup loop counter and limit.
__ get_u4(Rcount, Rdef_offset_addr, BytesPerInt, InterpreterMacroAssembler::Unsigned);
@@ -2044,7 +2044,7 @@ void TemplateTable::fast_binaryswitch() {

// Find Array start,
__ addi(Rarray, R14_bcp, 3 * BytesPerInt);
__ clrrdi(Rarray, Rarray, log2_long((jlong)BytesPerInt));
__ clrrdi(Rarray, Rarray, LogBytesPerInt);

// initialize i & j
__ li(Ri,0);
@@ -1802,7 +1802,7 @@ void LIR_Assembler::arithmetic_idiv(LIR_Code code, LIR_Opr left, LIR_Opr right,
Register treg1 = Z_R0_scratch;
Register treg2 = Z_R1_scratch;
jlong divisor = right->as_jlong();
jlong log_divisor = log2_long(right->as_jlong());
jlong log_divisor = log2i_exact(right->as_jlong());

if (divisor == min_jlong) {
// Min_jlong is special. Result is '0' except for min_jlong/min_jlong = 1.
@@ -1890,7 +1890,7 @@ void LIR_Assembler::arithmetic_idiv(LIR_Code code, LIR_Opr left, LIR_Opr right,
Register treg1 = Z_R0_scratch;
Register treg2 = Z_R1_scratch;
jlong divisor = right->as_jint();
jlong log_divisor = log2_long(right->as_jint());
jlong log_divisor = log2i_exact(right->as_jint());
__ move_reg_if_needed(dreg, T_LONG, lreg, T_INT); // sign extend
if (divisor == 2) {
__ z_srlg(treg2, dreg, 63); // dividend < 0 ? 1 : 0
@@ -228,12 +228,12 @@ bool LIRGenerator::strength_reduce_multiply(LIR_Opr left, jint c, LIR_Opr result
if (tmp->is_valid()) {
if (is_power_of_2(c + 1)) {
__ move(left, tmp);
__ shift_left(left, log2_int(c + 1), left);
__ shift_left(left, log2i_exact(c + 1), left);
__ sub(left, tmp, result);
return true;
} else if (is_power_of_2(c - 1)) {
__ move(left, tmp);
__ shift_left(left, log2_int(c - 1), left);
__ shift_left(left, log2i_exact(c - 1), left);
__ add(left, tmp, result);
return true;
}
@@ -2630,7 +2630,7 @@ void LIR_Assembler::arithmetic_idiv(LIR_Code code, LIR_Opr left, LIR_Opr right,
__ andl(rdx, divisor - 1);
__ addl(lreg, rdx);
}
__ sarl(lreg, log2_jint(divisor));
__ sarl(lreg, log2i_exact(divisor));
move_regs(lreg, dreg);
} else if (code == lir_irem) {
Label done;
@@ -249,12 +249,12 @@ bool LIRGenerator::strength_reduce_multiply(LIR_Opr left, jint c, LIR_Opr result
if (tmp->is_valid() && c > 0 && c < max_jint) {
if (is_power_of_2(c + 1)) {
__ move(left, tmp);
__ shift_left(left, log2_jint(c + 1), left);
__ shift_left(left, log2i_exact(c + 1), left);
__ sub(left, tmp, result);
return true;
} else if (is_power_of_2(c - 1)) {
__ move(left, tmp);
__ shift_left(left, log2_jint(c - 1), left);
__ shift_left(left, log2i_exact(c - 1), left);
__ add(left, tmp, result);
return true;
}
@@ -139,7 +139,7 @@ size_t ZPlatformAddressOffsetBits() {
const size_t min_address_offset_bits = 42; // 4TB
const size_t max_address_offset_bits = 44; // 16TB
const size_t address_offset = round_up_power_of_2(MaxHeapSize * ZVirtualToPhysicalRatio);
const size_t address_offset_bits = log2_intptr(address_offset);
const size_t address_offset_bits = log2i_exact(address_offset);
return clamp(address_offset_bits, min_address_offset_bits, max_address_offset_bits);
}

@@ -153,7 +153,7 @@ void InterpreterMacroAssembler::profile_arguments_type(Register mdp, Register ca
// CallTypeData/VirtualCallTypeData to reach its end. Non null
// if there's a return to profile.
assert(ReturnTypeEntry::static_cell_count() < TypeStackSlotEntries::per_arg_count(), "can't move past ret type");
shll(tmp, exact_log2(DataLayout::cell_size));
shll(tmp, log2i_exact((int)DataLayout::cell_size));
addptr(mdp, tmp);
}
movptr(Address(rbp, frame::interpreter_frame_mdp_offset * wordSize), mdp);
@@ -782,7 +782,7 @@ void VM_Version::get_processor_features() {
cores_per_cpu(), threads_per_core(),
cpu_family(), _model, _stepping, os::cpu_microcode_revision());
assert(res > 0, "not enough temporary space allocated");
assert(exact_log2_long(CPU_MAX_FEATURE) + 1 == sizeof(_features_names) / sizeof(char*), "wrong size features_names");
assert(log2i_exact((uint64_t)CPU_MAX_FEATURE) + 1 == sizeof(_features_names) / sizeof(char*), "wrong size features_names");
insert_features_names(buf + res, sizeof(buf) - res, _features_names);

_features_string = os::strdup(buf);

0 comments on commit 9d160aa

Please sign in to comment.