Legalize entry block arguments to match ABI types.
Insert conversion code that reconstructs the original function argument types from the legalized ABI signature. Add abi::legalize_abi_value(). This function is used when adapting code to a legalized function signature.
This commit is contained in:
@@ -2,6 +2,9 @@
|
|||||||
test legalizer
|
test legalizer
|
||||||
isa riscv
|
isa riscv
|
||||||
|
|
||||||
|
; regex: V=v\d+
|
||||||
|
; regex: VX=vx\d+
|
||||||
|
|
||||||
function f(i32) {
|
function f(i32) {
|
||||||
sig0 = signature(i32) -> i32
|
sig0 = signature(i32) -> i32
|
||||||
|
|
||||||
@@ -21,3 +24,11 @@ function f(i32) {
|
|||||||
ebb0(v0: i32):
|
ebb0(v0: i32):
|
||||||
return_reg v0
|
return_reg v0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function int_split_args(i64) -> i64 {
|
||||||
|
ebb0(v0: i64):
|
||||||
|
; check: $ebb0($(v0l=$VX): i32, $(v0h=$VX): i32):
|
||||||
|
; check: iconcat_lohi $v0l, $v0h
|
||||||
|
v1 = iadd_imm v0, 1
|
||||||
|
return v0
|
||||||
|
}
|
||||||
|
|||||||
@@ -10,8 +10,8 @@ ebb0(v1: i64, v2: i64):
|
|||||||
v3 = band v1, v2
|
v3 = band v1, v2
|
||||||
return v3
|
return v3
|
||||||
}
|
}
|
||||||
; check: $(v1l=$V), $(v1h=$VX) = isplit_lohi $v1
|
; check: $(v1l=$V), $(v1h=$VX) = isplit_lohi
|
||||||
; check: $(v2l=$V), $(v2h=$VX) = isplit_lohi $v2
|
; check: $(v2l=$V), $(v2h=$VX) = isplit_lohi
|
||||||
; check: [R#ec
|
; check: [R#ec
|
||||||
; sameln: $(v3l=$V) = band $v1l, $v2l
|
; sameln: $(v3l=$V) = band $v1l, $v2l
|
||||||
; check: [R#ec
|
; check: [R#ec
|
||||||
@@ -23,8 +23,8 @@ ebb0(v1: i64, v2: i64):
|
|||||||
v3 = bor v1, v2
|
v3 = bor v1, v2
|
||||||
return v3
|
return v3
|
||||||
}
|
}
|
||||||
; check: $(v1l=$V), $(v1h=$VX) = isplit_lohi $v1
|
; check: $(v1l=$V), $(v1h=$VX) = isplit_lohi
|
||||||
; check: $(v2l=$V), $(v2h=$VX) = isplit_lohi $v2
|
; check: $(v2l=$V), $(v2h=$VX) = isplit_lohi
|
||||||
; check: [R#cc
|
; check: [R#cc
|
||||||
; sameln: $(v3l=$V) = bor $v1l, $v2l
|
; sameln: $(v3l=$V) = bor $v1l, $v2l
|
||||||
; check: [R#cc
|
; check: [R#cc
|
||||||
@@ -36,8 +36,8 @@ ebb0(v1: i64, v2: i64):
|
|||||||
v3 = bxor v1, v2
|
v3 = bxor v1, v2
|
||||||
return v3
|
return v3
|
||||||
}
|
}
|
||||||
; check: $(v1l=$V), $(v1h=$VX) = isplit_lohi $v1
|
; check: $(v1l=$V), $(v1h=$VX) = isplit_lohi
|
||||||
; check: $(v2l=$V), $(v2h=$VX) = isplit_lohi $v2
|
; check: $(v2l=$V), $(v2h=$VX) = isplit_lohi
|
||||||
; check: [R#8c
|
; check: [R#8c
|
||||||
; sameln: $(v3l=$V) = bxor $v1l, $v2l
|
; sameln: $(v3l=$V) = bxor $v1l, $v2l
|
||||||
; check: [R#8c
|
; check: [R#8c
|
||||||
@@ -52,8 +52,8 @@ ebb0(v1: i64, v2: i64):
|
|||||||
v3 = iadd v1, v2
|
v3 = iadd v1, v2
|
||||||
return v3
|
return v3
|
||||||
}
|
}
|
||||||
; check: $(v1l=$V), $(v1h=$VX) = isplit_lohi $v1
|
; check: $(v1l=$V), $(v1h=$VX) = isplit_lohi
|
||||||
; check: $(v2l=$V), $(v2h=$VX) = isplit_lohi $v2
|
; check: $(v2l=$V), $(v2h=$VX) = isplit_lohi
|
||||||
; check: [R#0c
|
; check: [R#0c
|
||||||
; sameln: $(v3l=$V) = iadd $v1l, $v2l
|
; sameln: $(v3l=$V) = iadd $v1l, $v2l
|
||||||
; check: $(c=$V) = icmp ult, $v3l, $v1l
|
; check: $(c=$V) = icmp ult, $v3l, $v1l
|
||||||
|
|||||||
@@ -3,23 +3,65 @@
|
|||||||
//! This module provides functions and data structures that are useful for implementing the
|
//! This module provides functions and data structures that are useful for implementing the
|
||||||
//! `TargetIsa::legalize_signature()` method.
|
//! `TargetIsa::legalize_signature()` method.
|
||||||
|
|
||||||
use ir::{ArgumentLoc, ArgumentType, Type};
|
use ir::{ArgumentLoc, ArgumentType, ArgumentExtension, Type};
|
||||||
|
use std::cmp::Ordering;
|
||||||
|
|
||||||
/// Legalization action to perform on a single argument or return value.
|
/// Legalization action to perform on a single argument or return value when converting a
|
||||||
|
/// signature.
|
||||||
///
|
///
|
||||||
/// An argument may go through a sequence of legalization steps before it reaches the final
|
/// An argument may go through a sequence of legalization steps before it reaches the final
|
||||||
/// `Assign` action.
|
/// `Assign` action.
|
||||||
|
#[derive(Clone, Copy)]
|
||||||
pub enum ArgAction {
|
pub enum ArgAction {
|
||||||
/// Assign the argument to the given location.
|
/// Assign the argument to the given location.
|
||||||
Assign(ArgumentLoc),
|
Assign(ArgumentLoc),
|
||||||
|
|
||||||
/// Split the argument into smaller parts, then call again.
|
/// Convert the argument, then call again.
|
||||||
///
|
///
|
||||||
/// This action can split an integer type into two smaller integer arguments, or it can split a
|
/// This action can split an integer type into two smaller integer arguments, or it can split a
|
||||||
/// SIMD vector into halves.
|
/// SIMD vector into halves.
|
||||||
///
|
Convert(ValueConversion),
|
||||||
/// Floating point scalar types can't be split.
|
}
|
||||||
Split,
|
|
||||||
|
/// Legalization action to be applied to a value that is being passed to or from a legalized ABI.
|
||||||
|
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||||
|
pub enum ValueConversion {
|
||||||
|
/// Split an integer types into low and high parts, using `isplit_lohi`.
|
||||||
|
IntSplit,
|
||||||
|
|
||||||
|
/// Split a vector type into halves with identical lane types.
|
||||||
|
VectorSplit,
|
||||||
|
|
||||||
|
/// Bit-cast to an integer type of the same size.
|
||||||
|
IntBits,
|
||||||
|
|
||||||
|
/// Sign-extend integer value to the required type.
|
||||||
|
Sext(Type),
|
||||||
|
|
||||||
|
/// Unsigned zero-extend value to the required type.
|
||||||
|
Uext(Type),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ValueConversion {
|
||||||
|
/// Apply this conversion to a type, return the converted type.
|
||||||
|
pub fn apply(self, ty: Type) -> Type {
|
||||||
|
match self {
|
||||||
|
ValueConversion::IntSplit => ty.half_width().expect("Integer type too small to split"),
|
||||||
|
ValueConversion::VectorSplit => ty.half_vector().expect("Not a vector"),
|
||||||
|
ValueConversion::IntBits => Type::int(ty.bits()).expect("Bad integer size"),
|
||||||
|
ValueConversion::Sext(nty) => nty,
|
||||||
|
ValueConversion::Uext(nty) => nty,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Is this a split conversion that results in two arguments?
|
||||||
|
pub fn is_split(self) -> bool {
|
||||||
|
match self {
|
||||||
|
ValueConversion::IntSplit => true,
|
||||||
|
ValueConversion::VectorSplit => true,
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Common trait for assigning arguments to registers or stack locations.
|
/// Common trait for assigning arguments to registers or stack locations.
|
||||||
@@ -53,20 +95,104 @@ pub fn legalize_args<AA: ArgAssigner>(args: &mut Vec<ArgumentType>, aa: &mut AA)
|
|||||||
argno += 1;
|
argno += 1;
|
||||||
}
|
}
|
||||||
// Split this argument into two smaller ones. Then revisit both.
|
// Split this argument into two smaller ones. Then revisit both.
|
||||||
ArgAction::Split => {
|
ArgAction::Convert(conv) => {
|
||||||
let new_arg = ArgumentType { value_type: split_type(arg.value_type), ..arg };
|
let new_arg = ArgumentType { value_type: conv.apply(arg.value_type), ..arg };
|
||||||
args[argno].value_type = new_arg.value_type;
|
args[argno].value_type = new_arg.value_type;
|
||||||
args.insert(argno + 1, new_arg);
|
if conv.is_split() {
|
||||||
|
args.insert(argno + 1, new_arg);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Given a value type that isn't legal, compute a replacement type half the size.
|
/// Determine the right action to take when passing a `have` value type to a call signature where
|
||||||
fn split_type(ty: Type) -> Type {
|
/// the next argument is `arg` which has a different value type.
|
||||||
if ty.is_int() {
|
///
|
||||||
ty.half_width().expect("Integer type too small to split")
|
/// The signature legalization process in `legalize_args` above can replace a single argument value
|
||||||
} else {
|
/// with multiple arguments of smaller types. It can also change the type of an integer argument to
|
||||||
ty.half_vector().expect("Can only split integers and vectors")
|
/// a larger integer type, requiring the smaller value to be sign- or zero-extended.
|
||||||
|
///
|
||||||
|
/// The legalizer needs to repair the values at all ABI boundaries:
|
||||||
|
///
|
||||||
|
/// - Incoming function arguments to the entry EBB.
|
||||||
|
/// - Function arguments passed to a call.
|
||||||
|
/// - Return values from a call.
|
||||||
|
/// - Return values passed to a return instruction.
|
||||||
|
///
|
||||||
|
/// The `legalize_abi_value` function helps the legalizer with the process. When the legalizer
|
||||||
|
/// needs to pass a pre-legalized `have` argument, but the ABI argument `arg` has a different value
|
||||||
|
/// type, `legalize_abi_value(have, arg)` tells the legalizer how to create the needed value type
|
||||||
|
/// for the argument.
|
||||||
|
///
|
||||||
|
/// It may be necessary to call `legalize_abi_value` more than once for a given argument before the
|
||||||
|
/// desired argument type appears. This will happen when a vector or integer type needs to be split
|
||||||
|
/// more than once, for example.
|
||||||
|
pub fn legalize_abi_value(have: Type, arg: &ArgumentType) -> ValueConversion {
|
||||||
|
let have_bits = have.bits();
|
||||||
|
let arg_bits = arg.value_type.bits();
|
||||||
|
|
||||||
|
match have_bits.cmp(&arg_bits) {
|
||||||
|
// We have fewer bits than the ABI argument.
|
||||||
|
Ordering::Less => {
|
||||||
|
assert!(have.is_int() && arg.value_type.is_int(),
|
||||||
|
"Can only extend integer values");
|
||||||
|
match arg.extension {
|
||||||
|
ArgumentExtension::Uext => ValueConversion::Uext(arg.value_type),
|
||||||
|
ArgumentExtension::Sext => ValueConversion::Sext(arg.value_type),
|
||||||
|
_ => panic!("No argument extension specified"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// We have the same number of bits as the argument.
|
||||||
|
Ordering::Equal => {
|
||||||
|
// This must be an integer vector that is split and then extended.
|
||||||
|
assert!(arg.value_type.is_int());
|
||||||
|
assert!(!have.is_scalar());
|
||||||
|
ValueConversion::VectorSplit
|
||||||
|
}
|
||||||
|
// We have more bits than the argument.
|
||||||
|
Ordering::Greater => {
|
||||||
|
if have.is_scalar() {
|
||||||
|
if have.is_float() {
|
||||||
|
// Convert a float to int so it can be split the next time.
|
||||||
|
// ARM would do this to pass an `f64` in two registers.
|
||||||
|
ValueConversion::IntBits
|
||||||
|
} else {
|
||||||
|
ValueConversion::IntSplit
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ValueConversion::VectorSplit
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
use ir::types;
|
||||||
|
use ir::ArgumentType;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn legalize() {
|
||||||
|
let mut arg = ArgumentType::new(types::I32);
|
||||||
|
|
||||||
|
assert_eq!(legalize_abi_value(types::I64X2, &arg),
|
||||||
|
ValueConversion::VectorSplit);
|
||||||
|
assert_eq!(legalize_abi_value(types::I64, &arg),
|
||||||
|
ValueConversion::IntSplit);
|
||||||
|
|
||||||
|
// Vector of integers is broken down, then sign-extended.
|
||||||
|
arg.extension = ArgumentExtension::Sext;
|
||||||
|
assert_eq!(legalize_abi_value(types::I16X4, &arg),
|
||||||
|
ValueConversion::VectorSplit);
|
||||||
|
assert_eq!(legalize_abi_value(types::I16.by(2).unwrap(), &arg),
|
||||||
|
ValueConversion::VectorSplit);
|
||||||
|
assert_eq!(legalize_abi_value(types::I16, &arg),
|
||||||
|
ValueConversion::Sext(types::I32));
|
||||||
|
|
||||||
|
// 64-bit float is split as an integer.
|
||||||
|
assert_eq!(legalize_abi_value(types::F64, &arg),
|
||||||
|
ValueConversion::IntBits);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -67,6 +67,17 @@ impl Type {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get an integer type with the requested number of bits.
|
||||||
|
pub fn int(bits: u16) -> Option<Type> {
|
||||||
|
match bits {
|
||||||
|
8 => Some(I8),
|
||||||
|
16 => Some(I16),
|
||||||
|
32 => Some(I32),
|
||||||
|
64 => Some(I64),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Get a type with the same number of lanes as this type, but with the lanes replaced by
|
/// Get a type with the same number of lanes as this type, but with the lanes replaced by
|
||||||
/// booleans of the same size.
|
/// booleans of the same size.
|
||||||
///
|
///
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
//!
|
//!
|
||||||
//! This doesn't support the soft-float ABI at the moment.
|
//! This doesn't support the soft-float ABI at the moment.
|
||||||
|
|
||||||
use abi::{ArgAction, ArgAssigner, legalize_args};
|
use abi::{ArgAction, ValueConversion, ArgAssigner, legalize_args};
|
||||||
use ir::{Signature, ArgumentType, ArgumentLoc};
|
use ir::{Signature, ArgumentType, ArgumentLoc};
|
||||||
use isa::riscv::registers::{GPR, FPR};
|
use isa::riscv::registers::{GPR, FPR};
|
||||||
use settings as shared_settings;
|
use settings as shared_settings;
|
||||||
@@ -39,7 +39,7 @@ impl ArgAssigner for Args {
|
|||||||
// Check for a legal type.
|
// Check for a legal type.
|
||||||
// RISC-V doesn't have SIMD at all, so break all vectors down.
|
// RISC-V doesn't have SIMD at all, so break all vectors down.
|
||||||
if !ty.is_scalar() {
|
if !ty.is_scalar() {
|
||||||
return ArgAction::Split;
|
return ArgAction::Convert(ValueConversion::VectorSplit);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Large integers and booleans are broken down to fit in a register.
|
// Large integers and booleans are broken down to fit in a register.
|
||||||
@@ -47,7 +47,7 @@ impl ArgAssigner for Args {
|
|||||||
// Align registers and stack to a multiple of two pointers.
|
// Align registers and stack to a multiple of two pointers.
|
||||||
self.regs = align(self.regs, 2);
|
self.regs = align(self.regs, 2);
|
||||||
self.offset = align(self.offset, 2 * self.pointer_bytes);
|
self.offset = align(self.offset, 2 * self.pointer_bytes);
|
||||||
return ArgAction::Split;
|
return ArgAction::Convert(ValueConversion::IntSplit);
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.regs < 8 {
|
if self.regs < 8 {
|
||||||
|
|||||||
@@ -13,7 +13,9 @@
|
|||||||
//! The legalizer does not deal with register allocation constraints. These constraints are derived
|
//! The legalizer does not deal with register allocation constraints. These constraints are derived
|
||||||
//! from the encoding recipes, and solved later by the register allocator.
|
//! from the encoding recipes, and solved later by the register allocator.
|
||||||
|
|
||||||
use ir::{Function, Cursor, DataFlowGraph, InstructionData, Opcode, InstBuilder};
|
use abi::{legalize_abi_value, ValueConversion};
|
||||||
|
use ir::{Function, Cursor, DataFlowGraph, InstructionData, Opcode, InstBuilder, Ebb, Type, Value,
|
||||||
|
ArgumentType};
|
||||||
use ir::condcodes::IntCC;
|
use ir::condcodes::IntCC;
|
||||||
use isa::{TargetIsa, Legalize};
|
use isa::{TargetIsa, Legalize};
|
||||||
|
|
||||||
@@ -87,4 +89,115 @@ fn legalize_signatures(func: &mut Function, isa: &TargetIsa) {
|
|||||||
for sig in func.dfg.signatures.keys() {
|
for sig in func.dfg.signatures.keys() {
|
||||||
isa.legalize_signature(&mut func.dfg.signatures[sig]);
|
isa.legalize_signature(&mut func.dfg.signatures[sig]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if let Some(entry) = func.layout.entry_block() {
|
||||||
|
legalize_entry_arguments(func, entry);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Legalize the entry block arguments after `func`'s signature has been legalized.
|
||||||
|
///
|
||||||
|
/// The legalized signature may contain more arguments than the original signature, and the
|
||||||
|
/// argument types have been changed. This function goes through the arguments to the entry EBB and
|
||||||
|
/// replaces them with arguments of the right type for the ABI.
|
||||||
|
///
|
||||||
|
/// The original entry EBB arguments are computed from the new ABI arguments by code inserted at
|
||||||
|
/// the top of the entry block.
|
||||||
|
fn legalize_entry_arguments(func: &mut Function, entry: Ebb) {
|
||||||
|
// Insert position for argument conversion code.
|
||||||
|
// We want to insert instructions before the first instruction in the entry block.
|
||||||
|
// If the entry block is empty, append instructions to it instead.
|
||||||
|
let mut pos = Cursor::new(&mut func.layout);
|
||||||
|
pos.goto_top(entry);
|
||||||
|
pos.next_inst();
|
||||||
|
|
||||||
|
// Keep track of the argument types in the ABI-legalized signature.
|
||||||
|
let abi_types = &func.signature.argument_types;
|
||||||
|
let mut abi_arg = 0;
|
||||||
|
|
||||||
|
// Process the EBB arguments one at a time, possibly replacing one argument with multiple new
|
||||||
|
// ones. We do this by detaching the entry EBB arguments first.
|
||||||
|
let mut next_arg = func.dfg.take_ebb_args(entry);
|
||||||
|
while let Some(arg) = next_arg {
|
||||||
|
// Get the next argument before we mutate `arg`.
|
||||||
|
next_arg = func.dfg.next_ebb_arg(arg);
|
||||||
|
|
||||||
|
let arg_type = func.dfg.value_type(arg);
|
||||||
|
if arg_type == abi_types[abi_arg].value_type {
|
||||||
|
// No value translation is necessary, this argument matches the ABI type.
|
||||||
|
// Just use the original EBB argument value. This is the most common case.
|
||||||
|
func.dfg.put_ebb_arg(entry, arg);
|
||||||
|
abi_arg += 1;
|
||||||
|
} else {
|
||||||
|
// Compute the value we want for `arg` from the legalized ABI arguments.
|
||||||
|
let converted = convert_from_abi(&mut func.dfg,
|
||||||
|
&mut pos,
|
||||||
|
entry,
|
||||||
|
&mut abi_arg,
|
||||||
|
abi_types,
|
||||||
|
arg_type);
|
||||||
|
// The old `arg` is no longer an attached EBB argument, but there are probably still
|
||||||
|
// uses of the value. Make it an alias to the converted value.
|
||||||
|
func.dfg.change_to_alias(arg, converted);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Compute original value of type `ty` from the legalized ABI arguments beginning at `abi_arg`.
|
||||||
|
///
|
||||||
|
/// Update `abi_arg` to reflect the ABI arguments consumed and return the computed value.
|
||||||
|
fn convert_from_abi(dfg: &mut DataFlowGraph,
|
||||||
|
pos: &mut Cursor,
|
||||||
|
entry: Ebb,
|
||||||
|
abi_arg: &mut usize,
|
||||||
|
abi_types: &[ArgumentType],
|
||||||
|
ty: Type)
|
||||||
|
-> Value {
|
||||||
|
// Terminate the recursion when we get the desired type.
|
||||||
|
if ty == abi_types[*abi_arg].value_type {
|
||||||
|
return dfg.append_ebb_arg(entry, ty);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reconstruct how `ty` was legalized into the argument at `abi_arg`.
|
||||||
|
let conversion = legalize_abi_value(ty, &abi_types[*abi_arg]);
|
||||||
|
|
||||||
|
// The conversion describes value to ABI argument. We implement the reverse conversion here.
|
||||||
|
match conversion {
|
||||||
|
// Construct a `ty` by concatenating two ABI integers.
|
||||||
|
ValueConversion::IntSplit => {
|
||||||
|
let abi_ty = ty.half_width().expect("Invalid type for conversion");
|
||||||
|
let lo = convert_from_abi(dfg, pos, entry, abi_arg, abi_types, abi_ty);
|
||||||
|
let hi = convert_from_abi(dfg, pos, entry, abi_arg, abi_types, abi_ty);
|
||||||
|
dfg.ins(pos).iconcat_lohi(lo, hi)
|
||||||
|
}
|
||||||
|
// Construct a `ty` by concatenating two halves of a vector.
|
||||||
|
ValueConversion::VectorSplit => {
|
||||||
|
let abi_ty = ty.half_vector().expect("Invalid type for conversion");
|
||||||
|
let _lo = convert_from_abi(dfg, pos, entry, abi_arg, abi_types, abi_ty);
|
||||||
|
let _hi = convert_from_abi(dfg, pos, entry, abi_arg, abi_types, abi_ty);
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
// Construct a `ty` by bit-casting from an integer type.
|
||||||
|
ValueConversion::IntBits => {
|
||||||
|
assert!(!ty.is_int());
|
||||||
|
let abi_ty = Type::int(ty.bits()).expect("Invalid type for conversion");
|
||||||
|
let arg = convert_from_abi(dfg, pos, entry, abi_arg, abi_types, abi_ty);
|
||||||
|
dfg.ins(pos).bitcast(ty, arg)
|
||||||
|
}
|
||||||
|
// ABI argument is a sign-extended version of the value we want.
|
||||||
|
ValueConversion::Sext(abi_ty) => {
|
||||||
|
let arg = convert_from_abi(dfg, pos, entry, abi_arg, abi_types, abi_ty);
|
||||||
|
// TODO: Currently, we don't take advantage of the ABI argument being sign-extended.
|
||||||
|
// We could insert an `assert_sreduce` which would fold with a following `sextend` of
|
||||||
|
// this value.
|
||||||
|
dfg.ins(pos).ireduce(ty, arg)
|
||||||
|
}
|
||||||
|
ValueConversion::Uext(abi_ty) => {
|
||||||
|
let arg = convert_from_abi(dfg, pos, entry, abi_arg, abi_types, abi_ty);
|
||||||
|
// TODO: Currently, we don't take advantage of the ABI argument being sign-extended.
|
||||||
|
// We could insert an `assert_ureduce` which would fold with a following `uextend` of
|
||||||
|
// this value.
|
||||||
|
dfg.ins(pos).ireduce(ty, arg)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user