Get rid of Expression::Value and Expression:Reference, just folding in ValueOrRef directly.
This commit is contained in:
@@ -137,7 +137,7 @@ impl<M: Module> Backend<M> {
|
||||
// Look up the value for the variable. Because this might be a
|
||||
// global variable (and that requires special logic), we just turn
|
||||
// this into an `Expression` and re-use the logic in that implementation.
|
||||
let (val, vtype) = Expression::Reference(ann, var).into_crane(
|
||||
let (val, vtype) = ValueOrRef::Ref(ann, var).into_crane(
|
||||
&mut builder,
|
||||
&variable_table,
|
||||
&pre_defined_symbols,
|
||||
@@ -251,120 +251,53 @@ impl Expression {
|
||||
global_variables: &HashMap<String, (GlobalValue, ConstantType)>,
|
||||
) -> Result<(entities::Value, ConstantType), BackendError> {
|
||||
match self {
|
||||
// Values are pretty straightforward to compile, mostly because we only
|
||||
// have one type of variable, and it's an integer type.
|
||||
Expression::Value(_, val) => match val {
|
||||
Value::I8(_, v) => {
|
||||
Ok((builder.ins().iconst(types::I8, v as i64), ConstantType::I8))
|
||||
}
|
||||
Value::I16(_, v) => Ok((
|
||||
builder.ins().iconst(types::I16, v as i64),
|
||||
ConstantType::I16,
|
||||
)),
|
||||
Value::I32(_, v) => Ok((
|
||||
builder.ins().iconst(types::I32, v as i64),
|
||||
ConstantType::I32,
|
||||
)),
|
||||
Value::I64(_, v) => Ok((builder.ins().iconst(types::I64, v), ConstantType::I64)),
|
||||
Value::U8(_, v) => {
|
||||
Ok((builder.ins().iconst(types::I8, v as i64), ConstantType::U8))
|
||||
}
|
||||
Value::U16(_, v) => Ok((
|
||||
builder.ins().iconst(types::I16, v as i64),
|
||||
ConstantType::U16,
|
||||
)),
|
||||
Value::U32(_, v) => Ok((
|
||||
builder.ins().iconst(types::I32, v as i64),
|
||||
ConstantType::U32,
|
||||
)),
|
||||
Value::U64(_, v) => Ok((
|
||||
builder.ins().iconst(types::I64, v as i64),
|
||||
ConstantType::U64,
|
||||
)),
|
||||
},
|
||||
|
||||
Expression::Reference(_, name) => {
|
||||
// first we see if this is a local variable (which is nicer, from an
|
||||
// optimization point of view.)
|
||||
if let Some((local_var, etype)) = local_variables.get(&name) {
|
||||
return Ok((builder.use_var(*local_var), *etype));
|
||||
}
|
||||
|
||||
// then we check to see if this is a global reference, which requires us to
|
||||
// first lookup where the value is stored, and then load it.
|
||||
if let Some((global_var, etype)) = global_variables.get(name.as_ref()) {
|
||||
let cranelift_type = ir::Type::from(*etype);
|
||||
let val_ptr = builder.ins().symbol_value(cranelift_type, *global_var);
|
||||
return Ok((
|
||||
builder
|
||||
.ins()
|
||||
.load(cranelift_type, MemFlags::new(), val_ptr, 0),
|
||||
*etype,
|
||||
));
|
||||
}
|
||||
|
||||
// this should never happen, because we should have made sure that there are
|
||||
// no unbound variables a long time before this. but still ...
|
||||
Err(BackendError::VariableLookupFailure(name))
|
||||
}
|
||||
Expression::Atomic(x) => x.into_crane(builder, local_variables, global_variables),
|
||||
|
||||
Expression::Cast(_, target_type, expr) => {
|
||||
let (val, val_type) =
|
||||
expr.into_crane(builder, local_variables, global_variables)?;
|
||||
let (val, val_type) = expr.into_crane(builder, local_variables, global_variables)?;
|
||||
|
||||
match (val_type, &target_type) {
|
||||
(ConstantType::I8, Type::Primitive(PrimitiveType::I8)) => Ok((val, val_type)),
|
||||
(ConstantType::I8, Type::Primitive(PrimitiveType::I16)) => {
|
||||
Ok((builder.ins().sextend(types::I16, val), ConstantType::I16))
|
||||
}
|
||||
(ConstantType::I8, Type::Primitive(PrimitiveType::I32)) => {
|
||||
Ok((builder.ins().sextend(types::I32, val), ConstantType::I32))
|
||||
}
|
||||
(ConstantType::I8, Type::Primitive(PrimitiveType::I64)) => {
|
||||
Ok((builder.ins().sextend(types::I64, val), ConstantType::I64))
|
||||
}
|
||||
(ConstantType::I8, Type::Primitive(PrimitiveType::I16)) =>
|
||||
Ok((builder.ins().sextend(types::I16, val), ConstantType::I16)),
|
||||
(ConstantType::I8, Type::Primitive(PrimitiveType::I32)) =>
|
||||
Ok((builder.ins().sextend(types::I32, val), ConstantType::I32)),
|
||||
(ConstantType::I8, Type::Primitive(PrimitiveType::I64)) =>
|
||||
Ok((builder.ins().sextend(types::I64, val), ConstantType::I64)),
|
||||
|
||||
(ConstantType::I16, Type::Primitive(PrimitiveType::I16)) => Ok((val, val_type)),
|
||||
(ConstantType::I16, Type::Primitive(PrimitiveType::I32)) => {
|
||||
Ok((builder.ins().sextend(types::I32, val), ConstantType::I32))
|
||||
}
|
||||
(ConstantType::I16, Type::Primitive(PrimitiveType::I64)) => {
|
||||
Ok((builder.ins().sextend(types::I64, val), ConstantType::I64))
|
||||
}
|
||||
(ConstantType::I16, Type::Primitive(PrimitiveType::I32)) =>
|
||||
Ok((builder.ins().sextend(types::I32, val), ConstantType::I32)),
|
||||
(ConstantType::I16, Type::Primitive(PrimitiveType::I64)) =>
|
||||
Ok((builder.ins().sextend(types::I64, val), ConstantType::I64)),
|
||||
|
||||
(ConstantType::I32, Type::Primitive(PrimitiveType::I32)) => Ok((val, val_type)),
|
||||
(ConstantType::I32, Type::Primitive(PrimitiveType::I64)) => {
|
||||
Ok((builder.ins().sextend(types::I64, val), ConstantType::I64))
|
||||
}
|
||||
(ConstantType::I32, Type::Primitive(PrimitiveType::I64)) =>
|
||||
Ok((builder.ins().sextend(types::I64, val), ConstantType::I64)),
|
||||
|
||||
(ConstantType::I64, Type::Primitive(PrimitiveType::I64)) => Ok((val, val_type)),
|
||||
|
||||
(ConstantType::U8, Type::Primitive(PrimitiveType::U8)) => Ok((val, val_type)),
|
||||
(ConstantType::U8, Type::Primitive(PrimitiveType::U16)) => {
|
||||
Ok((builder.ins().uextend(types::I16, val), ConstantType::U16))
|
||||
}
|
||||
(ConstantType::U8, Type::Primitive(PrimitiveType::U32)) => {
|
||||
Ok((builder.ins().uextend(types::I32, val), ConstantType::U32))
|
||||
}
|
||||
(ConstantType::U8, Type::Primitive(PrimitiveType::U64)) => {
|
||||
Ok((builder.ins().uextend(types::I64, val), ConstantType::U64))
|
||||
}
|
||||
(ConstantType::U8, Type::Primitive(PrimitiveType::U16)) =>
|
||||
Ok((builder.ins().uextend(types::I16, val), ConstantType::U16)),
|
||||
(ConstantType::U8, Type::Primitive(PrimitiveType::U32)) =>
|
||||
Ok((builder.ins().uextend(types::I32, val), ConstantType::U32)),
|
||||
(ConstantType::U8, Type::Primitive(PrimitiveType::U64)) =>
|
||||
Ok((builder.ins().uextend(types::I64, val), ConstantType::U64)),
|
||||
|
||||
(ConstantType::U16, Type::Primitive(PrimitiveType::U16)) => Ok((val, val_type)),
|
||||
(ConstantType::U16, Type::Primitive(PrimitiveType::U32)) => {
|
||||
Ok((builder.ins().uextend(types::I32, val), ConstantType::U32))
|
||||
}
|
||||
(ConstantType::U16, Type::Primitive(PrimitiveType::U64)) => {
|
||||
Ok((builder.ins().uextend(types::I64, val), ConstantType::U64))
|
||||
}
|
||||
(ConstantType::U16, Type::Primitive(PrimitiveType::U32)) =>
|
||||
Ok((builder.ins().uextend(types::I32, val), ConstantType::U32)),
|
||||
(ConstantType::U16, Type::Primitive(PrimitiveType::U64)) =>
|
||||
Ok((builder.ins().uextend(types::I64, val), ConstantType::U64)),
|
||||
|
||||
(ConstantType::U32, Type::Primitive(PrimitiveType::U32)) => Ok((val, val_type)),
|
||||
(ConstantType::U32, Type::Primitive(PrimitiveType::U64)) => {
|
||||
Ok((builder.ins().uextend(types::I64, val), ConstantType::U64))
|
||||
}
|
||||
(ConstantType::U32, Type::Primitive(PrimitiveType::U64)) =>
|
||||
Ok((builder.ins().uextend(types::I64, val), ConstantType::U64)),
|
||||
|
||||
(ConstantType::U64, Type::Primitive(PrimitiveType::U64)) => Ok((val, val_type)),
|
||||
|
||||
|
||||
_ => Err(BackendError::InvalidTypeCast {
|
||||
from: val_type.into(),
|
||||
to: target_type,
|
||||
@@ -421,6 +354,63 @@ impl ValueOrRef {
|
||||
local_variables: &HashMap<ArcIntern<String>, (Variable, ConstantType)>,
|
||||
global_variables: &HashMap<String, (GlobalValue, ConstantType)>,
|
||||
) -> Result<(entities::Value, ConstantType), BackendError> {
|
||||
Expression::from(self).into_crane(builder, local_variables, global_variables)
|
||||
match self {
|
||||
// Values are pretty straightforward to compile, mostly because we only
|
||||
// have one type of variable, and it's an integer type.
|
||||
ValueOrRef::Value(_, val) => match val {
|
||||
Value::I8(_, v) => {
|
||||
Ok((builder.ins().iconst(types::I8, v as i64), ConstantType::I8))
|
||||
}
|
||||
Value::I16(_, v) => Ok((
|
||||
builder.ins().iconst(types::I16, v as i64),
|
||||
ConstantType::I16,
|
||||
)),
|
||||
Value::I32(_, v) => Ok((
|
||||
builder.ins().iconst(types::I32, v as i64),
|
||||
ConstantType::I32,
|
||||
)),
|
||||
Value::I64(_, v) => Ok((builder.ins().iconst(types::I64, v), ConstantType::I64)),
|
||||
Value::U8(_, v) => {
|
||||
Ok((builder.ins().iconst(types::I8, v as i64), ConstantType::U8))
|
||||
}
|
||||
Value::U16(_, v) => Ok((
|
||||
builder.ins().iconst(types::I16, v as i64),
|
||||
ConstantType::U16,
|
||||
)),
|
||||
Value::U32(_, v) => Ok((
|
||||
builder.ins().iconst(types::I32, v as i64),
|
||||
ConstantType::U32,
|
||||
)),
|
||||
Value::U64(_, v) => Ok((
|
||||
builder.ins().iconst(types::I64, v as i64),
|
||||
ConstantType::U64,
|
||||
)),
|
||||
},
|
||||
|
||||
ValueOrRef::Ref(_, name) => {
|
||||
// first we see if this is a local variable (which is nicer, from an
|
||||
// optimization point of view.)
|
||||
if let Some((local_var, etype)) = local_variables.get(&name) {
|
||||
return Ok((builder.use_var(*local_var), *etype));
|
||||
}
|
||||
|
||||
// then we check to see if this is a global reference, which requires us to
|
||||
// first lookup where the value is stored, and then load it.
|
||||
if let Some((global_var, etype)) = global_variables.get(name.as_ref()) {
|
||||
let cranelift_type = ir::Type::from(*etype);
|
||||
let val_ptr = builder.ins().symbol_value(cranelift_type, *global_var);
|
||||
return Ok((
|
||||
builder
|
||||
.ins()
|
||||
.load(cranelift_type, MemFlags::new(), val_ptr, 0),
|
||||
*etype,
|
||||
));
|
||||
}
|
||||
|
||||
// this should never happen, because we should have made sure that there are
|
||||
// no unbound variables a long time before this. but still ...
|
||||
Err(BackendError::VariableLookupFailure(name))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user