LLVM: Add short fallback for get_known_bits
Supports: when value is the immediate result of either a bitwise OR operation or a bitwise AND when either operands is a constant. Prevents some false positives when the value has PHI nodes in its ancestors.
This commit is contained in:
@@ -613,4 +613,138 @@ void cpu_translator::erase_stores(llvm::ArrayRef<llvm::Value*> args)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
llvm::KnownBits cpu_translator::get_known_bits_fallback(llvm::Value* value)
|
||||||
|
{
|
||||||
|
// TODO: Improve it - add support for integer addition/subtraction and more stuff
|
||||||
|
|
||||||
|
const auto type = value->getType();
|
||||||
|
|
||||||
|
if (!type->isVectorTy())
|
||||||
|
{
|
||||||
|
if (const auto it = llvm::dyn_cast<llvm::IntegerType>(type))
|
||||||
|
{
|
||||||
|
if (auto bin_inst = llvm::dyn_cast<llvm::BinaryOperator>(value))
|
||||||
|
{
|
||||||
|
llvm::Value* lhs = ensure(bin_inst->getOperand(0));
|
||||||
|
llvm::Value* rhs = ensure(bin_inst->getOperand(1));
|
||||||
|
|
||||||
|
llvm::ConstantInt* constant_value = llvm::dyn_cast<llvm::ConstantInt>(rhs) ? llvm::dyn_cast<llvm::ConstantInt>(rhs) : llvm::dyn_cast<llvm::ConstantInt>(lhs);
|
||||||
|
|
||||||
|
if (!constant_value)
|
||||||
|
{
|
||||||
|
return llvm::KnownBits(type->getScalarSizeInBits());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bin_inst->getOpcode() == llvm::Instruction::Or)
|
||||||
|
{
|
||||||
|
llvm::KnownBits ret(type->getScalarSizeInBits());
|
||||||
|
ret.One = constant_value->getValue();
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bin_inst->getOpcode() == llvm::Instruction::And)
|
||||||
|
{
|
||||||
|
llvm::KnownBits ret(type->getScalarSizeInBits());
|
||||||
|
ret.Zero = constant_value->getValue();
|
||||||
|
ret.Zero.flipAllBits();
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
return llvm::KnownBits(type->getScalarSizeInBits());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt::throw_exception("Bad KnownBits type: i%ux", type->getScalarSizeInBits());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (auto v = llvm::cast<llvm::FixedVectorType>(type); v->getScalarSizeInBits() * v->getNumElements() != 128)
|
||||||
|
{
|
||||||
|
// Unsupported
|
||||||
|
return llvm::KnownBits(type->getScalarSizeInBits());
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto cv = llvm::dyn_cast<llvm::ConstantDataVector>(value);
|
||||||
|
|
||||||
|
if (!cv)
|
||||||
|
{
|
||||||
|
if (llvm::isa<llvm::ConstantAggregateZero>(value))
|
||||||
|
{
|
||||||
|
llvm::KnownBits ret(type->getScalarSizeInBits());
|
||||||
|
ret.Zero.setAllBits();
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto original_value = peek_through_bitcasts(value);
|
||||||
|
const auto original_type = original_value->getType();
|
||||||
|
|
||||||
|
auto bin_inst = llvm::dyn_cast<llvm::BinaryOperator>(original_value);
|
||||||
|
|
||||||
|
if (!bin_inst)
|
||||||
|
{
|
||||||
|
return llvm::KnownBits(type->getScalarSizeInBits());
|
||||||
|
}
|
||||||
|
|
||||||
|
llvm::Value* lhs = ensure(bin_inst->getOperand(0));
|
||||||
|
llvm::Value* rhs = ensure(bin_inst->getOperand(1));
|
||||||
|
|
||||||
|
llvm::Value* constant_value = llvm::dyn_cast<llvm::ConstantDataVector>(rhs) ? llvm::dyn_cast<llvm::ConstantDataVector>(rhs) : llvm::dyn_cast<llvm::ConstantDataVector>(lhs);
|
||||||
|
|
||||||
|
if (!constant_value)
|
||||||
|
{
|
||||||
|
return llvm::KnownBits(value->getType()->getScalarSizeInBits());
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto [ok, v128_const] = get_const_vector(constant_value, -1);
|
||||||
|
|
||||||
|
ensure(ok);
|
||||||
|
|
||||||
|
llvm::APInt dest{};
|
||||||
|
|
||||||
|
auto combine_bits = [&](const auto& array, u32 size)
|
||||||
|
{
|
||||||
|
auto first = +array[0];
|
||||||
|
|
||||||
|
for (u32 i = 0; i < size; i++)
|
||||||
|
{
|
||||||
|
first &= +array[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
return first;
|
||||||
|
};
|
||||||
|
|
||||||
|
if (type->getScalarType()->isIntegerTy(8))
|
||||||
|
{
|
||||||
|
dest = llvm::APInt(8, combine_bits(v128_const._u8, 16));
|
||||||
|
}
|
||||||
|
else if (type->getScalarType()->isIntegerTy(16))
|
||||||
|
{
|
||||||
|
dest = llvm::APInt(16, combine_bits(v128_const._u16, 8));
|
||||||
|
}
|
||||||
|
else if (type->getScalarType()->isIntegerTy(32))
|
||||||
|
{
|
||||||
|
dest = llvm::APInt(32, combine_bits(v128_const._u32, 4));
|
||||||
|
}
|
||||||
|
else // if (type->getScalarType()->isIntegerTy(64))
|
||||||
|
{
|
||||||
|
return llvm::KnownBits(type->getScalarSizeInBits());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bin_inst->getOpcode() == llvm::Instruction::Or)
|
||||||
|
{
|
||||||
|
llvm::KnownBits ret(type->getScalarSizeInBits());
|
||||||
|
ret.One = dest;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bin_inst->getOpcode() == llvm::Instruction::And)
|
||||||
|
{
|
||||||
|
llvm::KnownBits ret(type->getScalarSizeInBits());
|
||||||
|
ret.Zero = dest;
|
||||||
|
ret.Zero.flipAllBits();
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
return llvm::KnownBits(type->getScalarSizeInBits());
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -4307,6 +4307,8 @@ template <typename T1, typename T2, typename T3>
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
llvm::KnownBits get_known_bits_fallback(llvm::Value* value);
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
llvm::KnownBits get_known_bits(T a)
|
llvm::KnownBits get_known_bits(T a)
|
||||||
{
|
{
|
||||||
@@ -4314,7 +4316,7 @@ template <typename T1, typename T2, typename T3>
|
|||||||
|
|
||||||
if (!is_known_bits_safe(value))
|
if (!is_known_bits_safe(value))
|
||||||
{
|
{
|
||||||
return llvm::KnownBits(value->getType()->getScalarSizeInBits());
|
return get_known_bits_fallback(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
return llvm::computeKnownBits(value, m_module->getDataLayout());
|
return llvm::computeKnownBits(value, m_module->getDataLayout());
|
||||||
|
|||||||
Reference in New Issue
Block a user