/// Emit the code for a function or task.
Emit the code for a function or task.
Emit the code for a function or task .
pub fn emit_function(&mut self, id: NodeId, env: ParamEnv) -> Result<Rc<EmittedFunction>> {
        if let Some(x) = self.tables.function_defs.get(&id.env(env)) {
            return x.clone();
        }
        let ast = self.ast_for_id(id).as_all().get_subroutine_decl().unwrap();
        info!("Emit function `{}` with {:?}", ast.prototype.name, env);
        // Gather the port details and return type of the function.
        let args = self.canonicalize_func_args(Ref(ast));
        let return_ty = typeck::return_type_of_function(self.cx, &ast.prototype, env);
        let lowered_return_ty = self.emit_type_both(return_ty)?;
        // Create the function signature and function builder.
        let mut sig = llhd::ir::Signature::new();
        sig.set_return_type(lowered_return_ty.0.clone());
        let func_name = ast.prototype.name.to_string();
        let mut mlir_builder = mlir::Builder::new(self.mcx);
        mlir_builder.set_loc(span_to_loc(self.mcx, ast.span()));
        mlir_builder.set_insertion_point_to_end(self.into_mlir.block());
        let mut func_op = circt::builtin::FunctionBuilder::new(&func_name);
        // Gather up the arguments.
        let mut arguments = vec![];
        for arg in &args.args {
            let ty = self.type_of_func_arg(Ref(arg), env);
            let ty = self.emit_type_both(ty)?;
            let ty = match arg.dir {
                ast::SubroutinePortDir::Input => ty,
                ast::SubroutinePortDir::Output
                | ast::SubroutinePortDir::Inout
                | ast::SubroutinePortDir::Ref
                | ast::SubroutinePortDir::ConstRef => pointer_ty(ty),
            };
            func_op.add_arg(arg.name.map(|x| x.value.as_str().to_string()), ty.1);
            sig.add_input(ty.0);
            arguments.push(arg);
        }
        // Gather up the results.
        if !return_ty.is_void() {
            func_op.add_result(None, lowered_return_ty.1);
        }
        // Create the function itself.
        let func_op = func_op.build(&mut mlir_builder);
        let mut func = llhd::ir::UnitData::new(
            llhd::ir::UnitKind::Function,
            llhd::ir::UnitName::Local(func_name.clone()),
            sig,
        );
        let mut builder = llhd::ir::UnitBuilder::new_anonymous(&mut func);
        // Create a unit generator that we will use to populate the function
        // with instructions.
        let mut values = Default::default();
        let mut gen = UnitGenerator::new(self, &mut builder, &mut values, &mut mlir_builder);
        let entry_blk = (gen.builder.block(), func_op.first_block());
        gen.append_to(entry_blk);
        // Add entries for the function arguments to the value table such that
        // things we emit know how to use them. Apply the default values for
        // output operands.
        for (value, arg) in gen
            .builder
            .input_args()
            .zip(func_op.arguments())
            .zip(args.args.iter())
        {
            gen.values.insert(arg.ast.id().into(), value);
            if arg.dir == ast::SubroutinePortDir::Output {
                let default = match arg.default {
                    Some(expr) => gen.emit_rvalue(expr.id(), env)?,
                    None => {
                        let ty = gen.type_of_func_arg(Ref(arg), env);
                        let ty = gen.emit_type_both(ty)?;
                        gen.emit_zero_for_type_both(ty)
                    }
                };
                gen.emit_blocking_assign_llhd((value, None), default)?;
            }
        }
        // Emit the body of the function.
        for item in &ast.items {
            if let ast::SubroutineItem::Stmt(stmt) = item {
                gen.emit_stmt(stmt.id(), env)?;
            }
        }
        // If the function body did not provide proper termination, add a
        // default return.
        if !gen.terminated {
            if return_ty.is_void() {
                gen.mk_ret(None);
            } else {
                let mut return_values = vec![];
                let zero = gen.emit_zero_for_type_both(lowered_return_ty);
                return_values.push(zero);
                gen.mk_ret(return_values);
            }
        }
        // Add the function to the module and return a handle.
        let x = Ok(Rc::new(EmittedFunction {
            unit: self.into.add_unit(func),
            mlir_symbol: func_name,
        }));
        self.tables.function_defs.insert(id.env(env), x.clone());
        x
    }
