Skip to content

Commit

Permalink
implement parser extract
Browse files Browse the repository at this point in the history
  • Loading branch information
rcgoodfellow committed Sep 28, 2024
1 parent 3a2e3d6 commit 577a63e
Show file tree
Hide file tree
Showing 4 changed files with 159 additions and 7 deletions.
15 changes: 15 additions & 0 deletions codegen/htq/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,21 @@ pub enum CodegenError {

#[error("transition must be in parser context\n{0:#?}")]
TransitionOutsideParser(Transition),

#[error("call does not have enough arguments\n{0:#?}")]
NotEnoughArgs(Lvalue),

#[error("expected expression got\n{0:#?}")]
ExpectedLvalue(Expression),

#[error("header declaration not found\n{0:#?}")]
HeaderDeclNotFound(Lvalue),

#[error("expected header type for lvalue\n{0:#?}")]
ExpectedHeaderType(Lvalue),

#[error("header definition for type {0} not found for lvalue\n{1:#?}")]
HeaderDefnNotFound(String, Lvalue),
}

#[derive(Error, Debug)]
Expand Down
123 changes: 121 additions & 2 deletions codegen/htq/src/expression.rs
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ pub(crate) fn emit_expression(
}
ExpressionKind::Call(call) => match context {
P4Context::Control(c) => {
let (stmts, blks, value) = emit_call(
let (stmts, blks, value) = emit_call_in_control(
call,
c,
hlir,
Expand Down Expand Up @@ -191,7 +191,44 @@ pub(crate) fn emit_binary_expr_eq(
todo!()
}

pub(crate) fn emit_call(
pub(crate) fn emit_call_in_parser(
call: &p4::ast::Call,
parser: &p4::ast::Parser,
hlir: &Hlir,
ast: &p4::ast::AST,
ra: &mut RegisterAllocator,
afa: &mut AsyncFlagAllocator,
names: &HashMap<String, NameInfo>,
table_context: &mut TableContext,
) -> Result<
(
Vec<Statement>,
Vec<htq::ast::StatementBlock>,
Option<ExpressionValue>,
),
CodegenError,
> {
match call.lval.leaf() {
"extract" => {
let (stmts, result) = emit_extract_call(
call,
parser,
hlir,
ast,
ra,
afa,
names,
table_context,
)?;
Ok((stmts, Vec::default(), result))
}
x => {
todo!("unhandled parser function: {x:#?}");
}
}
}

pub(crate) fn emit_call_in_control(
call: &p4::ast::Call,
control: &p4::ast::Control,
hlir: &Hlir,
Expand Down Expand Up @@ -254,6 +291,88 @@ pub(crate) fn emit_call(
}
}

fn emit_extract_call(
call: &p4::ast::Call,
parser: &p4::ast::Parser,
_hlir: &Hlir,
ast: &p4::ast::AST,
ra: &mut RegisterAllocator,
_afa: &mut AsyncFlagAllocator,
names: &HashMap<String, NameInfo>,
_table_context: &mut TableContext,
) -> Result<(Vec<Statement>, Option<ExpressionValue>), CodegenError> {
let src = &parser.parameters[1].name;
let source = ra.get(src).ok_or(CodegenError::NoRegisterForParameter(
src.to_owned(),
ra.clone(),
))?;

let tgt = call
.args
.first()
.ok_or(CodegenError::NotEnoughArgs(call.lval.clone()))?;
let tgt = match &tgt.kind {
ExpressionKind::Lvalue(lval) => lval,
_ => return Err(CodegenError::ExpectedLvalue(tgt.as_ref().clone())),
};
let target = ra
.get(tgt.root())
.ok_or(CodegenError::RegisterDoesNotExistForLval(tgt.clone()))?;
let output = ra.alloc(&tgt.root());

let info = names
.get(tgt.root())
.ok_or(CodegenError::HeaderDeclNotFound(tgt.clone()))?;

let typename = match &info.ty {
p4::ast::Type::UserDefined(name, _) => name.clone(),
_ => return Err(CodegenError::ExpectedHeaderType(tgt.clone())),
};

let offset = if let Some(hdr) = ast.get_header(&typename) {
hdr.index_of(tgt.leaf())
.ok_or(CodegenError::MemberOffsetNotFound(tgt.clone()))?
} else {
let st = ast.get_struct(&typename).ok_or(
CodegenError::HeaderDefnNotFound(typename.clone(), tgt.clone()),
)?;
st.index_of(tgt.leaf())
.ok_or(CodegenError::MemberOffsetNotFound(tgt.clone()))?
};

let sz = type_size(&info.ty, ast);

let offset_reg =
ra.get("offset")
.ok_or(CodegenError::NoRegisterForParameter(
String::from("offset"),
ra.clone(),
))?;

let extract_stmt = htq::ast::Extract {
output,
target,
target_offset: Value::number(offset as i128),
source,
source_offset: Value::reg(offset_reg.clone()), //TODO
};

let add_offset_stmt = htq::ast::Add {
target: ra.alloc(&offset_reg.0),
typ: Type::Unsigned(32),
source_a: Value::reg(offset_reg),
source_b: Value::number(sz as i128),
};

Ok((
vec![
Statement::Extract(extract_stmt),
Statement::Add(add_offset_stmt),
],
None,
))
}

fn emit_apply_call(
call: &p4::ast::Call,
control: &p4::ast::Control,
Expand Down
6 changes: 6 additions & 0 deletions codegen/htq/src/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,13 +50,19 @@ fn emit_parser(
parameters.push(p);
}

parameters.push(htq::ast::Parameter {
reg: ra.alloc("offset"),
typ: htq::ast::Type::Unsigned(32),
});

let mut names = parser.names();

// TODO XXX parsers cannot have tables, this indicates broken abstractions
// around code generation control flow.
let mut table_context = HashMap::default();

for state in &parser.states {
let mut ra = ra.clone();
// keeps track of register revisions for locals
let mut statements = Vec::default();
let mut blocks = Vec::default();
Expand Down
22 changes: 17 additions & 5 deletions codegen/htq/src/statement.rs
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,12 @@ fn emit_transition(
CodegenError::NoRegisterForParameter(x.name.clone(), ra.clone()),
)?));
}
args.push(Value::reg(ra.get("offset").ok_or(
CodegenError::NoRegisterForParameter(
String::from("offset"),
ra.clone(),
),
)?));

let hdr = targets[0].clone();

Expand Down Expand Up @@ -397,7 +403,7 @@ fn emit_call(
CodegenError,
> {
let (instrs, blocks, _result) = match &context {
P4Context::Control(c) => crate::expression::emit_call(
P4Context::Control(c) => crate::expression::emit_call_in_control(
call,
c,
hlir,
Expand All @@ -408,10 +414,16 @@ fn emit_call(
names,
table_context,
)?,
P4Context::Parser(_) => {
//TODO
(Vec::default(), Vec::default(), None)
}
P4Context::Parser(p) => crate::expression::emit_call_in_parser(
call,
p,
hlir,
ast,
ra,
afa,
names,
table_context,
)?,
};
Ok((instrs, blocks))
}
Expand Down

0 comments on commit 577a63e

Please sign in to comment.