-
Notifications
You must be signed in to change notification settings - Fork 6
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
b793d5f
commit b8c9f44
Showing
15 changed files
with
665 additions
and
97 deletions.
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
[package] | ||
name = "p4-cg" | ||
version = "0.1.0" | ||
edition = "2021" | ||
|
||
[dependencies] | ||
p4 = { path = "../../p4" } | ||
thiserror = "1.0.63" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
// Copyright 2024 Oxide Computer Company |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,108 @@ | ||
// Copyright 2024 Oxide Computer Company | ||
|
||
use htq::ast::Parameter; | ||
use p4::hlir::Hlir; | ||
|
||
use crate::{ | ||
error::CodegenError, p4_type_to_htq_type, statement::emit_statement, | ||
RegisterAllocator, | ||
}; | ||
|
||
pub(crate) fn emit_control_functions( | ||
ast: &p4::ast::AST, | ||
hlir: &Hlir, | ||
) -> Result<Vec<htq::ast::Function>, CodegenError> { | ||
let mut result = Vec::default(); | ||
|
||
for control in &ast.controls { | ||
let cf = emit_control(ast, hlir, control)?; | ||
result.extend(cf.into_iter()); | ||
} | ||
|
||
Ok(result) | ||
} | ||
|
||
fn emit_control( | ||
ast: &p4::ast::AST, | ||
hlir: &Hlir, | ||
control: &p4::ast::Control, | ||
) -> Result<Vec<htq::ast::Function>, CodegenError> { | ||
let mut result = Vec::default(); | ||
|
||
let mut parameters = Vec::new(); | ||
for x in &control.parameters { | ||
let p = htq::ast::Parameter { | ||
reg: htq::ast::Register::new(x.name.as_str()), | ||
pointer: true, | ||
typ: p4_type_to_htq_type(&x.ty)?, | ||
}; | ||
parameters.push(p); | ||
} | ||
|
||
result.push(emit_control_apply(ast, hlir, control, ¶meters)?); | ||
|
||
for action in &control.actions { | ||
result.push(emit_control_action( | ||
ast, | ||
hlir, | ||
control, | ||
action, | ||
¶meters, | ||
)?); | ||
} | ||
Ok(result) | ||
} | ||
|
||
fn emit_control_apply( | ||
ast: &p4::ast::AST, | ||
hlir: &Hlir, | ||
control: &p4::ast::Control, | ||
parameters: &[Parameter], | ||
) -> Result<htq::ast::Function, CodegenError> { | ||
let mut ra = RegisterAllocator::default(); | ||
let mut names = control.names(); | ||
let mut statements = Vec::default(); | ||
for s in &control.apply.statements { | ||
statements.extend( | ||
emit_statement(s, ast, hlir, &mut names, &mut ra)?.into_iter(), | ||
) | ||
} | ||
let f = htq::ast::Function { | ||
name: format!("{}_apply", control.name), | ||
parameters: parameters.to_owned(), | ||
statements, | ||
}; | ||
Ok(f) | ||
} | ||
|
||
fn emit_control_action( | ||
ast: &p4::ast::AST, | ||
hlir: &Hlir, | ||
control: &p4::ast::Control, | ||
action: &p4::ast::Action, | ||
parameters: &[Parameter], | ||
) -> Result<htq::ast::Function, CodegenError> { | ||
let mut ra = RegisterAllocator::default(); | ||
let mut names = control.names(); | ||
let mut statements = Vec::default(); | ||
let mut parameters = parameters.to_owned(); | ||
for x in &action.parameters { | ||
let p = htq::ast::Parameter { | ||
reg: htq::ast::Register::new(x.name.as_str()), | ||
pointer: true, | ||
typ: p4_type_to_htq_type(&x.ty)?, | ||
}; | ||
parameters.push(p); | ||
} | ||
for s in &action.statement_block.statements { | ||
statements.extend( | ||
emit_statement(s, ast, hlir, &mut names, &mut ra)?.into_iter(), | ||
) | ||
} | ||
let f = htq::ast::Function { | ||
name: format!("{}_{}", control.name, action.name), | ||
parameters, | ||
statements, | ||
}; | ||
Ok(f) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,18 +1,63 @@ | ||
// Copyright 2024 Oxide Computer Company | ||
|
||
use p4::{ | ||
ast::{DeclarationInfo, Expression, Lvalue}, | ||
lexer::Token, | ||
}; | ||
use thiserror::Error; | ||
|
||
#[derive(Error, Debug)] | ||
pub enum CodegenError { | ||
#[error("There is no equivalent htq type for {0}")] | ||
NoEquivalentType(p4::ast::Type), | ||
|
||
#[error("undefined lvalue \n{0:#?}")] | ||
UndefinedLvalue(Lvalue), | ||
|
||
#[error("cannot assign to \n{0:#?}")] | ||
InvalidAssignment(DeclarationInfo), | ||
|
||
#[error("cannot convert numeric type \n{0:#?}\n to u128")] | ||
NumericConversion(Expression), | ||
|
||
#[error( | ||
"no type information for \n{0:#?}\nthis is likely a type checking bug" | ||
)] | ||
UntypedExpression(Expression), | ||
|
||
#[error( | ||
"parent {0} for member for \n{1:#?}\nnot found: this is likely a front end bug" | ||
)] | ||
MemberParentNotFound(String, Lvalue), | ||
|
||
#[error( | ||
"expected parent of lvalue \n{0:#?}\nto be a struct: this is likely a front end bug" | ||
)] | ||
ExpectedStructParent(Lvalue), | ||
|
||
#[error( | ||
"expected parent of lvalue \n{0:#?}\nto be a header: this is likely a front end bug" | ||
)] | ||
ExpectedHeaderParent(Lvalue), | ||
|
||
#[error("offset for struct or header member \n{0:#?}\nnot found")] | ||
MemberOffsetNotFound(Lvalue), | ||
|
||
#[error("header member {0}\n{1:#?}\nnot found")] | ||
MemberNotFound(String, Lvalue), | ||
|
||
#[error("user defined type {0} not found \n{1:#?}")] | ||
UserDefinedTypeNotFound(String, Token), | ||
|
||
#[error("cannot calculate offset into extern {0} \n{1:#?}")] | ||
CannotOffsetExtern(String, Token), | ||
} | ||
|
||
#[derive(Error, Debug)] | ||
pub enum EmitError { | ||
#[error("io error {0}")] | ||
#[error("io error: {0}")] | ||
Io(#[from] std::io::Error), | ||
|
||
#[error("codegen error {0}")] | ||
#[error("codegen error: {0}")] | ||
Codegen(#[from] CodegenError), | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,8 +1,96 @@ | ||
use htq::ast::{Register, Rset, Statement, Type, Value}; | ||
use p4::ast::{Expression, ExpressionKind}; | ||
|
||
// Copyright 2024 Oxide Computer Company | ||
use crate::error::CodegenError; | ||
use crate::{error::CodegenError, VersionedRegister}; | ||
|
||
// Builds a vector of statements that implement the expression. Returns the | ||
// statements and the register the result of the expression is held in. | ||
pub(crate) fn emit_expression( | ||
expr: &Expression, | ||
) -> Result<(Vec<Statement>, Register, Type), CodegenError> { | ||
let r = VersionedRegister::for_expression(expr); | ||
match &expr.kind { | ||
ExpressionKind::BoolLit(value) => emit_bool_lit(*value, r), | ||
ExpressionKind::BitLit(width, value) => { | ||
emit_bit_lit(*width, *value, r, expr) | ||
} | ||
ExpressionKind::IntegerLit(value) => emit_int_lit(*value, r), | ||
ExpressionKind::SignedLit(width, value) => { | ||
emit_signed_lit(*width, *value, r) | ||
} | ||
ExpressionKind::Call(_) => { | ||
//TODO | ||
Ok(( | ||
Vec::default(), | ||
Register::new("badreg"), | ||
Type::User("badtype".to_owned()), | ||
)) | ||
} | ||
ExpressionKind::Lvalue(_) => { | ||
//TODO | ||
Ok(( | ||
Vec::default(), | ||
Register::new("badreg"), | ||
Type::User("badtype".to_owned()), | ||
)) | ||
} | ||
xpr => todo!("expression: {xpr:?}"), | ||
} | ||
} | ||
|
||
pub(crate) fn emit_bool_lit( | ||
value: bool, | ||
ra: VersionedRegister, | ||
) -> Result<(Vec<Statement>, Register, Type), CodegenError> { | ||
let instrs = vec![Statement::Rset(Rset { | ||
target: ra.clone().to_reg(), | ||
typ: Type::Bool, | ||
source: Value::bool(value), | ||
})]; | ||
Ok((instrs, ra.to_reg(), Type::Bool)) | ||
} | ||
|
||
pub(crate) fn emit_bit_lit( | ||
width: u16, | ||
value: u128, | ||
ra: VersionedRegister, | ||
expr: &Expression, | ||
) -> Result<(Vec<Statement>, Register, Type), CodegenError> { | ||
let value = i128::try_from(value) | ||
.map_err(|_| CodegenError::NumericConversion(expr.clone()))?; | ||
let typ = Type::Bitfield(usize::from(width)); | ||
let instrs = vec![Statement::Rset(Rset { | ||
typ: typ.clone(), | ||
target: ra.clone().to_reg(), | ||
source: Value::number(value), | ||
})]; | ||
Ok((instrs, ra.to_reg(), typ)) | ||
} | ||
|
||
pub(crate) fn emit_int_lit( | ||
value: i128, | ||
ra: VersionedRegister, | ||
) -> Result<(Vec<Statement>, Register, Type), CodegenError> { | ||
let typ = Type::Signed(128); | ||
let instrs = vec![Statement::Rset(Rset { | ||
typ: typ.clone(), | ||
target: ra.clone().to_reg(), | ||
source: Value::number(value), | ||
})]; | ||
Ok((instrs, ra.to_reg(), typ)) | ||
} | ||
|
||
pub(crate) fn _emit_expression( | ||
_stmt: &p4::ast::Expression, | ||
) -> Result<Vec<htq::ast::Statement>, CodegenError> { | ||
todo!() | ||
pub(crate) fn emit_signed_lit( | ||
width: u16, | ||
value: i128, | ||
ra: VersionedRegister, | ||
) -> Result<(Vec<Statement>, Register, Type), CodegenError> { | ||
let typ = Type::Signed(usize::from(width)); | ||
let instrs = vec![Statement::Rset(Rset { | ||
typ: typ.clone(), | ||
target: ra.clone().to_reg(), | ||
source: Value::number(value), | ||
})]; | ||
Ok((instrs, ra.to_reg(), typ)) | ||
} |
Oops, something went wrong.