Expr.cpp
#include "Expr.h"
#include "IROperator.h" // for lossless_cast()
namespace Halide {
namespace Internal {
const IntImm *IntImm::make(Type t, int64_t value) {
internal_assert(t.is_int() && t.is_scalar())
<< "IntImm must be a scalar Int\n";
internal_assert(t.bits() == 8 || t.bits() == 16 || t.bits() == 32 || t.bits() == 64)
<< "IntImm must be 8, 16, 32, or 64-bit\n";
// Normalize the value by dropping the high bits.
// Since left-shift of negative value is UB in C++, cast to uint64 first;
// it's unlikely any compilers we care about will misbehave, but UBSan will complain.
value = (int64_t)(((uint64_t)value) << (64 - t.bits()));
// Then sign-extending to get them back
value >>= (64 - t.bits());
IntImm *node = new IntImm;
node->type = t;
node->value = value;
return node;
}
const UIntImm *UIntImm::make(Type t, uint64_t value) {
internal_assert(t.is_uint() && t.is_scalar())
<< "UIntImm must be a scalar UInt\n";
internal_assert(t.bits() == 1 || t.bits() == 8 || t.bits() == 16 || t.bits() == 32 || t.bits() == 64)
<< "UIntImm must be 1, 8, 16, 32, or 64-bit\n";
// Normalize the value by dropping the high bits
value <<= (64 - t.bits());
value >>= (64 - t.bits());
UIntImm *node = new UIntImm;
node->type = t;
node->value = value;
return node;
}
const FloatImm *FloatImm::make(Type t, double value) {
internal_assert(t.is_float() && t.is_scalar())
<< "FloatImm must be a scalar Float\n";
FloatImm *node = new FloatImm;
node->type = t;
switch (t.bits()) {
case 16:
if (t.is_bfloat()) {
node->value = (double)((bfloat16_t)value);
} else {
node->value = (double)((float16_t)value);
}
break;
case 32:
node->value = (float)value;
break;
case 64:
node->value = value;
break;
default:
internal_error << "FloatImm must be 16, 32, or 64-bit\n";
}
return node;
}
const StringImm *StringImm::make(const std::string &val) {
StringImm *node = new StringImm;
node->type = type_of<const char *>();
node->value = val;
return node;
}
/** Check if for_type executes for loop iterations in parallel and unordered. */
bool is_unordered_parallel(ForType for_type) {
return (for_type == ForType::Parallel ||
for_type == ForType::GPUBlock ||
for_type == ForType::GPUThread);
}
/** Returns true if for_type executes for loop iterations in parallel. */
bool is_parallel(ForType for_type) {
return (is_unordered_parallel(for_type) ||
for_type == ForType::Vectorized ||
for_type == ForType::GPULane);
}
} // namespace Internal
Range::Range(const Expr &min_in, const Expr &extent_in)
: min(lossless_cast(Int(32), min_in)), extent(lossless_cast(Int(32), extent_in)) {
if (min_in.defined() && !min.defined()) {
user_error << "Min cannot be losslessly cast to an int32: " << min_in;
}
if (extent_in.defined() && !extent.defined()) {
user_error << "Extent cannot be losslessly cast to an int32: " << extent_in;
}
}
} // namespace Halide