blob: f116d566ae551f421e8d52810d2e82591001e8ed [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.
*/
/**
* @author Alexander Astapchuk
*/
/**
* @file
* @brief Val class declaration.
*/
#if !defined(__VAL_H_INCLUDED__)
#define __VAL_H_INCLUDED__
#include "enc.h"
namespace Jitrino {
namespace Jet {
/**
* @defgroup VA_ Attributes of Val items.
*/
/**
* @brief 'Non Zero' - an items tested to be non-zero/non-null.
*/
#define VA_NZ (0x00000001)
/**
* @brief An item was tested against negative-size and is either positive or
* zero.
*/
#define VA_NOT_NEG (0x00000002)
/**
* @brief Item was marked in GC map.
*/
#define VA_MARKED (0x00000004)
/**
* @brief Item has its copy in the memory, no need to sync it back.
*
* For example, if the item was just loaded from memory to register - no
* need to store it back, e.g. to outlive CALL. Surely, this attribute
* must be dropped on a defining operation.
*
* Currently unused.
*/
#define VA_FRESH (0x00000008)
/// @} // ~VA_
/**
* @brief Class Val represents various value items that may exist during
* compilation - immediate constants, memory references or values
* in registers.
*
* Val acts similar to Encoder's Opnd, but may carry extended information,
* that Opnd can't handle (e.g. attributes or float point and double items
* - both immediate-s and static constants in memory), and also has
* extended set of operations over it.
*/
class Val {
public:
/**
* Initializes the instance with \e dummy values.
*
* That is the instance gets #opnd_mem kind, but the type is jvoid,
* and the base register gets meaningless value ((AR)NOTHING).
*/
Val()
{
clear();
}
Val(jtype jt)
{
clear(); m_jt = jt;
}
Val(jtype jt, AR ar)
{
clear(); m_kind = opnd_reg; m_jt = jt; m_reg = ar;
}
Val(int ival)
{
clear(); m_kind = opnd_imm; m_jt = i32; m_lval = ival;
m_surviveCalls = true;
}
Val(jlong lval)
{
clear(); m_kind = opnd_imm; m_jt = i64; m_lval = lval;
m_surviveCalls = true;
}
Val(float fval, const void* caddr = NULL)
{
clear();
m_kind = opnd_imm; m_jt = flt32; m_fval = fval; m_caddr = caddr;
m_surviveCalls = true;
}
Val(double dval, const void* caddr = NULL)
{
clear();
m_kind = opnd_imm; m_jt = dbl64; m_dval = dval; m_caddr = caddr;
m_surviveCalls = true;
}
Val(jtype jt, const void* p)
{
clear();
m_kind = opnd_imm; assert(jt==jobj || jt==iplatf); m_jt = jt; m_pval = p;
}
Val(AR base, int disp, AR index = ar_x, unsigned scale=0)
{
clear();
m_kind = opnd_mem; m_jt = jvoid;
m_base = base; m_index = index;
m_scale = scale; m_disp = disp;
}
Val(jtype jt, AR base, int disp, AR index = ar_x, unsigned scale=0)
{
clear();
m_kind = opnd_mem; m_jt = jt;
m_base = base; m_index = index;
m_scale = scale; m_disp = disp;
}
#ifdef _IA32_
/**
* Special-purpose ctor, only exists on IA-32.
*
* Packs \c disp address into displacement.
*/
Val(jtype jt, AR base, void* disp)
{
clear();
m_kind = opnd_mem; m_jt = jt;
m_base = base; m_index = ar_x;
m_scale = 0; m_disp = (int)disp;
}
#endif
Val(const Opnd& op) {
clear();
m_jt = op.jt();
m_kind = op.kind();
if (is_reg()) {
m_reg = op.reg();
}
else if (is_mem()) {
m_base = op.base();
m_disp = op.disp();
m_index = op.index();
m_scale = op.scale();
}
else if (m_jt <= i32) {
m_lval = op.ival();
m_surviveCalls = true;
}
else if (m_jt == jobj) {
m_pval = (const void*)op.lval();
}
else {
assert(m_jt == i64);
m_lval = op.lval();
}
}
/**
* Returns kind of the Val.
*/
OpndKind kind(void) const { return m_kind; }
/**
* Returns type of the Val.
*/
jtype jt(void) const { return m_jt; }
/**
* Returns type of the Val.
*/
jtype type(void) const { return m_jt; }
/**
* Tests whether this Val was not initialized to a valid value (e.g.
* created via Val() ctor).
*/
bool is_dummy(void) const
{
return is_mem() && base() == (AR)NOTHING;
}
bool is_reg(void) const { return kind() == opnd_reg; }
bool is_mem(void) const { return kind() == opnd_mem; }
bool is_imm(void) const { return kind() == opnd_imm; }
bool uses(AR ar) const
{
if (is_mem()) return base() == ar || index() == ar;
if (is_reg()) return reg() == ar;
return false;
}
//
bool operator==(const Val& that) const
{
if (kind() != that.kind()) return false;
if (is_reg()) return reg() == that.reg();
if (is_mem()) {
// no test for jt()
return base() == that.base() &&
disp() == that.disp() &&
index() == that.index() &&
scale() == that.scale();
}
assert(is_imm());
if (jt() != that.jt()) return false;
return m_lval == that.m_lval;
}
bool operator!=(const Val& that) const
{
return !(*this==that);
}
/**
* Converts the Val into Opnd.
*/
Opnd as_opnd(void) const
{
return as_opnd(jt());
}
/**
* Converts the Val into Opnd, and sets its type to \c jt.
*/
Opnd as_opnd(jtype jt) const
{
if (is_mem()) {
return Opnd(jt, base(), disp(), index(), scale());
}
if (is_reg()) {
return Opnd(jt, reg());
}
return Opnd(jt, (int_ptr)lval());
}
//
AR reg(void) const { return m_kind == opnd_reg ? m_reg : ar_x; }
//
int ival(void) const { return is_imm() ? (int)m_lval : 0; }
jlong lval(void) const { return is_imm() ? m_lval : 0; }
//
float fval(void) const { return is_imm() ? m_fval : 0; }
double dval(void) const { return is_imm() ? m_dval : 0; }
const void* pval(void) const { return is_imm() ? m_pval : NULL; }
const void* caddr(void) const { return m_caddr; }
/**
* Sets current Val's property \b survive_calls.
* @return reference to this Val instance
* @todo Make the property as attribute ?
*/
Val& long_live(void) { m_surviveCalls = true; return *this; };
/**
* Sets a property whether this Val may outlive calls without any
* special preparation (e.g. static fiedls).
*/
void set_survive_calls(bool s = true) { m_surviveCalls = s; };
/**
* Tests whether this Val may outlive calls without any special
* preparation (e.g. static fiedls).
*/
bool get_survive_calls(void) const { return m_surviveCalls; };
/**
* Tests whether this Val may outlive calls without any special
* preparation (e.g. static fiedls).
*/
bool survive_calls(void) const { return m_surviveCalls; };
/**
* Converts Val into operand.
*/
void to_opnd(Opnd& op) {
m_kind = op.kind();
if (op.is_mem()) {
m_base = op.base();
m_disp = op.disp();
m_index = op.index();
m_scale = op.scale();
} else if (op.is_reg()){
m_reg = op.reg();
} else if (op.jt() <= i32) {
m_lval = op.ival();
m_surviveCalls = true;
} else if (op.jt() == jobj) {
m_pval = (const void*)op.lval();
} else if (op.jt() == flt32) {
m_fval = (float)op.ival();
} else if (op.jt() == dbl64) {
m_dval = (double)op.lval();
} else {
assert(op.jt() == i64);
m_lval = op.lval();
}
}
/**
* Converts Val into operand.
*/
void to_val(Val& value) {
m_jt = value.jt();
m_kind = value.kind();
m_surviveCalls = value.get_survive_calls();
m_caddr = value.caddr();
m_attrs = value.attrs();
if (value.is_mem()) {
m_base = value.base();
m_disp = value.disp();
m_index = value.index();
m_scale = value.scale();
} else if (value.is_reg()){
m_reg = value.reg();
} else if (value.jt() <= i32) {
m_lval = value.ival();
} else if (value.jt() == jobj) {
m_pval = value.pval();
} else if (value.jt() == flt32) {
m_fval = value.fval();
} else if (value.jt() == dbl64) {
m_dval = value.dval();
} else {
assert(value.jt() == i64);
m_lval = value.lval();
}
}
/**
* Converts Val into memory reference.
*/
void to_mem(AR base, int disp, AR index = ar_x, unsigned scale=0)
{
m_surviveCalls = false;
m_kind = opnd_mem;
m_base = base; m_index = index;
m_scale = scale; m_disp = disp;
}
/**
* Converts Val into register reference.
*/
void to_reg(AR ar)
{
m_surviveCalls = false;
m_kind = opnd_reg;
m_reg = ar;
}
/**
* Returns \link VA_ attributes \endlink.
*/
unsigned attrs(void) const { return m_attrs; }
/**
* Assigns \link VA_ attributes \endlink to this Val.
*/
void attrs(unsigned attrs)
{
m_attrs = attrs;
}
/**
* Adds the specified \link VA_ attributes \endlink to this Val.
*/
void set(unsigned attr)
{
m_attrs |= attr;
}
/**
* Removes the specified \link VA_ attributes \endlink to this Val.
*/
void clr(unsigned attrs)
{
m_attrs &= ~attrs;
}
/**
* Tests whether this Val has at least one given attribute.
*/
bool has(unsigned mask) const
{
return 0 != (m_attrs&mask);
}
AR base(void) const { return m_kind == opnd_mem ? m_base : ar_x; }
AR index(void) const { return m_kind == opnd_mem ? m_index : ar_x; }
int disp(void) const { return m_kind == opnd_mem ? m_disp : 0; }
unsigned scale(void) const { return m_kind == opnd_mem ? m_scale : 0; }
private:
void clear(void)
{
m_kind = opnd_mem;
m_jt = jvoid;
// As we are initializing Val to be mem, then set m_base
// to something meaningless, to avoid confusions with real
// memory operands which has only displacement.
m_base = (AR)NOTHING;
m_index = ar_x;
m_lval = 0;
m_scale = m_disp = 0;
//
m_caddr = NULL;
m_attrs = 0;
m_surviveCalls = false;
}
OpndKind m_kind;
jtype m_jt;
union {
AR m_reg;
int m_disp;
jlong m_lval;
double m_dval;
float m_fval;
const void* m_pval;
};
AR m_base;
AR m_index;
unsigned m_scale;
//
const void* m_caddr;
unsigned m_attrs;
bool m_surviveCalls;
};
}}; // ~namespace Jitrino::Jet
#endif // ~__VAL_H_INCLUDED__