diff --git a/Cargo.lock b/Cargo.lock index 37216ee3fbaf095900ca648fcbcad447ef3af34c..1f9d1747a6ee3734825aeb18d792164cf6f99f19 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -712,6 +712,16 @@ dependencies = [ "with_builtin_macros", ] +[[package]] +name = "juno_casts_and_intrinsics" +version = "0.1.0" +dependencies = [ + "async-std", + "hercules_rt", + "juno_build", + "with_builtin_macros", +] + [[package]] name = "juno_frontend" version = "0.1.0" diff --git a/Cargo.toml b/Cargo.toml index c6b2468fb9d41b467d48221d6621d9fcbb197034..a34845f8b26aeb97d076e7ebfcf8125efa43473c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -20,6 +20,7 @@ members = [ "juno_scheduler", "juno_build", - "juno_samples/matmul", "juno_samples/simple3", + "juno_samples/matmul", + "juno_samples/casts_and_intrinsics", ] diff --git a/hercules_cg/src/cpu.rs b/hercules_cg/src/cpu.rs index eaa7374b7a8f6c3df66a9a5085d179a143b81d34..8437e9e44b2c7792b54f563f86f59ee5fa6bd23a 100644 --- a/hercules_cg/src/cpu.rs +++ b/hercules_cg/src/cpu.rs @@ -597,7 +597,54 @@ impl<'a> CPUContext<'a> { write!(w, ", -1")?; } } - SUnaryOperator::Cast(_) => todo!(), + SUnaryOperator::Cast(dst_ty) => { + let src_ty = &self.svalue_types[input]; + if src_ty.is_integer() + && dst_ty.is_integer() + && src_ty.num_bits() > dst_ty.num_bits() + { + write!(w, "trunc ")?; + } else if src_ty.is_signed() + && dst_ty.is_integer() + && src_ty.num_bits() < dst_ty.num_bits() + { + write!(w, "sext ")?; + } else if src_ty.is_integer() + && dst_ty.is_integer() + && src_ty.num_bits() < dst_ty.num_bits() + { + write!(w, "zext ")?; + } else if src_ty.is_integer() && dst_ty.is_integer() { + // A no-op. + write!(w, "bitcast ")?; + } else if src_ty.is_float() + && dst_ty.is_float() + && src_ty.num_bits() > dst_ty.num_bits() + { + write!(w, "fptrunc ")?; + } else if src_ty.is_float() + && dst_ty.is_float() + && src_ty.num_bits() < dst_ty.num_bits() + { + write!(w, "fpext ")?; + } else if src_ty.is_float() && dst_ty.is_float() { + // A no-op. + write!(w, "bitcast ")?; + } else if src_ty.is_float() && dst_ty.is_signed() { + write!(w, "fptosi ")?; + } else if src_ty.is_float() && dst_ty.is_integer() { + write!(w, "fptoui ")?; + } else if src_ty.is_signed() && dst_ty.is_float() { + write!(w, "sitofp ")?; + } else if src_ty.is_integer() && dst_ty.is_float() { + write!(w, "uitofp ")?; + } else { + panic!("PANIC: Invalid cast type combination."); + } + self.emit_svalue(input, true, w)?; + write!(w, " to ")?; + self.emit_type(dst_ty, w)?; + } } } SInst::Binary { left, right, op } => { @@ -677,6 +724,24 @@ impl<'a> CPUContext<'a> { } } } + SInst::IntrinsicCall { intrinsic, args } => { + emit_assign(w)?; + write!(w, "call ")?; + self.emit_type(&self.svalue_types[&self_svalue], w)?; + write!( + w, + " @llvm.{}.{}(", + // TODO: make lower case names conform to LLVM expectations. + intrinsic.lower_case_name(), + Self::intrinsic_type_str(&self.svalue_types[&self_svalue]) + )?; + self.emit_svalue(&args[0], true, w)?; + for idx in 1..args.len() { + write!(w, ", ")?; + self.emit_svalue(&args[idx], true, w)?; + } + write!(w, ")")?; + } SInst::ProductExtract { product, indices } => { emit_assign(w)?; write!(w, "extractvalue ")?; diff --git a/hercules_cg/src/sched_gen.rs b/hercules_cg/src/sched_gen.rs index e5378b9cca4ae553ff8a760202db0526b13f7211..70a898b6c259b8bf7543b5ff4d1202132c71cf9b 100644 --- a/hercules_cg/src/sched_gen.rs +++ b/hercules_cg/src/sched_gen.rs @@ -1071,6 +1071,17 @@ impl<'a> FunctionContext<'a> { self.stypes[self.typing[id.idx()].idx()].clone().unwrap(), )); } + Node::IntrinsicCall { + intrinsic, + ref args, + } => { + let args = args.iter().map(|id| get_svalue(*id).clone()).collect(); + block.insts.push(SInst::IntrinsicCall { intrinsic, args }); + block.virt_regs.push(( + self_virt_reg(), + self.stypes[self.typing[id.idx()].idx()].clone().unwrap(), + )); + } Node::Read { collect, diff --git a/hercules_cg/src/sched_ir.rs b/hercules_cg/src/sched_ir.rs index 3ceee621f4469127c40453e364b87a230a947e85..6a482443eaf39c6f3b87c7b19ec06adbe67ff5ad 100644 --- a/hercules_cg/src/sched_ir.rs +++ b/hercules_cg/src/sched_ir.rs @@ -213,6 +213,28 @@ impl SType { } } + pub fn is_signed(&self) -> bool { + match self { + SType::Integer8 | SType::Integer16 | SType::Integer32 | SType::Integer64 => true, + _ => false, + } + } + + pub fn is_integer(&self) -> bool { + self.is_unsigned() || self.is_signed() || *self == SType::Boolean + } + + pub fn num_bits(&self) -> u8 { + match self { + SType::Boolean => 1, + SType::Integer8 | SType::UnsignedInteger8 => 8, + SType::Integer16 | SType::UnsignedInteger16 => 16, + SType::Integer32 | SType::UnsignedInteger32 | SType::Float32 => 32, + SType::Integer64 | SType::UnsignedInteger64 | SType::Float64 => 64, + _ => panic!(), + } + } + pub fn try_product(&self) -> Option<&[SType]> { if let SType::Product(fields) = self { Some(fields) @@ -334,6 +356,10 @@ pub enum SInst { third: SValue, op: STernaryOperator, }, + IntrinsicCall { + intrinsic: Intrinsic, + args: Box<[SValue]>, + }, ProductExtract { product: SValue, indices: Box<[usize]>, @@ -487,6 +513,7 @@ impl SInst { third: _, op, } => op.upper_case_name(), + SInst::IntrinsicCall { intrinsic, args: _ } => intrinsic.upper_case_name(), SInst::ProductExtract { product: _, indices: _, diff --git a/hercules_cg/src/sched_schedule.rs b/hercules_cg/src/sched_schedule.rs index 16720bbc60380866cd2dbd868ebf9f6cbd5a91fe..4ba407f0e316e6611e311ff095bff6121a922c5a 100644 --- a/hercules_cg/src/sched_schedule.rs +++ b/hercules_cg/src/sched_schedule.rs @@ -44,7 +44,7 @@ pub fn sched_get_uses(inst: &SInst) -> Box<dyn Iterator<Item = &SValue> + '_> { false_target: _, true_target: _, } => Box::new(once(cond)), - SInst::PartitionExit { data_outputs } => Box::new(data_outputs.iter().map(|svalue| svalue)), + SInst::PartitionExit { data_outputs } => Box::new(data_outputs.iter()), SInst::Return { value } => Box::new(once(value)), SInst::Unary { input, op: _ } => Box::new(once(input)), SInst::Binary { left, right, op: _ } => Box::new(once(left).chain(once(right))), @@ -54,6 +54,7 @@ pub fn sched_get_uses(inst: &SInst) -> Box<dyn Iterator<Item = &SValue> + '_> { third, op: _, } => Box::new(once(first).chain(once(second)).chain(once(third))), + SInst::IntrinsicCall { intrinsic: _, args } => Box::new(args.iter()), SInst::ProductExtract { product, indices: _, diff --git a/hercules_ir/src/gcm.rs b/hercules_ir/src/gcm.rs index 3180a88b215dfcc36817abef816795561e03f4da..19df2d6bb3a42c4c989e9d04eb84b37caa6cf4a0 100644 --- a/hercules_ir/src/gcm.rs +++ b/hercules_ir/src/gcm.rs @@ -18,7 +18,6 @@ pub fn gcm( antideps: &Vec<(NodeID, NodeID)>, loops: &LoopTree, fork_join_map: &HashMap<NodeID, NodeID>, - partial_partition: &mut Vec<Option<PartitionID>>, ) -> Vec<NodeID> { let mut bbs: Vec<Option<NodeID>> = vec![None; function.nodes.len()]; @@ -186,30 +185,12 @@ pub fn gcm( // #[feature(iter_collect_into)] // Look between the LCA and the schedule early location to place the - // node. If a data node can't be scheduled to any control nodes in its - // partition (this may happen if all of the control nodes in a partition - // got deleted, for example), then the data node can be scheduled into a - // control node in a different partition. + // node. let schedule_early = schedule_early[id.idx()].unwrap(); - let need_to_repartition = !dom - .chain(lca.unwrap_or(schedule_early), schedule_early) - .any(|dominator| { - partial_partition[id.idx()].is_none() - || partial_partition[dominator.idx()] == partial_partition[id.idx()] - }); - if need_to_repartition { - partial_partition[id.idx()] = None; - } let mut chain = dom // If the node has no users, then it doesn't really matter where we // place it - just place it at the early placement. - .chain(lca.unwrap_or(schedule_early), schedule_early) - // Filter the dominator chain by control nodes in the same partition - // as this data node, if the data node is in a partition already. - .filter(|dominator| { - partial_partition[id.idx()].is_none() - || partial_partition[dominator.idx()] == partial_partition[id.idx()] - }); + .chain(lca.unwrap_or(schedule_early), schedule_early); let mut location = chain.next().unwrap(); while let Some(control_node) = chain.next() { // If the next node further up the dominator tree is in a shallower diff --git a/hercules_opt/src/editor.rs b/hercules_opt/src/editor.rs index 3286fa884663450ab0b15915467e1e82cfc428ff..a75ea38aa3b7703e7efecc952b54d9ccb8df45c6 100644 --- a/hercules_opt/src/editor.rs +++ b/hercules_opt/src/editor.rs @@ -687,16 +687,9 @@ pub fn repair_plan(plan: &mut Plan, new_function: &Function, edits: &[Edit]) { &antideps, &loops, &fork_join_map, - &mut new_partitions, ); - let added_and_to_repartition_data_nodes: Vec<NodeID> = new_partitions - .iter() - .enumerate() - .filter(|(_, part)| part.is_none()) - .map(|(idx, _)| NodeID::new(idx)) - .collect(); - for data_id in added_and_to_repartition_data_nodes { - new_partitions[data_id.idx()] = new_partitions[bbs[data_id.idx()].idx()]; + for data_idx in 0..new_function.nodes.len() { + new_partitions[data_idx] = new_partitions[bbs[data_idx].idx()]; } // Step 6: create a solitary gravestone partition. This will get removed diff --git a/hercules_opt/src/pass.rs b/hercules_opt/src/pass.rs index 03aff10ade7e4aca8ecf58d94127a405640eb7e3..f5e0a9ad5ac9a081efe3016cd0dcb6430c688bc6 100644 --- a/hercules_opt/src/pass.rs +++ b/hercules_opt/src/pass.rs @@ -275,7 +275,6 @@ impl PassManager { antideps, loops, fork_join_map, - &mut vec![None; function.nodes.len()], ) }, ) diff --git a/juno_samples/casts_and_intrinsics/Cargo.toml b/juno_samples/casts_and_intrinsics/Cargo.toml new file mode 100644 index 0000000000000000000000000000000000000000..f49797969012f5195a0338b7b14fa04414dddb03 --- /dev/null +++ b/juno_samples/casts_and_intrinsics/Cargo.toml @@ -0,0 +1,18 @@ +[package] +name = "juno_casts_and_intrinsics" +version = "0.1.0" +authors = ["Russel Arbore <rarbore2@illinois.edu>"] +edition = "2021" + +[[bin]] +name = "juno_casts_and_intrinsics" +path = "src/main.rs" + +[build-dependencies] +juno_build = { path = "../../juno_build" } + +[dependencies] +juno_build = { path = "../../juno_build" } +hercules_rt = { path = "../../hercules_rt" } +with_builtin_macros = "0.1.0" +async-std = "*" diff --git a/juno_samples/casts_and_intrinsics/build.rs b/juno_samples/casts_and_intrinsics/build.rs new file mode 100644 index 0000000000000000000000000000000000000000..8422f7e60619b48aca2d5e783eaed45e70be71c3 --- /dev/null +++ b/juno_samples/casts_and_intrinsics/build.rs @@ -0,0 +1,12 @@ +extern crate juno_build; +use juno_build::JunoCompiler; + +fn main() { + JunoCompiler::new() + .file_in_src("casts_and_intrinsics.jn") + .unwrap() + .schedule_in_src("casts_and_intrinsics.sch") + .unwrap() + .build() + .unwrap(); +} diff --git a/juno_samples/casts_and_intrinsics/src/casts_and_intrinsics.jn b/juno_samples/casts_and_intrinsics/src/casts_and_intrinsics.jn new file mode 100644 index 0000000000000000000000000000000000000000..5261063353496496e3e994a91620073438528ccd --- /dev/null +++ b/juno_samples/casts_and_intrinsics/src/casts_and_intrinsics.jn @@ -0,0 +1,5 @@ +#[entry] +fn casts_and_intrinsics(input : f32) -> i32 { + let sqrt = sqrt!::<f32>(input); + return sqrt as i32; +} diff --git a/juno_samples/casts_and_intrinsics/src/casts_and_intrinsics.sch b/juno_samples/casts_and_intrinsics/src/casts_and_intrinsics.sch new file mode 100644 index 0000000000000000000000000000000000000000..80ec2766eac8850ff736cd8a1f52dbe87bf24553 --- /dev/null +++ b/juno_samples/casts_and_intrinsics/src/casts_and_intrinsics.sch @@ -0,0 +1,2 @@ +function casts_and_intrinsics { +} diff --git a/juno_samples/casts_and_intrinsics/src/main.rs b/juno_samples/casts_and_intrinsics/src/main.rs new file mode 100644 index 0000000000000000000000000000000000000000..344168e0e1995becff3b4580f4d957002a9ee2a5 --- /dev/null +++ b/juno_samples/casts_and_intrinsics/src/main.rs @@ -0,0 +1,22 @@ +#![feature(future_join)] + +extern crate async_std; +extern crate juno_build; +extern crate hercules_rt; + +juno_build::juno!("casts_and_intrinsics"); + +fn main() { + async_std::task::block_on(async { + let output = unsafe { + casts_and_intrinsics(16.0).await + }; + println!("{}", output); + assert_eq!(output, 4); + }); +} + +#[test] +fn casts_and_intrinsics_test() { + main(); +}