pub fn emit_function ( & mut self , id : NodeId , env : ParamEnv ) -> Result < Rc < EmittedFunction > > { if let Some ( x ) = self . tables . function_defs . get ( & id . env ( env ) ) { return x . clone ( ) ; } let ast = self . ast_for_id ( id ) . as_all ( ) . get_subroutine_decl ( ) . unwrap ( ) ; info ! ( " " ast prototype name env ) ; // Gather the port details and return type of the function. let args = self . canonicalize_func_args ( Ref ( ast ) ) ; let return_ty = typeck :: return_type_of_function ( self . cx , & ast . prototype , env ) ; let lowered_return_ty = self . emit_type_both ( return_ty ) ? ; // Create the function signature and function builder. let mut sig = llhd :: ir :: Signature :: new ( ) ; sig . set_return_type ( lowered_return_ty . 0 . clone ( ) ) ; let func_name = ast . prototype . name . to_string ( ) ; let mut mlir_builder = mlir :: Builder :: new ( self . mcx ) ; mlir_builder . set_loc ( span_to_loc ( self . mcx , ast . span ( ) ) ) ; mlir_builder . set_insertion_point_to_end ( self . into_mlir . block ( ) ) ; let mut func_op = circt :: builtin :: FunctionBuilder :: new ( & func_name ) ; // Gather up the arguments. let mut arguments = vec ! [ ] ; for arg in & args . args { let ty = self . type_of_func_arg ( Ref ( arg ) , env ) ; let ty = self . emit_type_both ( ty ) ? ; let ty = match arg . dir { ast :: SubroutinePortDir :: Input => ty , ast :: SubroutinePortDir :: Output | ast :: SubroutinePortDir :: Inout | ast :: SubroutinePortDir :: Ref | ast :: SubroutinePortDir :: ConstRef => pointer_ty ( ty ) , } ; func_op . add_arg ( arg . name . map ( | x | x . value . as_str ( ) . to_string ( ) ) , ty . 1 ) ; sig . add_input ( ty . 0 ) ; arguments . push ( arg ) ; } // Gather up the results. if ! return_ty . is_void ( ) { func_op . add_result ( None , lowered_return_ty . 1 ) ; } // Create the function itself. let func_op = func_op . build ( & mut mlir_builder ) ; let mut func = llhd :: ir :: UnitData :: new ( llhd :: ir :: UnitKind :: Function , llhd :: ir :: UnitName :: Local ( func_name . clone ( ) ) , sig , ) ; let mut builder = llhd :: ir :: UnitBuilder :: new_anonymous ( & mut func ) ; // Create a unit generator that we will use to populate the function // with instructions. let mut values = Default :: default ( ) ; let mut gen = UnitGenerator :: new ( self , & mut builder , & mut values , & mut mlir_builder ) ; let entry_blk = ( gen . builder . block ( ) , func_op . first_block ( ) ) ; gen . append_to ( entry_blk ) ; // Add entries for the function arguments to the value table such that // things we emit know how to use them. Apply the default values for // output operands. for ( value , arg ) in gen . builder . input_args ( ) . zip ( func_op . arguments ( ) ) . zip ( args . args . iter ( ) ) { gen . values . insert ( arg . ast . id ( ) . into ( ) , value ) ; if arg . dir == ast :: SubroutinePortDir :: Output { let default = match arg . default { Some ( expr ) => gen . emit_rvalue ( expr . id ( ) , env ) ? , None => { let ty = gen . type_of_func_arg ( Ref ( arg ) , env ) ; let ty = gen . emit_type_both ( ty ) ? ; gen . emit_zero_for_type_both ( ty ) } } ; gen . emit_blocking_assign_llhd ( ( value , None ) , default ) ? ; } } // Emit the body of the function. for item in & ast . items { if let ast :: SubroutineItem :: Stmt ( stmt ) = item { gen . emit_stmt ( stmt . id ( ) , env ) ? ; } } // If the function body did not provide proper termination, add a // default return. if ! gen . terminated { if return_ty . is_void ( ) { gen . mk_ret ( None ) ; } else { let mut return_values = vec ! [ ] ; let zero = gen . emit_zero_for_type_both ( lowered_return_ty ) ; return_values . push ( zero ) ; gen . mk_ret ( return_values ) ; } } // Add the function to the module and return a handle. let x = Ok ( Rc :: new ( EmittedFunction { unit : self . into . add_unit ( func ) , mlir_symbol : func_name , } ) ) ; self . tables . function_defs . insert ( id . env ( env ) , x . clone ( ) ) ; x }
Emit the code for a function or task.
Emit the code for a function or task .
&mut self
id
NodeId
env
ParamEnv