From 9c31093d982694e577a81b0d7502c96fdd45e253 Mon Sep 17 00:00:00 2001 From: Steve Manuel Date: Mon, 14 Mar 2022 01:57:51 -0600 Subject: [PATCH] feat: parse binary logic --- src/instruction.rs | 68 +++++++++++++++++++++++++++ src/parser/command.rs | 23 ++++++++- src/parser/instruction.rs | 98 ++++++++++++++++++++++++++++++++++++--- src/parser/lexer.rs | 9 ++++ src/program/graph.rs | 1 + src/program/memory.rs | 12 ++++- src/program/mod.rs | 1 + 7 files changed, 203 insertions(+), 9 deletions(-) diff --git a/src/instruction.rs b/src/instruction.rs index 24678b64..e7b664e7 100644 --- a/src/instruction.rs +++ b/src/instruction.rs @@ -57,6 +57,62 @@ impl fmt::Display for ArithmeticOperator { } } +#[derive(Clone, Debug, PartialEq)] +pub enum LogicalOperand { + LiteralInteger(i64), + MemoryReference(MemoryReference), +} + +impl fmt::Display for LogicalOperand { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match &self { + LogicalOperand::LiteralInteger(value) => write!(f, "{}", value), + LogicalOperand::MemoryReference(value) => write!(f, "{}", value), + } + } +} + +#[derive(Clone, Debug, PartialEq)] +pub enum LogicalOperator { + Binary(BinaryLogic), + Unary(UnaryLogic), +} + +#[derive(Clone, Debug, PartialEq)] +pub enum BinaryLogic { + And, + Or, + Ior, + Xor, +} + +#[derive(Clone, Debug, PartialEq)] +pub enum UnaryLogic { + Neg, + Not, + True, + False, +} + +impl fmt::Display for LogicalOperator { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match &self { + LogicalOperator::Binary(logic) => match logic { + BinaryLogic::And => write!(f, "AND"), + BinaryLogic::Or => write!(f, "OR"), + BinaryLogic::Ior => write!(f, "IOR"), + BinaryLogic::Xor => write!(f, "XOR"), + }, + LogicalOperator::Unary(logic) => match logic { + UnaryLogic::Neg => write!(f, "NEG"), + UnaryLogic::Not => write!(f, "NOT"), + UnaryLogic::True => write!(f, "TRUE"), + UnaryLogic::False => write!(f, "FALSE"), + }, + } + } +} + #[derive(Clone, Debug, PartialEq)] pub enum AttributeValue { String(String), @@ -364,6 +420,13 @@ pub struct Arithmetic { pub source: ArithmeticOperand, } +#[derive(Clone, Debug, PartialEq)] +pub struct Logic { + pub operator: LogicalOperator, + pub operands: [MemoryReference; 2], + // pub operands: (MemoryReference, LogicalOperand), +} + #[derive(Clone, Debug, PartialEq)] pub struct Label(pub String); @@ -435,6 +498,7 @@ pub enum Instruction { SwapPhases(SwapPhases), WaveformDefinition(WaveformDefinition), Arithmetic(Arithmetic), + Logic(Logic), Halt, Label(Label), Move(Move), @@ -481,6 +545,7 @@ impl From<&Instruction> for InstructionRole { | Instruction::ShiftPhase(_) | Instruction::SwapPhases(_) => InstructionRole::RFControl, Instruction::Arithmetic(_) + | Instruction::Logic(_) | Instruction::Move(_) | Instruction::Exchange(_) | Instruction::Load(_) @@ -801,6 +866,9 @@ impl fmt::Display for Instruction { write!(f, "JUMP-WHEN @{} {}", target, condition) } Instruction::Label(Label(label)) => write!(f, "LABEL @{}", label), + Instruction::Logic(Logic { operator, operands }) => { + write!(f, "{} {} {}", operator, operands[0], operands[1]) + } } } } diff --git a/src/parser/command.rs b/src/parser/command.rs index d21ff204..06afcd68 100644 --- a/src/parser/command.rs +++ b/src/parser/command.rs @@ -22,8 +22,9 @@ use nom::{ use crate::instruction::{ Arithmetic, ArithmeticOperand, ArithmeticOperator, Calibration, Capture, CircuitDefinition, Declaration, Delay, Exchange, Fence, FrameDefinition, Instruction, Jump, JumpUnless, JumpWhen, - Label, Load, Measurement, Move, Pragma, Pulse, RawCapture, Reset, SetFrequency, SetPhase, - SetScale, ShiftFrequency, ShiftPhase, Store, Waveform, WaveformDefinition, + Label, Load, Logic, LogicalOperator, Measurement, Move, Pragma, Pulse, RawCapture, Reset, + SetFrequency, SetPhase, SetScale, ShiftFrequency, ShiftPhase, Store, Waveform, + WaveformDefinition, }; use crate::parser::common::parse_variable_qubit; use crate::parser::instruction::parse_block; @@ -57,6 +58,24 @@ pub fn parse_arithmetic( )) } +/// Parse an arithmetic instruction of the form `destination source`. +/// Called using the arithmetic operator itself (such as `ADD`) which should be previously parsed. +pub fn parse_logical_binary( + operator: LogicalOperator, + input: ParserInput, +) -> ParserResult { + let (input, left) = common::parse_memory_reference(input)?; // addr + let (input, right) = common::parse_memory_reference(input)?; // addr + + Ok(( + input, + Instruction::Logic(Logic { + operator, + operands: [left, right], + }), + )) +} + /// Parse the contents of a `DECLARE` instruction. pub fn parse_declare<'a>(input: ParserInput<'a>) -> ParserResult<'a, Instruction> { let (input, name) = token!(Identifier(v))(input)?; diff --git a/src/parser/instruction.rs b/src/parser/instruction.rs index e94752a0..d44d3825 100644 --- a/src/parser/instruction.rs +++ b/src/parser/instruction.rs @@ -20,7 +20,7 @@ use nom::{ }; use crate::{ - instruction::{ArithmeticOperator, Instruction}, + instruction::{ArithmeticOperator, BinaryLogic, Instruction, LogicalOperator}, token, }; @@ -43,7 +43,10 @@ pub fn parse_instruction(input: ParserInput) -> ParserResult { Some((Token::Command(command), remainder)) => { match command { Command::Add => command::parse_arithmetic(ArithmeticOperator::Add, remainder), - // Command::And => {} + Command::And => command::parse_logical_binary( + LogicalOperator::Binary(BinaryLogic::And), + remainder, + ), Command::Capture => command::parse_capture(remainder, true), // Command::Convert => {} Command::Declare => command::parse_declare(remainder), @@ -61,7 +64,10 @@ pub fn parse_instruction(input: ParserInput) -> ParserResult { // Command::GT => {} Command::Halt => Ok((remainder, Instruction::Halt)), // Command::Include => {} - // Command::Ior => {} + Command::Ior => command::parse_logical_binary( + LogicalOperator::Binary(BinaryLogic::Ior), + remainder, + ), Command::Jump => command::parse_jump(remainder), Command::JumpUnless => command::parse_jump_unless(remainder), Command::JumpWhen => command::parse_jump_when(remainder), @@ -76,6 +82,10 @@ pub fn parse_instruction(input: ParserInput) -> ParserResult { // Command::Neg => {} // Command::Nop => {} // Command::Not => {} + Command::Or => command::parse_logical_binary( + LogicalOperator::Binary(BinaryLogic::Or), + remainder, + ), Command::Pragma => command::parse_pragma(remainder), Command::Pulse => command::parse_pulse(remainder, true), Command::RawCapture => command::parse_raw_capture(remainder, true), @@ -88,7 +98,10 @@ pub fn parse_instruction(input: ParserInput) -> ParserResult { Command::Store => command::parse_store(remainder), Command::Sub => command::parse_arithmetic(ArithmeticOperator::Subtract, remainder), // Command::Wait => {} - // Command::Xor => {} + Command::Xor => command::parse_logical_binary( + LogicalOperator::Binary(BinaryLogic::Xor), + remainder, + ), _ => Err(nom::Err::Failure(Error { input: &input[..1], error: ErrorKind::UnsupportedInstruction, @@ -149,8 +162,8 @@ mod tests { use std::collections::HashMap; use crate::instruction::{ - Label, Reset, SetFrequency, SetPhase, SetScale, ShiftFrequency, ShiftPhase, Waveform, - WaveformDefinition, + BinaryLogic, Label, Logic, LogicalOperator, Reset, SetFrequency, SetPhase, SetScale, + ShiftFrequency, ShiftPhase, Waveform, WaveformDefinition, }; use crate::parser::lexer::lex; use crate::{ @@ -242,6 +255,79 @@ mod tests { ] ); + make_test!( + logic, + parse_instructions, + "AND ro ro[1]\nOR ro ro[1]\nIOR ro[1] ro[2]\nXOR ro[1] ro\nAND ro[1] ro[2]", + vec![ + Instruction::Logic(Logic { + operator: LogicalOperator::Binary(BinaryLogic::And), + operands: [ + MemoryReference { + name: "ro".to_owned(), + index: 0 + }, + MemoryReference { + name: "ro".to_owned(), + index: 1 + } + ] + }), + Instruction::Logic(Logic { + operator: LogicalOperator::Binary(BinaryLogic::Or), + operands: [ + MemoryReference { + name: "ro".to_owned(), + index: 0 + }, + MemoryReference { + name: "ro".to_owned(), + index: 1 + } + ] + }), + Instruction::Logic(Logic { + operator: LogicalOperator::Binary(BinaryLogic::Ior), + operands: [ + MemoryReference { + name: "ro".to_owned(), + index: 1 + }, + MemoryReference { + name: "ro".to_owned(), + index: 2 + } + ] + }), + Instruction::Logic(Logic { + operator: LogicalOperator::Binary(BinaryLogic::Xor), + operands: [ + MemoryReference { + name: "ro".to_owned(), + index: 1 + }, + MemoryReference { + name: "ro".to_owned(), + index: 0 + } + ] + }), + Instruction::Logic(Logic { + operator: LogicalOperator::Binary(BinaryLogic::And), + operands: [ + MemoryReference { + name: "ro".to_owned(), + index: 1 + }, + MemoryReference { + name: "ro".to_owned(), + index: 2 + } + ] + }), + ] + ); + make_test!( capture_instructions, parse_instructions, diff --git a/src/parser/lexer.rs b/src/parser/lexer.rs index 4db79e2a..8b1e6f0f 100644 --- a/src/parser/lexer.rs +++ b/src/parser/lexer.rs @@ -96,6 +96,7 @@ pub enum Command { Neg, Nop, Not, + Or, Pragma, Pulse, RawCapture, @@ -196,6 +197,7 @@ fn recognize_command_or_identifier(identifier: String) -> Token { "DEFGATE" => Token::Command(DefGate), "ADD" => Token::Command(Add), "AND" => Token::Command(And), + "OR" => Token::Command(Or), "CONVERT" => Token::Command(Convert), "DIV" => Token::Command(Div), "EQ" => Token::Command(Eq), @@ -343,6 +345,13 @@ fn lex_variable(input: &str) -> LexResult { })(input) } +// fn lex_logical_binary_op(input: &str) -> LexResult { +// use Token::*; +// alt(( +// value() +// ))(input) +// } + #[cfg(test)] mod tests { use super::{lex, Command, Operator, Token}; diff --git a/src/program/graph.rs b/src/program/graph.rs index b8eef721..3f85454c 100644 --- a/src/program/graph.rs +++ b/src/program/graph.rs @@ -511,6 +511,7 @@ impl ScheduledProgram { let instruction_index = Some(index); match instruction { Instruction::Arithmetic(_) + | Instruction::Logic(_) | Instruction::Capture(_) | Instruction::Delay(_) | Instruction::Fence(_) diff --git a/src/program/memory.rs b/src/program/memory.rs index f71a31bf..6841d3df 100644 --- a/src/program/memory.rs +++ b/src/program/memory.rs @@ -18,7 +18,7 @@ use std::collections::HashSet; use crate::expression::Expression; use crate::instruction::{ Arithmetic, ArithmeticOperand, Capture, CircuitDefinition, Delay, Exchange, Gate, - GateDefinition, Instruction, Jump, JumpUnless, JumpWhen, Label, Load, + GateDefinition, Instruction, Jump, JumpUnless, JumpWhen, Label, Load, Logic, LogicalOperator, MeasureCalibrationDefinition, Measurement, MemoryReference, Move, Pulse, RawCapture, SetPhase, SetScale, ShiftPhase, Store, Vector, WaveformInvocation, }; @@ -90,6 +90,16 @@ impl Instruction { /// Return all memory accesses by the instruction - in expressions, captures, and memory manipulation pub fn get_memory_accesses(&self) -> MemoryAccesses { match self { + Instruction::Logic(Logic { operands, operator }) => match operator { + LogicalOperator::Binary(_) => MemoryAccesses { + reads: operands + .iter() + .map(|memref| memref.name.clone()) + .collect::>(), + ..Default::default() + }, + LogicalOperator::Unary(_) => todo!("implement memory access for unary logic"), + }, Instruction::Arithmetic(Arithmetic { destination, source, diff --git a/src/program/mod.rs b/src/program/mod.rs index 5afa3462..830ead1c 100644 --- a/src/program/mod.rs +++ b/src/program/mod.rs @@ -173,6 +173,7 @@ impl Program { | Instruction::Pragma(_) | Instruction::WaveformDefinition(_) | Instruction::Arithmetic(_) + | Instruction::Logic(_) | Instruction::Halt | Instruction::Label(_) | Instruction::Move(_)