blob: ed6c059cc0db1f675bbf49a39ce3076584a6971e [file] [log] [blame]
// Copyright (c) 2024, the R8 project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.ir.analysis.value.arithmetic;
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.ir.analysis.value.AbstractValue;
import com.android.tools.r8.utils.BitUtils;
public class AbstractCalculator {
public static AbstractValue andIntegers(
AppView<?> appView, AbstractValue left, AbstractValue right) {
if (left.isZero()) {
return left;
}
if (right.isZero()) {
return right;
}
if (left.isSingleNumberValue() && right.isSingleNumberValue()) {
int result =
left.asSingleNumberValue().getIntValue() & right.asSingleNumberValue().getIntValue();
return appView.abstractValueFactory().createUncheckedSingleNumberValue(result);
}
if (left.hasDefinitelySetAndUnsetBitsInformation()
&& right.hasDefinitelySetAndUnsetBitsInformation()) {
return appView
.abstractValueFactory()
.createDefiniteBitsNumberValue(
left.getDefinitelySetIntBits() & right.getDefinitelySetIntBits(),
left.getDefinitelyUnsetIntBits() | right.getDefinitelyUnsetIntBits());
}
if (left.hasDefinitelySetAndUnsetBitsInformation()) {
return appView
.abstractValueFactory()
.createDefiniteBitsNumberValue(0, left.getDefinitelyUnsetIntBits());
}
if (right.hasDefinitelySetAndUnsetBitsInformation()) {
return appView
.abstractValueFactory()
.createDefiniteBitsNumberValue(0, right.getDefinitelyUnsetIntBits());
}
return AbstractValue.unknown();
}
public static AbstractValue orIntegers(
AppView<?> appView, AbstractValue left, AbstractValue right) {
if (left.isZero()) {
return right;
}
if (right.isZero()) {
return left;
}
if (left.isSingleNumberValue() && right.isSingleNumberValue()) {
int result =
left.asSingleNumberValue().getIntValue() | right.asSingleNumberValue().getIntValue();
return appView.abstractValueFactory().createUncheckedSingleNumberValue(result);
}
if (left.hasDefinitelySetAndUnsetBitsInformation()
&& right.hasDefinitelySetAndUnsetBitsInformation()) {
return appView
.abstractValueFactory()
.createDefiniteBitsNumberValue(
left.getDefinitelySetIntBits() | right.getDefinitelySetIntBits(),
left.getDefinitelyUnsetIntBits() & right.getDefinitelyUnsetIntBits());
}
if (left.hasDefinitelySetAndUnsetBitsInformation()) {
return appView
.abstractValueFactory()
.createDefiniteBitsNumberValue(left.getDefinitelySetIntBits(), 0);
}
if (right.hasDefinitelySetAndUnsetBitsInformation()) {
return appView
.abstractValueFactory()
.createDefiniteBitsNumberValue(right.getDefinitelySetIntBits(), 0);
}
return AbstractValue.unknown();
}
public static AbstractValue orIntegers(
AppView<?> appView,
AbstractValue first,
AbstractValue second,
AbstractValue third,
AbstractValue fourth) {
return orIntegers(
appView, first, orIntegers(appView, second, orIntegers(appView, third, fourth)));
}
public static AbstractValue shlIntegers(
AppView<?> appView, AbstractValue left, AbstractValue right) {
if (!right.isSingleNumberValue()) {
return AbstractValue.unknown();
}
int rightConst = right.asSingleNumberValue().getIntValue();
return shlIntegers(appView, left, rightConst);
}
public static AbstractValue shlIntegers(AppView<?> appView, AbstractValue left, int rightConst) {
if (rightConst == 0) {
return left;
}
if (left.isSingleNumberValue()) {
int result = left.asSingleNumberValue().getIntValue() << rightConst;
return appView.abstractValueFactory().createUncheckedSingleNumberValue(result);
}
if (left.hasDefinitelySetAndUnsetBitsInformation() && rightConst > 0) {
// Shift the known bits and add that we now know that the lowermost n bits are definitely
// unset. Note that when rightConst is 31, 1 << rightConst is Integer.MIN_VALUE. When
// subtracting 1 we overflow and get 0111...111, as desired.
return appView
.abstractValueFactory()
.createDefiniteBitsNumberValue(
left.getDefinitelySetIntBits() << rightConst,
(left.getDefinitelyUnsetIntBits() << rightConst) | ((1 << rightConst) - 1));
}
return AbstractValue.unknown();
}
public static AbstractValue shrIntegers(
AppView<?> appView, AbstractValue left, AbstractValue right) {
if (!right.isSingleNumberValue()) {
return AbstractValue.unknown();
}
int rightConst = right.asSingleNumberValue().getIntValue();
return shrIntegers(appView, left, rightConst);
}
public static AbstractValue shrIntegers(AppView<?> appView, AbstractValue left, int rightConst) {
if (rightConst == 0) {
return left;
}
if (left.isSingleNumberValue()) {
int result = left.asSingleNumberValue().getIntValue() >> rightConst;
return appView.abstractValueFactory().createUncheckedSingleNumberValue(result);
}
if (left.hasDefinitelySetAndUnsetBitsInformation()) {
return appView
.abstractValueFactory()
.createDefiniteBitsNumberValue(
left.getDefinitelySetIntBits() >> rightConst,
left.getDefinitelyUnsetIntBits() >> rightConst);
}
return AbstractValue.unknown();
}
public static AbstractValue ushrIntegers(
AppView<?> appView, AbstractValue left, AbstractValue right) {
if (!right.isSingleNumberValue()) {
return AbstractValue.unknown();
}
int rightConst = right.asSingleNumberValue().getIntValue();
if (rightConst == 0) {
return left;
}
if (left.isSingleNumberValue()) {
int result = left.asSingleNumberValue().getIntValue() >>> rightConst;
return appView.abstractValueFactory().createUncheckedSingleNumberValue(result);
}
if (left.hasDefinitelySetAndUnsetBitsInformation() && rightConst > 0) {
// Shift the known bits information and add that we now know that the uppermost n bits are
// definitely unset.
return appView
.abstractValueFactory()
.createDefiniteBitsNumberValue(
left.getDefinitelySetIntBits() >>> rightConst,
(left.getDefinitelyUnsetIntBits() >>> rightConst)
| (BitUtils.ONLY_SIGN_BIT_SET_MASK >> (rightConst - 1)));
}
return AbstractValue.unknown();
}
public static AbstractValue xorIntegers(
AppView<?> appView, AbstractValue left, AbstractValue right) {
if (left.isSingleNumberValue() && right.isSingleNumberValue()) {
int result =
left.asSingleNumberValue().getIntValue() ^ right.asSingleNumberValue().getIntValue();
return appView.abstractValueFactory().createUncheckedSingleNumberValue(result);
}
if (left.hasDefinitelySetAndUnsetBitsInformation()
&& right.hasDefinitelySetAndUnsetBitsInformation()) {
return appView
.abstractValueFactory()
.createDefiniteBitsNumberValue(
(left.getDefinitelySetIntBits() & right.getDefinitelyUnsetIntBits())
| (left.getDefinitelyUnsetIntBits() & right.getDefinitelySetIntBits()),
(left.getDefinitelySetIntBits() & right.getDefinitelySetIntBits())
| (left.getDefinitelyUnsetIntBits() & right.getDefinitelyUnsetIntBits()));
}
return AbstractValue.unknown();
}
}