Move library crates under 'lib/'.

Give these crates each a more standard directory layout with sources in
a 'src' sub-sirectory and Cargo.toml in the top lib/foo directory.

Add license and description fields to each.

The build script for the cretonne crate now lives in
'lib/cretonne/build.rs' separating it from the normal library sources
under 'lib/cretonne/src'.
This commit is contained in:
Jakob Stoklund Olesen
2016-10-17 14:44:43 -07:00
parent e7f30a40b4
commit 0764df28b5
52 changed files with 64 additions and 64 deletions

243
lib/cretonne/src/write.rs Normal file
View File

@@ -0,0 +1,243 @@
//! Converting Cretonne IL to text.
//!
//! The `write` module provides the `write_function` function which converts an IL `Function` to an
//! equivalent textual representation. This textual representation can be read back by the
//! `cretonne-reader` crate.
use ir::{Function, Ebb, Inst, Value, Type};
use isa::TargetIsa;
use std::fmt::{Result, Error, Write};
use std::result;
/// Write `func` to `w` as equivalent text.
/// Use `isa` to emit ISA-dependent annotations.
pub fn write_function(w: &mut Write, func: &Function, isa: Option<&TargetIsa>) -> Result {
try!(write_spec(w, func));
try!(writeln!(w, " {{"));
let mut any = try!(write_preamble(w, func));
for ebb in &func.layout {
if any {
try!(writeln!(w, ""));
}
try!(write_ebb(w, func, isa, ebb));
any = true;
}
writeln!(w, "}}")
}
// ====--------------------------------------------------------------------------------------====//
//
// Function spec.
//
// ====--------------------------------------------------------------------------------------====//
fn write_spec(w: &mut Write, func: &Function) -> Result {
write!(w, "function {}{}", func.name, func.own_signature())
}
fn write_preamble(w: &mut Write, func: &Function) -> result::Result<bool, Error> {
let mut any = false;
for ss in func.stack_slots.keys() {
any = true;
try!(writeln!(w, " {} = {}", ss, func.stack_slots[ss]));
}
for jt in func.jump_tables.keys() {
any = true;
try!(writeln!(w, " {} = {}", jt, func.jump_tables[jt]));
}
Ok(any)
}
// ====--------------------------------------------------------------------------------------====//
//
// Basic blocks
//
// ====--------------------------------------------------------------------------------------====//
pub fn write_arg(w: &mut Write, func: &Function, arg: Value) -> Result {
write!(w, "{}: {}", arg, func.dfg.value_type(arg))
}
pub fn write_ebb_header(w: &mut Write, func: &Function, ebb: Ebb) -> Result {
// Write out the basic block header, outdented:
//
// ebb1:
// ebb1(vx1: i32):
// ebb10(vx4: f64, vx5: b1):
//
// If we're writing encoding annotations, shift by 20.
if !func.encodings.is_empty() {
try!(write!(w, " "));
}
let mut args = func.dfg.ebb_args(ebb);
match args.next() {
None => return writeln!(w, "{}:", ebb),
Some(arg) => {
try!(write!(w, "{}(", ebb));
try!(write_arg(w, func, arg));
}
}
// Remaining args.
for arg in args {
try!(write!(w, ", "));
try!(write_arg(w, func, arg));
}
writeln!(w, "):")
}
pub fn write_ebb(w: &mut Write, func: &Function, isa: Option<&TargetIsa>, ebb: Ebb) -> Result {
try!(write_ebb_header(w, func, ebb));
for inst in func.layout.ebb_insts(ebb) {
try!(write_instruction(w, func, isa, inst));
}
Ok(())
}
// ====--------------------------------------------------------------------------------------====//
//
// Instructions
//
// ====--------------------------------------------------------------------------------------====//
// 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<Type> {
let constraints = func.dfg[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.dfg.value_type(func.dfg.first_result(inst));
assert!(!rtype.is_void(),
"Polymorphic instruction must produce a result");
Some(rtype)
}
fn write_instruction(w: &mut Write,
func: &Function,
isa: Option<&TargetIsa>,
inst: Inst)
-> Result {
// Write out encoding info.
if let Some(enc) = func.encodings.get(inst).cloned() {
let mut s = String::with_capacity(16);
if let Some(isa) = isa {
try!(write!(s, "[{}]", isa.display_enc(enc)));
} else {
try!(write!(s, "[{}]", enc));
}
// Align instruction following ISA annotation to col 24.
try!(write!(w, "{:23} ", s));
} else {
// No annotations, simply indent by 4.
try!(write!(w, " "));
}
// Write out the result values, if any.
let mut has_results = false;
for r in func.dfg.inst_results(inst) {
if !has_results {
has_results = true;
try!(write!(w, "{}", r));
} else {
try!(write!(w, ", {}", r));
}
}
if has_results {
try!(write!(w, " = "));
}
// Then the opcode, possibly with a '.type' suffix.
let opcode = func.dfg[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 ir::instructions::InstructionData::*;
match func.dfg[inst] {
Nullary { .. } => writeln!(w, ""),
Unary { arg, .. } => writeln!(w, " {}", arg),
UnaryImm { imm, .. } => writeln!(w, " {}", imm),
UnaryIeee32 { imm, .. } => writeln!(w, " {}", imm),
UnaryIeee64 { imm, .. } => writeln!(w, " {}", imm),
UnaryImmVector { ref data, .. } => writeln!(w, " {}", data),
UnarySplit { arg, .. } => writeln!(w, " {}", arg),
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]),
Ternary { args, .. } => writeln!(w, " {}, {}, {}", args[0], args[1], args[2]),
TernaryOverflow { ref data, .. } => writeln!(w, " {}", data),
InsertLane { lane, args, .. } => writeln!(w, " {}, {}, {}", args[0], lane, args[1]),
ExtractLane { lane, arg, .. } => writeln!(w, " {}, {}", arg, lane),
IntCompare { cond, args, .. } => writeln!(w, " {}, {}, {}", cond, args[0], args[1]),
FloatCompare { cond, args, .. } => writeln!(w, " {}, {}, {}", cond, args[0], args[1]),
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),
Return { ref data, .. } => {
if data.varargs.is_empty() {
writeln!(w, "")
} else {
writeln!(w, " {}", data.varargs)
}
}
}
}
#[cfg(test)]
mod tests {
use ir::{Function, FunctionName, StackSlotData};
use ir::types;
#[test]
fn basic() {
let mut f = Function::new();
assert_eq!(f.to_string(), "function \"\"() {\n}\n");
f.name = FunctionName::new("foo".to_string());
assert_eq!(f.to_string(), "function foo() {\n}\n");
f.stack_slots.push(StackSlotData::new(4));
assert_eq!(f.to_string(),
"function foo() {\n ss0 = stack_slot 4\n}\n");
let ebb = f.dfg.make_ebb();
f.layout.append_ebb(ebb);
assert_eq!(f.to_string(),
"function foo() {\n ss0 = stack_slot 4\n\nebb0:\n}\n");
f.dfg.append_ebb_arg(ebb, types::I8);
assert_eq!(f.to_string(),
"function foo() {\n ss0 = stack_slot 4\n\nebb0(vx0: i8):\n}\n");
f.dfg.append_ebb_arg(ebb, types::F32.by(4).unwrap());
assert_eq!(f.to_string(),
"function foo() {\n ss0 = stack_slot 4\n\nebb0(vx0: i8, vx1: f32x4):\n}\n");
}
}