blob: 30f9abf528f5491d9ce3919a2a1c988a012f78a3 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <ostream>
#include "abcdbounds.h"
#include "constantfolder.h"
#include "opndmap.h"
#include "simplifier.h"
namespace Jitrino {
namespace {
bool hasTypeBounds(Type::Tag srcTag, int64 &lb, int64 &ub);
int numbitsInType(Type::Tag typetag);
} // namespace
void AbcdReasons::print(::std::ostream &os) const
{
assert(facts.size() < 100);
StlSet<SsaTmpOpnd *>::const_iterator
iter = facts.begin(),
end = facts.end();
if (iter != end) {
os << "{";
{
SsaTmpOpnd *opnd = *iter;
opnd->print(os);
}
for (++iter ; iter != end; ++iter) {
SsaTmpOpnd *opnd = *iter;
os << " ";
opnd->print(os);
}
os << "}";
} else {
os << "NoReasons";
}
}
PiBound PiBound::add(const PiBound &other, bool is_signed) const {
assert(typetag == other.typetag);
if (isUndefined()) return *this;
if (other.isUndefined()) return other;
if ((!isUnknown()) && (!other.isUnknown())) {
if (var_part.isEmpty() || other.var_part.isEmpty()) {
// if one or no variables, can add
ConstInst::ConstValue v1;
ConstInst::ConstValue v2;
ConstInst::ConstValue res;
v1.i8 = const_part;
v2.i8 = other.const_part;
if (ConstantFolder::foldConstant(typetag, Op_Add, v1, v2, res, is_signed)) {
int64 c = (numbitsInType(typetag)==64) ? res.i8 : ((int64)res.i4);
if (!var_part.isEmpty()) {
return PiBound(typetag, var_multiple, var_part, c);
} else if (!other.var_part.isEmpty()) {
return PiBound(typetag, other.var_multiple, other.var_part, c);
} else
return PiBound(typetag, c);
}
} else if ((!var_part.isEmpty()) && (!other.var_part.isEmpty())
&& (var_part == other.var_part)) {
// if variables are the same, can add
ConstInst::ConstValue v1;
ConstInst::ConstValue v2;
ConstInst::ConstValue res;
v1.i8 = const_part;
v2.i8 = other.const_part;
if (ConstantFolder::foldConstant(typetag, Op_Add, v1, v2, res, is_signed)) {
int64 c = (numbitsInType(typetag)==64) ? res.i8 : ((int64)res.i4);
v1.i8 = var_multiple;
v2.i8 = other.var_multiple;
if (ConstantFolder::foldConstant(typetag, Op_Add, v1, v2, res, is_signed)){
int64 mult = ((numbitsInType(typetag)==64)
? res.i8
: ((int64)res.i4));
return PiBound(typetag, mult, var_part, c);
}
}
}
}
return getUnknown();
}
PiBound PiBound::neg () const {
if (isUnknown() || isUndefined()) return *this;
ConstInst::ConstValue v1;
ConstInst::ConstValue res;
v1.i8 = const_part;
if (ConstantFolder::foldConstant(typetag, Op_Neg, v1, res)) {
int64 c = (numbitsInType(typetag)==64) ? res.i8 : ((int64)res.i4);
v1.i8 = var_multiple;
if (ConstantFolder::foldConstant(typetag, Op_Neg, v1, res)) {
int64 mult = ((numbitsInType(typetag)==64)
? res.i8
: ((int64)res.i4));
return PiBound(typetag, mult, var_part, c);
}
}
return getUnknown();
}
PiBound PiBound::abs () const {
if (isUnknown() || isUndefined()) return *this;
if (var_multiple != 0) return getUnknown();
if (const_part < 0) {
int64 newconst_part = -const_part;
if (newconst_part == const_part) { //overflow
return getUnknown();
}
return PiBound(typetag, 0, 0, newconst_part);
}
return *this;
}
PiBound PiBound::mul(const PiBound &other, bool is_signed) const {
assert(typetag == other.typetag);
if (isUndefined()) return other;
else if (other.isUndefined()) return *this;
else if ((!isUnknown()) && (!other.isUnknown())) {
if (var_part.isEmpty() && other.var_part.isEmpty()) {
// if no variables, can multiply
ConstInst::ConstValue v1;
ConstInst::ConstValue v2;
ConstInst::ConstValue res;
v1.i8 = const_part;
v2.i8 = other.const_part;
if (ConstantFolder::foldConstant(typetag, Op_Mul, v1, v2, res, is_signed)) {
int64 c = (numbitsInType(typetag)==64) ? res.i8 : ((int64)res.i4);
return PiBound(typetag, c);
}
} else if (var_part.isEmpty() != other.var_part.isEmpty()) {
// if only 1 variable, can multiply
ConstInst::ConstValue v1;
ConstInst::ConstValue v2;
ConstInst::ConstValue res;
v1.i8 = const_part;
v2.i8 = other.const_part;
if (ConstantFolder::foldConstant(typetag, Op_Mul, v1, v2, res, is_signed)) {
int64 c = (numbitsInType(typetag)==64) ? res.i8 : ((int64)res.i4);
v1.i8 = var_part.isEmpty() ? other.var_multiple : var_multiple;
v2.i8 = var_part.isEmpty() ? const_part : other.const_part;
if (ConstantFolder::foldConstant(typetag, Op_Mul, v1, v2, res, is_signed)){
int64 mult = ((numbitsInType(typetag)==64)
? res.i8
: ((int64)res.i4));
return PiBound(typetag, mult, var_part, c);
}
}
}
}
return getUnknown();
}
PiBound
PiBound::cast(Type::Tag newtype, bool isLb) const {
if (isUnknown()) return PiBound(newtype, true);
else if (isUndefined()) return PiBound(newtype, false);
else if (var_multiple == 0) {
int64 lb, ub;
if (hasTypeBounds(newtype, lb, ub)) {
if (isLb) {
return PiBound(newtype, var_multiple, var_part,
::std::max(const_part, lb));
} else {
return PiBound(newtype, var_multiple, var_part,
::std::min(const_part, ub));
}
}
}
return *this;
}
bool
PiBound::isConstant() const
{
if (isUndefined()) return true;
if (isUnknown()) return false;
if (var_multiple != 0) return false;
return true;
}
bool
PiBound::isNonNegativeConstant() const
{
if (!isConstant()) return false;
return (const_part >= 0);
}
bool
PiBound::isNegativeConstant() const
{
if (!isConstant()) return false;
return (const_part < 0);
}
PiCondition
PiCondition::add(int64 constant) const
{
return PiCondition(lb.add(PiBound(lb.getType(), constant), true),
ub.add(PiBound(ub.getType(), constant), true));
}
PiCondition
PiCondition::neg() const
{
return PiCondition(ub.neg(),lb.neg());
}
PiCondition
PiCondition::mul(int64 constant) const
{
if (constant < 0) {
return PiCondition(ub.mul(PiBound(ub.getType(), constant), true),
lb.mul(PiBound(lb.getType(), constant), true));
} else {
return PiCondition(lb.mul(PiBound(lb.getType(), constant), true),
ub.mul(PiBound(ub.getType(), constant), true));
}
}
PiCondition
PiCondition::cast(Type::Tag newtype) const
{
return PiCondition(lb.cast(newtype, true),ub.cast(newtype, false));
}
// Print routines gathered here
::std::ostream &operator <<(::std::ostream &os, int64 val)
{
if (((int64)(int)val) == val) {
os << (int) val;
} else if (val == -val) {
os << "-9223372036854775808";
} else {
char buf[100];
int idx = 0;
bool sign = (val < (int64) 0);
if (sign) val = -val;
while (val > 0) {
buf[idx++] = '0' + ((char)(val%10));
val = val / 10;
}
if (sign) os << "-";
while (idx > 0) {
os << buf[--idx];
}
}
return os;
}
void
VarBound::print(::std::ostream &os) const
{
if (isEmpty()) {
os << "NULL";
} else {
the_var->print(os);
}
}
void
ConstBound::print(::std::ostream& os) const
{
switch (flag) {
case Const_PlusInfinity:
os << "+inf"; break;
case Const_MinusInfinity:
os << "-inf"; break;
case Const_IsConst:
os << (long) the_const; break;
case Const_IsNull:
assert(0);
os << "<<NULLCONST>>"; break;
}
}
void
PiBound::print(::std::ostream &os) const
{
if (isUnknown()) {
os << "unknown";
} else if (isUndefined()) {
os << "undef";
} else {
if (var_multiple) {
if (var_multiple != int64(1)) {
os << (long) var_multiple;
os << "*";
}
var_part.print(os);
if (const_part > 0)
os << "+";
}
if (const_part || !var_multiple) {
os << (long) const_part;
}
}
}
void
PiCondition::print(::std::ostream &os) const
{
os << "[";
lb.print(os);
os << ",";
ub.print(os);
os << "]";
}
PiCondition PiCondition::typeBounds(Type::Tag dstTag, Type::Tag srcTag)
{
int64 lb, ub;
if (hasTypeBounds(srcTag, lb, ub)) {
return PiCondition(PiBound(dstTag, lb), PiBound(dstTag, ub));
} else {
return PiCondition(PiBound(dstTag, true), PiBound(dstTag, true));
}
}
PiCondition PiCondition::convBounds(VarBound convVar)
{
assert(convVar.the_var != 0);
Inst *defInst = convVar.the_var->getInst();
assert(defInst && (defInst->getOpcode() == Op_Conv));
Opnd *srci = defInst->getSrc(0); // the source operand
Type::Tag srcType = srci->getType()->tag;
Type::Tag instrType = defInst->getType();
PiCondition bounds = PiCondition::typeBounds(instrType, srcType);
PiCondition bounds2 = bounds.cast(srcType);
return bounds2;
}
void printPiCondition(const PiCondition *cond, ::std::ostream &os)
{
cond->print(os);
}
PiBoundIter
VarBound::getPredecessors(bool boundingBelow, bool useReasons,
MemoryManager &mm) const
{
Inst *defInst = the_var ? (the_var->getInst()) : 0;
return PiBoundIter(defInst, boundingBelow, useReasons, mm);
}
bool
VarBound::isPhiVar() const {
Inst *defInst = the_var->getInst();
return (defInst && (defInst->getOpcode() == Op_Phi));
}
bool
VarBound::isMinMax(bool isMin) const {
Inst *defInst = the_var->getInst();
if (defInst){
if (isMin)
return (defInst->getOpcode() == Op_Min);
else
return (defInst->getOpcode() == Op_Max);
}
return false;
}
bool
VarBound::isConvVar() const {
Inst *defInst = the_var ? the_var->getInst() : 0;
return (defInst && (defInst->getOpcode() == Op_Conv));
}
VarBound
VarBound::getConvSource() const {
assert(isConvVar());
Inst *defInst = the_var->getInst();
return defInst->getSrc(0);
}
// true if type1 includes all values from type2
bool
VarBound::typeIncludes(Type::Tag type1, Type::Tag type2)
{
if (type1 == type2) return true;
int64 lb1, lb2, ub1, ub2;
bool hasBounds1, hasBounds2;
hasBounds1 = hasTypeBounds(type1, lb1, ub1);
hasBounds2 = hasTypeBounds(type2, lb2, ub2);
if ((!hasBounds1) || (!hasBounds2)) {
return false;
} else {
if ((lb1 <= lb2) && (ub2 <= ub1)) {
return true;
} else {
return false;
}
}
}
bool
VarBound::convPassesSource() const {
assert(isConvVar());
Inst *instr = the_var->getInst();
Opnd *srci = instr->getSrc(0); // the source operand
Type::Tag srcType = srci->getType()->tag;
Type::Tag dstType = the_var->getType()->tag;
Type::Tag instrType = instr->getType();
if (typeIncludes(dstType, instrType) &&
typeIncludes(instrType, srcType)) {
return true;
} else {
return false;
}
}
bool
VarBound::isConvexFunction() const {
if (the_var == 0) return false;
Inst *the_inst = the_var->getInst();
if(Op_Shr == the_inst->getOpcode()) {
Modifier mod = the_inst->getModifier();
assert(mod.hasSignedModifier());
if ((mod.getSignedModifier() == SignedOp) && ConstantFolder::isConstant(the_inst->getSrc(1)) ) {
return true;
}
}
return false;
}
ConstBound
VarBound::getConvexInputBound(bool isLB, ConstBound outputBound,
VarBound &inputVar) const
{
if (outputBound.isKnown()) {
Inst *the_inst = the_var->getInst();
switch (the_inst->getOpcode()) {
case Op_Shr: {
assert(the_inst->getOperation().isSignedModifierSigned());
Opnd *inputOpnd = the_inst->getSrc(0);
Opnd *shiftByOp = the_inst->getSrc(1);
Inst *shiftByInst = shiftByOp->getInst();
ConstInst *shiftByConstInst = shiftByInst->asConstInst();
if (shiftByConstInst != 0) {
U_32 shiftBy;
if (shiftByConstInst->getType() == Type::Int32) {
shiftBy = (U_32)shiftByConstInst->getValue().i4;
} else if (shiftByConstInst->getType() == Type::Int64) {
shiftBy = (U_32)shiftByConstInst->getValue().i8;
} else {
return ConstBound();
}
if (outputBound.isKnown()) {
Type::Tag typetag = the_inst->getType();
// must be signed
switch (typetag) {
case Type::Int32:
{
I_32 bound = outputBound.getInt32();
if (the_inst->getShiftMaskModifier() == ShiftMask_Masked)
shiftBy = shiftBy & 31;
I_32 input = bound << shiftBy;
if (!isLB) {
if (shiftBy < 31) {
input = input + ((I_32(1) << shiftBy) - 1);
} else {
input = 0xffffffff;
}
}
if (bound < 0) {
input = input | 0x80000000;
} else {
input = input & 0x7fffffff;
}
inputVar = VarBound(inputOpnd);
return ConstBound(input);
}
case Type::Int64:
{
int64 bound = outputBound.getInt64();
if (the_inst->getShiftMaskModifier() == ShiftMask_Masked)
shiftBy = shiftBy & 63;
int64 input = bound << shiftBy;
if (!isLB) {
if (shiftBy < 64) {
input = input + ((int64(1) << shiftBy) - 1);
} else {
input = __INT64_C(0xffffffffffffffff);
}
}
if (bound < 0) {
input = input | __INT64_C(0x8000000000000000);
} else {
input = input & __INT64_C(0x7fffffffffffffff);
}
inputVar = VarBound(inputOpnd);
return ConstBound(input);
}
default:
break;
}
}
}
return ConstBound();
}
default:
break;
}
assert(0);
return ConstBound();
} else {
return ConstBound();
}
}
void PiBoundIter::print(::std::ostream& outs) const
{
if (!instr) {
outs << "[]";
} else {
PiBoundIter acopy(*this);
outs << "[";
instr->print(outs);
outs << " : ";
current.print(outs);
while (++acopy) {
outs << ", ";
acopy.current.print(outs);
}
outs << "]";
}
}
bool PiBound::extractConstant(Type::Tag newtype, ConstInst *cinst0, PiBound &res)
{
assert(cinst0);
ConstInst::ConstValue cv = cinst0->getValue();
switch (cinst0->getType()) {
case Type::Int8: case Type::Int16: case Type::Int32:
{
I_32 c = cv.i4;
res = PiBound(newtype, int64(c));
return true;
}
case Type::Int64:
{
int64 c = cv.i8;
res = PiBound(newtype, int64(c));
return true;
}
case Type::UInt8: case Type::UInt16: case Type::UInt32:
{
U_32 c = (U_32) cv.i4;
res = PiBound(newtype, int64(uint64(c)));
return true;
}
case Type::UInt64:
{
uint64 c = cv.i8;
if (c < uint64(__INT64_C(0x8000000000000000))) {
res = PiBound(newtype, int64(c));
return true;
}
break;
}
default:
break;
}
return false;
}
Opnd *PiBoundIter::getConstantOpnd(Opnd *opnd)
{
if (ConstantFolder::isConstant(opnd)) {
return opnd;
} else {
return 0;
}
}
PiBound PiBoundIter::getBound(AbcdReasons *why0) {
if (why0) {
assert(why);
why0->addReasons(*why);
}
return current;
}
void PiBoundIter::init(bool useReasons)
{
assert(!why);
why = useReasons ? new AbcdReasons(mm) : 0;
}
void PiBoundIter::setCurrent()
{
if (isEmpty()) return;
if (!instr) return;
switch (instr->getOpcode()) {
case Op_Phi:
{
if (idx >= instr->getNumSrcOperands()) {
instr = 0;
if (why) why->clear();
} else {
Opnd *srci = instr->getSrc(idx);
VarBound vb(srci);
current = PiBound(instr->getType(), vb);
if (why) why->clear();
}
}
break;
case Op_TauPi:
{
// first, try to insert condition
TauPiInst *pInst = instr->asTauPiInst();
const PiCondition *cond = pInst->getCond();
Opnd *tauDepOpnd = pInst->getSrc(1);
SsaTmpOpnd *tauDep = tauDepOpnd->asSsaTmpOpnd();
assert(tauDep);
if (isLb) {
current = cond->getLb();
} else {
current = cond->getUb();
}
assert(!current.isUnknown());
if (current.isUndefined() && (idx >= 1)) {
instr = 0;
} else if ((!current.isUndefined()) && (idx == 0)) {
// use the Pi condition
if (why) why->addReason(tauDep);
} else if (idx <= 1) {
// effect of assignment
Opnd *srci = instr->getSrc(0);
VarBound vb(srci);
current = PiBound(instr->getType(), vb);
} else {
instr = 0;
}
}
break;
case Op_Add:
if (idx > 0) instr = 0;
else {
Opnd *op0 = instr->getSrc(0);
Opnd *op1 = instr->getSrc(1);
Opnd *constOpnd0 = getConstantOpnd(op0);
Opnd *constOpnd1 = getConstantOpnd(op1);
if ((constOpnd0 || constOpnd1)
&& (instr->getType() == Type::Int32)) {
int64 c;
// I assume we've done folding first
assert(!(constOpnd0 && constOpnd1));
if (constOpnd1) {
// swap the operands;
constOpnd0 = constOpnd1;
op1 = op0;
}
// now constOpnd0 is the constant opnd
// op1 is the non-constant opnd
Inst *inst0 = constOpnd0->getInst();
assert(inst0);
ConstInst *cinst0 = inst0->asConstInst();
assert(cinst0);
ConstInst::ConstValue cv = cinst0->getValue();
c = cv.i4;
VarBound vb(op1);
current = PiBound(instr->getType(), 1, vb, c);
} else
instr = 0;
}
break;
case Op_Sub:
if (idx > 0) instr = 0;
else {
Opnd *constOpnd = getConstantOpnd(instr->getSrc(1));
if (constOpnd
&& (instr->getType() == Type::Int32)) {
#ifndef NDEBUG
Opnd *op0 = instr->getSrc(0);
#endif
Opnd *op1 = constOpnd;
// now op1 should be constant
// I assume we've done folding first
assert(!getConstantOpnd(op0));
Inst *inst1 = op1->getInst();
assert(inst1);
ConstInst *cinst1 = inst1->asConstInst();
assert(cinst1);
ConstInst::ConstValue cv = cinst1->getValue();
I_32 c = cv.i4;
I_32 negc = -c;
if (neg_overflowed(negc,c)) { // overflowed
instr = 0;
} else {
VarBound vb(op1);
current = PiBound(instr->getType(), 1, vb, negc);
}
} else
instr = 0;
}
break;
case Op_Min:
if ((idx == 0) || (idx == 1)) {
Opnd *srci = instr->getSrc(idx); // the source operand
VarBound vb(srci);
current = PiBound(instr->getType(), vb);
} else {
instr = 0;
}
break;
case Op_Max:
if ((idx == 0) || (idx == 1)) {
Opnd *srci = instr->getSrc(idx); // the source operand
VarBound vb(srci);
current = PiBound(instr->getType(), vb);
} else {
instr = 0;
}
break;
case Op_Abs:
if (idx == 0) {
ConstBound cb((int64)0);
current = PiBound(instr->getType(), (int64) 0);
} else {
instr = 0;
}
break;
case Op_TauCheckBounds:
assert(0);
switch (idx) {
case 0:
{
Opnd *srci = instr->getSrc(1); // the index in;
VarBound vb(srci);
current = PiBound(srci->getType()->tag, vb); // result bounded by input index
}
break;
case 1:
if (isLb) {
current = PiBound(instr->getType(), int64(0)); // and 0
} else {
// the array length
Opnd *srci = instr->getSrc(0); // the array length
VarBound vb(srci);
current = PiBound(srci->getType()->tag, int64(1), vb, int64(-1)); // len - 1
}
break;
default:
instr = 0;
break;
};
break;
case Op_Copy:
if (idx == 0) {
Opnd *srci = instr->getSrc(0); // the source operand
VarBound vb(srci);
current = PiBound(instr->getType(), vb);
} else {
instr = 0;
}
break;
case Op_LdVar:
if (idx == 0) {
assert(instr->isVarAccess());
VarAccessInst *varInst = (VarAccessInst *)instr;
Opnd *srci = varInst->getSrc(0);
VarBound vb(srci);
current = PiBound(instr->getType(), vb);
} else {
instr = 0;
}
break;
case Op_StVar:
if (idx == 0) {
assert(instr->isVarAccess());
Opnd *srci = instr->getSrc(0);
VarBound vb(srci);
current = PiBound(instr->getType(), vb);
} else {
instr = 0;
}
break;
case Op_TauArrayLen:
if (idx == 0) {
if (isLb) {
// 0
current = PiBound(instr->getType(), int64(0));
} else {
current = PiBound(instr->getType(), int64(0x7fffffff)); // bounded by max int
}
} else {
instr = 0;
}
break;
case Op_LdConstant:
if (idx == 0) {
ConstInst *cinst0 = instr->asConstInst();
if (!PiBound::extractConstant(instr->getType(), cinst0, current)) {
instr = 0;
}
} else {
instr = 0;
}
break;
// could maybe do something with these:
case Op_TauRem:
if (idx == 0) {
Opnd *denom = instr->getSrc(1);
if (getConstantOpnd(denom)) {
Inst *consti1 = denom->getInst();
ConstInst *cinst1 = consti1->asConstInst();
assert(cinst1);
PiBound tmp(instr->getType(), true);
if (PiBound::extractConstant(instr->getType(), cinst1, current)) {
if (isLb) {
current = tmp.abs().neg();
} else {
current = tmp.abs();
}
}
} else {
instr = 0;
}
} else {
instr = 0;
}
break;
case Op_Conv:
if (idx == 0) {
Opnd *srci = instr->getSrc(0); // the source operand
Type::Tag srcType = srci->getType()->tag;
Type::Tag dstType = instr->getDst()->getType()->tag;
Type::Tag instrType = instr->getType();
PiCondition bounds = PiCondition::typeBounds(dstType, srcType);
PiCondition bounds2 = bounds.cast(instrType);
PiCondition bounds3 = bounds.cast(dstType);
if (isLb) {
current = bounds3.getLb();
} else {
current = bounds3.getUb();
}
} else {
instr = 0;
}
break;
case Op_Cmp:
if (idx == 0) {
current = PiBound(instr->getType(), int64(isLb ? 0 : 1));
} else {
instr = 0;
}
break;
case Op_Cmp3:
if (idx == 0) {
current = PiBound(instr->getType(), int64(isLb ? -1 : 1));
} else {
instr = 0;
}
break;
case Op_TauCheckNull:
case Op_TauCheckZero:
case Op_TauCheckCast:
case Op_TauHasType:
case Op_TauHasExactType:
case Op_TauIsNonNull:
assert(0);
break;
case Op_Or:
case Op_Not:
case Op_Neg:
case Op_DefArg:
case Op_NewArray:
case Op_TauCast:
case Op_TauAsType:
default:
instr = 0 ;
break;
}
}
namespace {
bool hasTypeBounds(Type::Tag srcTag, int64 &lb, int64 &ub)
{
switch (srcTag) {
case Type::Int8: lb = -int64(0x80); ub = 0x7f; return true;
case Type::Int16: lb = -int64(0x8000); ub = 0x7fff; return true;
case Type::Int32: lb = -int64(0x80000000); ub = 0x7fffffff; return true;
case Type::Int64:
lb = __INT64_C(0x8000000000000000);
ub = __INT64_C(0x7fffffffffffffff); return true;
case Type::UInt8: lb = 0; ub = 0x100; return true;
case Type::UInt16: lb = 0; ub = 0x10000; return true;
case Type::UInt32: lb = 0; ub = __INT64_C(0x100000000); return true;
default:
return false;
}
}
int numbitsInType(Type::Tag typetag) {
if ((typetag == Type::Int64) || (typetag == Type::UInt64) ||
((typetag == Type::IntPtr) && (sizeof(POINTER_SIZE_INT) == 8))) {
return 64;
} else {
return 32;
}
}
} // namespace
} // namespace Jitrino