diff --git a/cranelift/src/libcretonne/write.rs b/cranelift/src/libcretonne/write.rs index 38800bb48a..e0d19aa5a8 100644 --- a/cranelift/src/libcretonne/write.rs +++ b/cranelift/src/libcretonne/write.rs @@ -7,6 +7,7 @@ use std::io::{self, Write}; use repr::Function; use entities::{Inst, Ebb, Value}; +use types::Type; pub type Result = io::Result<()>; @@ -126,6 +127,35 @@ pub fn write_ebb(w: &mut Write, func: &Function, ebb: Ebb) -> Result { // // ====--------------------------------------------------------------------------------------====// +// Should `inst` be printed with a type suffix? +// +// Polymorphic instructions may need a suffix indicating the value of the controlling type variable +// if it can't be trivially inferred. +// +fn type_suffix(func: &Function, inst: Inst) -> Option { + let constraints = func[inst].opcode().constraints(); + + if !constraints.is_polymorphic() { + return None; + } + + // If the controlling type variable can be inferred from the type of the designated value input + // operand, we don't need the type suffix. + // TODO: Should we include the suffix when the input value is defined in another block? The + // parser needs to know the type of the value, so it must be defined in a block that lexically + // comes before this one. + if constraints.use_typevar_operand() { + return None; + } + + // This polymorphic instruction doesn't support basic type inference. + // The controlling type variable is required to be the type of the first result. + let rtype = func.value_type(func.first_result(inst)); + assert!(!rtype.is_void(), + "Polymorphic instruction must produce a result"); + Some(rtype) +} + pub fn write_instruction(w: &mut Write, func: &Function, inst: Inst) -> Result { try!(write!(w, " ")); @@ -143,30 +173,34 @@ pub fn write_instruction(w: &mut Write, func: &Function, inst: Inst) -> Result { try!(write!(w, " = ")); } - // Then the opcode and operands, depending on format. + // Then the opcode, possibly with a '.type' suffix. + let opcode = func[inst].opcode(); + + match type_suffix(func, inst) { + Some(suf) => try!(write!(w, "{}.{}", opcode, suf)), + None => try!(write!(w, "{}", opcode)), + } + + // Then the operands, depending on format. use instructions::InstructionData::*; match func[inst] { - Nullary { opcode, .. } => writeln!(w, "{}", opcode), - Unary { opcode, arg, .. } => writeln!(w, "{} {}", opcode, arg), - UnaryImm { opcode, imm, .. } => writeln!(w, "{} {}", opcode, imm), - UnaryIeee32 { opcode, imm, .. } => writeln!(w, "{} {}", opcode, imm), - UnaryIeee64 { opcode, imm, .. } => writeln!(w, "{} {}", opcode, imm), - UnaryImmVector { opcode, .. } => writeln!(w, "{} [...]", opcode), - Binary { opcode, args, .. } => writeln!(w, "{} {}, {}", opcode, args[0], args[1]), - BinaryImm { opcode, arg, imm, .. } => writeln!(w, "{} {}, {}", opcode, arg, imm), - BinaryImmRev { opcode, imm, arg, .. } => writeln!(w, "{} {}, {}", opcode, imm, arg), - BinaryOverflow { opcode, args, .. } => writeln!(w, "{} {}, {}", opcode, args[0], args[1]), - Select { opcode, args, .. } => { - writeln!(w, "{} {}, {}, {}", opcode, args[0], args[1], args[2]) - } - InsertLane { opcode, lane, args, .. } => { - writeln!(w, "{} {}, {}, {}", opcode, args[0], lane, args[1]) - } - ExtractLane { opcode, lane, arg, .. } => writeln!(w, "{} {}, {}", opcode, arg, lane), - Jump { opcode, ref data, .. } => writeln!(w, "{} {}", opcode, data), - Branch { opcode, ref data, .. } => writeln!(w, "{} {}", opcode, data), - BranchTable { opcode, arg, table, .. } => writeln!(w, "{} {}, {}", opcode, arg, table), - Call { opcode, ref data, .. } => writeln!(w, "{} {}", opcode, data), + Nullary { .. } => writeln!(w, ""), + Unary { arg, .. } => writeln!(w, " {}", arg), + UnaryImm { imm, .. } => writeln!(w, " {}", imm), + UnaryIeee32 { imm, .. } => writeln!(w, " {}", imm), + UnaryIeee64 { imm, .. } => writeln!(w, " {}", imm), + UnaryImmVector { .. } => writeln!(w, " [...]"), + Binary { args, .. } => writeln!(w, " {}, {}", args[0], args[1]), + BinaryImm { arg, imm, .. } => writeln!(w, " {}, {}", arg, imm), + BinaryImmRev { imm, arg, .. } => writeln!(w, " {}, {}", imm, arg), + BinaryOverflow { args, .. } => writeln!(w, " {}, {}", args[0], args[1]), + Select { args, .. } => writeln!(w, " {}, {}, {}", args[0], args[1], args[2]), + InsertLane { lane, args, .. } => writeln!(w, " {}, {}, {}", args[0], lane, args[1]), + ExtractLane { lane, arg, .. } => writeln!(w, " {}, {}", arg, lane), + Jump { ref data, .. } => writeln!(w, " {}", data), + Branch { ref data, .. } => writeln!(w, " {}", data), + BranchTable { arg, table, .. } => writeln!(w, " {}, {}", arg, table), + Call { ref data, .. } => writeln!(w, " {}", data), } } diff --git a/cranelift/tests/parser/tiny.cton b/cranelift/tests/parser/tiny.cton index acc8ea7384..9619147f6f 100644 --- a/cranelift/tests/parser/tiny.cton +++ b/cranelift/tests/parser/tiny.cton @@ -3,3 +3,12 @@ function minimal() { ebb0: trap } + +; Create and use values. +; Polymorphic instructions with type suffix. +function ivalues() { +ebb0: + v0 = iconst.i32 2 + v1 = iconst.i8 6 + v2 = ishl v0, v1 +} diff --git a/cranelift/tests/parser/tiny.cton.ref b/cranelift/tests/parser/tiny.cton.ref index 474c30527e..c8c28dd419 100644 --- a/cranelift/tests/parser/tiny.cton.ref +++ b/cranelift/tests/parser/tiny.cton.ref @@ -2,3 +2,10 @@ function minimal() { ebb0: trap } + +function ivalues() { +ebb0: + v0 = iconst.i32 2 + v1 = iconst.i8 6 + v2 = ishl v0, v1 +}