#endif typedef unsigned char byte; typedef unsigned short int word; #define FMT(a,b) a, b #define PTRS_PER_FORMAT 2 static const char *arith[4] = { "*" , "*-" , "*+" , "??" } ; static const char *nextar[4] = { ",AR0" , ",AR1" , "" , "" } ; static const char *TMS32010Formats[] = { FMT("0000ssss0aaaaaaa", "add %A%S"), FMT("0000ssss10mmn00n", "add %M%S%N"), FMT("0001ssss0aaaaaaa", "sub %A%S"), FMT("0001ssss10mmn00n", "sub %M%S%N"), FMT("0010ssss0aaaaaaa", "lac %A%S"), FMT("0010ssss10mmn00n", "lac %M%S%N"), FMT("0011000r0aaaaaaa", "sar %R,%A"), FMT("0011000r10mmn00n", "sar %R%M%N"), FMT("0011100r0aaaaaaa", "lar %R,%A"), FMT("0011100r10mmn00n", "lar %R%M%N"), FMT("01000ppp0aaaaaaa", "in %A,%P"), FMT("01000ppp10mmn00n", "in %M,%P%N"), FMT("01001ppp0aaaaaaa", "out %A,%P"), FMT("01001ppp10mmn00n", "out %M,%P%N"), FMT("01010sss0aaaaaaa", "sacl %A"), /* This instruction has a shift but */ FMT("01010sss10mmn00n", "sacl %M%N"), /* is documented as not performed */
typedef unsigned char byte; typedef unsigned short int word; #define FMT(a,b) a, b #define PTRS_PER_FORMAT 2 static const char *arith[8] = { "*", "*-", "*+", "??", "BR0-", "*0-", "*0+", "*BR0+" } ; static const char *nextar[16] = { "", "", "", "", "", "", "", "", ",AR0", ",AR1", ",AR2", ",AR3", ",AR4", ",AR5", ",AR6", ",AR7" } ; static const char *cmpmode[4] = { "0 (ARx = AR0)" , "1 (ARx < AR0)" , "2 (ARx > AR0)" , "3 (ARx <> AR0)" } ; static const char *TMS32025Formats[] = { FMT("0000tttt0aaaaaaa", "add %A,%T"), /* 0xxx */ FMT("0000tttt1mmmnnnn", "add %M,%T%N"), FMT("0001tttt0aaaaaaa", "sub %A,%T"), /* 1xxx */ FMT("0001tttt1mmmnnnn", "sub %M,%T%N"), FMT("0010tttt0aaaaaaa", "lac %A,%T"), /* 2xxx */ FMT("0010tttt1mmmnnnn", "lac %M,%T%N"), FMT("00110rrr0aaaaaaa", "lar %R,%A"), /* 3xxx */ FMT("00110rrr1mmmnnnn", "lar %R%M%N"), FMT("001110000aaaaaaa", "mpy %A"), /* 38xx */ FMT("001110001mmmnnnn", "mpy %M%N"), FMT("001110010aaaaaaa", "sqra %A"), /* 39xx */ FMT("001110011mmmnnnn", "sqra %M%N"), FMT("001110100aaaaaaa", "mpya %A"), /* 3Axx */ FMT("001110101mmmnnnn", "mpya %M%N"), FMT("001110110aaaaaaa", "mpys %A"), /* 3Bxx */ FMT("001110111mmmnnnn", "mpys %M%N"),
/// main! int main(int argc, char *argv[]) { init_debug_list(); ProgramParams params(argc, argv); // Set up cfg values Cfg_SetValue("rust_compiler", "mrustc"); Cfg_SetValueCb("feature", [¶ms](const ::std::string& s) { return params.features.count(s) != 0; }); CompilePhaseV("Target Load", [&]() { Target_SetCfg(params.target); }); if( params.target_saveback != "") { Target_ExportCurSpec(params.target_saveback); return 0; } if( params.infile == "" ) { ::std::cerr << "No input file passed" << ::std::endl; return 1; } if( params.test_harness ) { Cfg_SetFlag("test"); } try { // Parse the crate into AST AST::Crate crate = CompilePhase<AST::Crate>("Parse", [&]() { return Parse_Crate(params.infile); }); crate.m_test_harness = params.test_harness; crate.m_crate_name_suffix = params.crate_name_suffix; if( params.last_stage == ProgramParams::STAGE_PARSE ) { return 0; } // Load external crates. CompilePhaseV("LoadCrates", [&]() { // Hacky! AST::g_crate_overrides = params.crate_overrides; for(const auto& ld : params.lib_search_dirs) { AST::g_crate_load_dirs.push_back(ld); } crate.load_externs(); }); // Iterate all items in the AST, applying syntax extensions CompilePhaseV("Expand", [&]() { Expand(crate); }); if( params.test_harness ) { Expand_TestHarness(crate); } // Extract the crate type and name from the crate attributes auto crate_type = params.crate_type; if( crate_type == ::AST::Crate::Type::Unknown ) { crate_type = crate.m_crate_type; } if( crate_type == ::AST::Crate::Type::Unknown ) { // Assume to be executable crate_type = ::AST::Crate::Type::Executable; } crate.m_crate_type = crate_type; if( crate.m_crate_type == ::AST::Crate::Type::ProcMacro ) { Expand_ProcMacro(crate); } auto crate_name = params.crate_name; if( crate_name == "" ) { crate_name = crate.m_crate_name; } if( crate_name == "" ) { auto s = params.infile.find_last_of('/'); if( s == ::std::string::npos ) s = 0; else s += 1; auto e = params.infile.find_first_of('.', s); if( e == ::std::string::npos ) e = params.infile.size() - s; crate_name = ::std::string(params.infile.begin() + s, params.infile.begin() + e); for(auto& b : crate_name) { if ('0' <= b && b <= '9') { } else if ('A' <= b && b <= 'Z') { } else if (b == '_') { } else if (b == '-') { b = '_'; } else { // TODO: Error? } } } crate.m_crate_name = crate_name; if( params.test_harness ) { crate.m_crate_name += "$test"; } if( params.outfile == "" ) { switch( crate.m_crate_type ) { case ::AST::Crate::Type::RustLib: params.outfile = FMT(params.output_dir << "lib" << crate.m_crate_name << ".hir"); break; case ::AST::Crate::Type::Executable: params.outfile = FMT(params.output_dir << crate.m_crate_name); break; default: params.outfile = FMT(params.output_dir << crate.m_crate_name << ".o"); break; } DEBUG("params.outfile = " << params.outfile); } if( params.debug.dump_ast ) { CompilePhaseV("Dump Expanded", [&]() { Dump_Rust( FMT(params.outfile << "_1_ast.rs").c_str(), crate ); }); } if( params.last_stage == ProgramParams::STAGE_EXPAND ) { return 0; } // Allocator and panic strategies CompilePhaseV("Implicit Crates", [&]() { if( params.test_harness ) { crate.load_extern_crate(Span(), "test"); } if( crate.m_crate_type == ::AST::Crate::Type::Executable || params.test_harness || crate.m_crate_type == ::AST::Crate::Type::ProcMacro ) { bool allocator_crate_loaded = false; ::std::string alloc_crate_name; bool panic_runtime_loaded = false; ::std::string panic_crate_name; bool panic_runtime_needed = false; for(const auto& ec : crate.m_extern_crates) { ::std::ostringstream ss; for(const auto& e : ec.second.m_hir->m_lang_items) ss << e << ","; DEBUG("Looking at lang items from " << ec.first << " : " << ss.str()); if(ec.second.m_hir->m_lang_items.count("mrustc-allocator")) { if( allocator_crate_loaded ) { ERROR(Span(), E0000, "Multiple allocator crates loaded - " << alloc_crate_name << " and " << ec.first); } alloc_crate_name = ec.first; allocator_crate_loaded = true; } if(ec.second.m_hir->m_lang_items.count("mrustc-panic_runtime")) { if( panic_runtime_loaded ) { ERROR(Span(), E0000, "Multiple panic_runtime crates loaded - " << panic_crate_name << " and " << ec.first); } panic_crate_name = ec.first; panic_runtime_loaded = true; } if(ec.second.m_hir->m_lang_items.count("mrustc-needs_panic_runtime")) { panic_runtime_needed = true; } } if( !allocator_crate_loaded ) { crate.load_extern_crate(Span(), "alloc_system"); } if( panic_runtime_needed && !panic_runtime_loaded ) { // TODO: Get a panic method from the command line // - Fall back to abort by default, because mrustc doesn't do unwinding yet. crate.load_extern_crate(Span(), "panic_abort"); } // - `mrustc-main` lang item default crate.m_lang_items.insert(::std::make_pair( ::std::string("mrustc-main"), ::AST::Path("", {AST::PathNode("main")}) )); } }); if( params.emit_depfile != "" ) { ::std::ofstream of { params.emit_depfile }; of << params.outfile << ":"; // - Iterate all loaded files for modules struct H { ::std::ofstream& of; H(::std::ofstream& of): of(of) {} void visit_module(::AST::Module& mod) { if( mod.m_file_info.path != "!" && mod.m_file_info.path.back() != '/' ) { of << " " << mod.m_file_info.path; } // TODO: Should we check anon modules? //for(auto& amod : mod.anon_mods()) { // this->visit_module(*amod); //} for(auto& i : mod.items()) { if(i.data.is_Module()) { this->visit_module(i.data.as_Module()); } } } }; H(of).visit_module(crate.m_root_module); // - Iterate all loaded crates files for(const auto& ec : crate.m_extern_crates) { of << " " << ec.second.m_filename; } // - Iterate all extra files (include! and friends) } // Resolve names to be absolute names (include references to the relevant struct/global/function) // - This does name checking on types and free functions. // - Resolves all identifiers/paths to references CompilePhaseV("Resolve Use", [&]() { Resolve_Use(crate); // - Absolutise and resolve use statements }); CompilePhaseV("Resolve Index", [&]() { Resolve_Index(crate); // - Build up a per-module index of avalable names (faster and simpler later resolve) }); CompilePhaseV("Resolve Absolute", [&]() { Resolve_Absolutise(crate); // - Convert all paths to Absolute or UFCS, and resolve variables }); if( params.debug.dump_ast ) { CompilePhaseV("Temp output - Resolved", [&]() { Dump_Rust( FMT(params.outfile << "_1_ast.rs").c_str(), crate ); }); } if( params.last_stage == ProgramParams::STAGE_RESOLVE ) { return 0; } // -------------------------------------- // HIR Section // -------------------------------------- // Construc the HIR from the AST ::HIR::CratePtr hir_crate = CompilePhase< ::HIR::CratePtr>("HIR Lower", [&]() { return LowerHIR_FromAST(mv$( crate )); }); // Deallocate the original crate crate = ::AST::Crate(); // Replace type aliases (`type`) into the actual type // - Also inserts defaults in trait impls CompilePhaseV("Resolve Type Aliases", [&]() { ConvertHIR_ExpandAliases(*hir_crate); }); // Set up bindings and other useful information. CompilePhaseV("Resolve Bind", [&]() { ConvertHIR_Bind(*hir_crate); }); // Enumerate marker impls on types and other useful metadata CompilePhaseV("Resolve HIR Markings", [&]() { ConvertHIR_Markings(*hir_crate); }); // Determine what trait to use for <T>::Foo (and does some associated type expansion) CompilePhaseV("Resolve UFCS paths", [&]() { ConvertHIR_ResolveUFCS(*hir_crate); }); // Basic constant evalulation (intergers/floats only) CompilePhaseV("Constant Evaluate", [&]() { ConvertHIR_ConstantEvaluate(*hir_crate); }); if( params.debug.dump_hir ) { // DUMP after initial consteval CompilePhaseV("Dump HIR", [&]() { ::std::ofstream os (FMT(params.outfile << "_2_hir.rs")); HIR_Dump( os, *hir_crate ); }); } // === Type checking === // - This can recurse and call the MIR lower to evaluate constants // Check outer items first (types of constants/functions/statics/impls/...) // - Doesn't do any expressions except those in types CompilePhaseV("Typecheck Outer", [&]() { Typecheck_ModuleLevel(*hir_crate); }); // Check the rest of the expressions (including function bodies) CompilePhaseV("Typecheck Expressions", [&]() { Typecheck_Expressions(*hir_crate); }); // === HIR Expansion === // Annotate how each node's result is used CompilePhaseV("Expand HIR Annotate", [&]() { HIR_Expand_AnnotateUsage(*hir_crate); }); // - Now that all types are known, closures can be desugared CompilePhaseV("Expand HIR Closures", [&]() { HIR_Expand_Closures(*hir_crate); }); // - Construct VTables for all traits and impls. // TODO: How early can this be done? CompilePhaseV("Expand HIR VTables", [&]() { HIR_Expand_VTables(*hir_crate); }); // - And calls can be turned into UFCS CompilePhaseV("Expand HIR Calls", [&]() { HIR_Expand_UfcsEverything(*hir_crate); }); CompilePhaseV("Expand HIR Reborrows", [&]() { HIR_Expand_Reborrows(*hir_crate); }); CompilePhaseV("Expand HIR ErasedType", [&]() { HIR_Expand_ErasedType(*hir_crate); }); if( params.debug.dump_hir ) { // DUMP after typecheck (before validation) CompilePhaseV("Dump HIR", [&]() { ::std::ofstream os (FMT(params.outfile << "_2_hir.rs")); HIR_Dump( os, *hir_crate ); }); } // - Ensure that typeck worked (including Fn trait call insertion etc) CompilePhaseV("Typecheck Expressions (validate)", [&]() { Typecheck_Expressions_Validate(*hir_crate); }); if( params.last_stage == ProgramParams::STAGE_TYPECK ) { return 0; } // Lower expressions into MIR CompilePhaseV("Lower MIR", [&]() { HIR_GenerateMIR(*hir_crate); }); if( params.debug.dump_mir ) { // DUMP after generation CompilePhaseV("Dump MIR", [&]() { ::std::ofstream os (FMT(params.outfile << "_3_mir.rs")); MIR_Dump( os, *hir_crate ); }); } // Validate the MIR CompilePhaseV("MIR Validate", [&]() { MIR_CheckCrate(*hir_crate); }); if( params.debug.dump_hir ) { // DUMP after consteval (full HIR again) CompilePhaseV("Dump HIR", [&]() { ::std::ofstream os (FMT(params.outfile << "_2_hir.rs")); HIR_Dump( os, *hir_crate ); }); } // - Expand constants in HIR and virtualise calls CompilePhaseV("MIR Cleanup", [&]() { MIR_CleanupCrate(*hir_crate); }); if( params.debug.full_validate_early || getenv("MRUSTC_FULL_VALIDATE_PREOPT") ) { CompilePhaseV("MIR Validate Full Early", [&]() { MIR_CheckCrate_Full(*hir_crate); }); } // Optimise the MIR CompilePhaseV("MIR Optimise", [&]() { MIR_OptimiseCrate(*hir_crate, params.debug.disable_mir_optimisations); }); if( params.debug.dump_mir ) { // DUMP: After optimisation CompilePhaseV("Dump MIR", [&]() { ::std::ofstream os (FMT(params.outfile << "_3_mir.rs")); MIR_Dump( os, *hir_crate ); }); } CompilePhaseV("MIR Validate PO", [&]() { MIR_CheckCrate(*hir_crate); }); // - Exhaustive MIR validation (follows every code path and checks variable validity) // > DEBUGGING ONLY CompilePhaseV("MIR Validate Full", [&]() { if( params.debug.full_validate || getenv("MRUSTC_FULL_VALIDATE") ) MIR_CheckCrate_Full(*hir_crate); }); if( params.last_stage == ProgramParams::STAGE_MIR ) { return 0; } // TODO: Pass to mark items that are.. // - Signature Exportable (public) // - MIR Exportable (public generic, #[inline], or used by a either of those) // - Require codegen (public or used by an exported function) TransOptions trans_opt; trans_opt.mode = params.codegen.codegen_type == "" ? "c" : params.codegen.codegen_type; trans_opt.build_command_file = params.codegen.emit_build_command; trans_opt.opt_level = params.opt_level; for(const char* libdir : params.lib_search_dirs ) { // Store these paths for use in final linking. hir_crate->m_link_paths.push_back( libdir ); } for(const char* libname : params.libraries ) { hir_crate->m_ext_libs.push_back(::HIR::ExternLibrary { libname }); } trans_opt.emit_debug_info = params.emit_debug_info; // Generate code for non-generic public items (if requested) if( params.test_harness ) { // If the test harness is enabled, override crate type to "Executable" crate_type = ::AST::Crate::Type::Executable; } // Enumerate items to be passed to codegen TransList items = CompilePhase<TransList>("Trans Enumerate", [&]() { switch( crate_type ) { case ::AST::Crate::Type::Unknown: ::std::cerr << "BUG? Unknown crate type" << ::std::endl; exit(1); break; case ::AST::Crate::Type::RustLib: case ::AST::Crate::Type::RustDylib: case ::AST::Crate::Type::CDylib: return Trans_Enumerate_Public(*hir_crate); case ::AST::Crate::Type::ProcMacro: // TODO: proc macros enumerate twice, once as a library (why?) and again as an executable return Trans_Enumerate_Public(*hir_crate); case ::AST::Crate::Type::Executable: return Trans_Enumerate_Main(*hir_crate); } throw ::std::runtime_error("Invalid crate_type value"); }); // - Generate monomorphised versions of all functions CompilePhaseV("Trans Monomorph", [&]() { Trans_Monomorphise_List(*hir_crate, items); }); // - Do post-monomorph inlining CompilePhaseV("MIR Optimise Inline", [&]() { MIR_OptimiseCrate_Inlining(*hir_crate, items); }); // - Clean up no-unused functions //CompilePhaseV("Trans Enumerate Cleanup", [&]() { Trans_Enumerate_Cleanup(*hir_crate, items); }); switch(crate_type) { case ::AST::Crate::Type::Unknown: throw ""; case ::AST::Crate::Type::RustLib: // Generate a loadable .o CompilePhaseV("Trans Codegen", [&]() { Trans_Codegen(params.outfile + ".o", trans_opt, *hir_crate, items, /*is_executable=*/false); }); // Save a loadable HIR dump CompilePhaseV("HIR Serialise", [&]() { HIR_Serialise(params.outfile, *hir_crate); }); // TODO: Link metatdata and object into a .rlib //Trans_Link(params.outfile, params.outfile + ".hir", params.outfile + ".o", CodegenOutput::StaticLibrary); break; case ::AST::Crate::Type::RustDylib: // Generate a .so //CompilePhaseV("Trans Codegen", [&]() { Trans_Codegen(params.outfile + ".so", trans_opt, *hir_crate, items, CodegenOutput::DynamicLibrary); }); CompilePhaseV("Trans Codegen", [&]() { Trans_Codegen(params.outfile + ".o", trans_opt, *hir_crate, items, /*is_executable=*/false); }); // Save a loadable HIR dump CompilePhaseV("HIR Serialise", [&]() { HIR_Serialise(params.outfile, *hir_crate); }); // TODO: Add the metadata to the .so as a non-loadable segment //Trans_Link(params.outfile, params.outfile + ".hir", params.outfile + ".o", CodegenOutput::DynamicLibrary); break; case ::AST::Crate::Type::CDylib: // Generate a .so/.dll CompilePhaseV("Trans Codegen", [&]() { Trans_Codegen(params.outfile, trans_opt, *hir_crate, items, /*is_executable=*/false); }); // - No metadata file //Trans_Link(params.outfile, "", params.outfile + ".o", CodegenOutput::DynamicLibrary); break; case ::AST::Crate::Type::ProcMacro: { // Needs: An executable (the actual macro handler), metadata (for `extern crate foo;`) // 1. Generate code for the .o file // TODO: Is the .o actually needed for proc macros? CompilePhaseV("Trans Codegen", [&]() { Trans_Codegen(params.outfile + ".o", trans_opt, *hir_crate, items, /*is_executable=*/false); }); // 2. Generate code for the plugin itself TransList items2 = CompilePhase<TransList>("Trans Enumerate", [&]() { return Trans_Enumerate_Main(*hir_crate); }); CompilePhaseV("Trans Monomorph", [&]() { Trans_Monomorphise_List(*hir_crate, items2); }); CompilePhaseV("MIR Optimise Inline", [&]() { MIR_OptimiseCrate_Inlining(*hir_crate, items2); }); CompilePhaseV("Trans Codegen", [&]() { Trans_Codegen(params.outfile + "-plugin", trans_opt, *hir_crate, items2, /*is_executable=*/true); }); // - Save a very basic HIR dump, making sure that there's no lang items in it (e.g. `mrustc-main`) hir_crate->m_lang_items.clear(); CompilePhaseV("HIR Serialise", [&]() { HIR_Serialise(params.outfile, *hir_crate); }); //Trans_Link(params.outfile, params.outfile + ".hir", params.outfile + ".o", CodegenOutput::StaticLibrary); //Trans_Link(params.outfile+"-plugin", "", params.outfile + "-plugin.o", CodegenOutput::StaticLibrary); break; } case ::AST::Crate::Type::Executable: CompilePhaseV("Trans Codegen", [&]() { Trans_Codegen(params.outfile, trans_opt, *hir_crate, items, /*is_executable=*/true); }); //Trans_Link(params.outfile, "", params.outfile + ".o", CodegenOutput::Executable); break; } } catch(unsigned int) {} //catch(const CompileError::Base& e) //{ // ::std::cerr << "Parser Error: " << e.what() << ::std::endl; // return 2; //} //catch(const ::std::exception& e) //{ // ::std::cerr << "Misc Error: " << e.what() << ::std::endl; // return 2; //} //catch(const char* e) //{ // ::std::cerr << "Internal Compiler Error: " << e << ::std::endl; // return 2; //} return 0; }
/* Registers bank 0/1 */ static const char *const regfile[32] = { "Reg$00 (INDF)", "Reg$01 (TMR0/OPTION)", "Reg$02 (PCL)", "Reg$03 (STATUS)", "Reg$04 (FSR)", "Reg$05 (PORTA/TRISA)", "Reg$06 (PORTB/TRISB)", "Reg$07", "Reg$08", "Reg$09", "Reg$0A (PCLATH)", "Reg$0B (INTCON)", "Reg$0C (PIR1/PIE1)", "Reg$0D", "Reg$0E (none/PCON)", "Reg$0F", "Reg$10", "Reg$11", "Reg$12", "Reg$13", "Reg$14", "Reg$15", "Reg$16", "Reg$17", "Reg$18", "Reg$19", "Reg$1A", "Reg$1B", "Reg$1C", "Reg$1D", "Reg$1E", "Reg$1F (CMCON/VRCON)" }; /* Registers bank 1 */ /*static const char *const regfile1[32] = { "Reg$00 (INDF)", "Reg$01 (OPTION)", "Reg$02 (PCL)", "Reg$03 (STATUS)", "Reg$04 (FSR)", "Reg$05 (TRISA)", "Reg$06 (TRISB)", "Reg$07", "Reg$08", "Reg$09", "Reg$0A (PCLATH)", "Reg$0B (INTCON)", "Reg$0C (PIE1)", "Reg$0D", "Reg$0E (PCON)", "Reg$0F", "Reg$10", "Reg$11", "Reg$12", "Reg$13", "Reg$14", "Reg$15", "Reg$16", "Reg$17", "Reg$18", "Reg$19", "Reg$1A", "Reg$1B", "Reg$1C", "Reg$1D", "Reg$1E", "Reg$1F (VRCON)" }; static const char **regfile[2] = { regfile0, regfile1 };*/ static const char *const dest[2] = { "W", "Reg" }; static const char *const PIC16C62xFormats[] = { FMT("0000000xx00000", "nop"), FMT("00000000001000", "return"), FMT("00000000001001", "retfie"), FMT("00000001100011", "sleep"), FMT("00000001100100", "clrwdt"), FMT("0000001fffffff", "movwf %F"), FMT("00000100000011", "clrw"), FMT("0000011fffffff", "clrf %F"), FMT("000010dfffffff", "subwf %F,%D"), FMT("000011dfffffff", "decf %F,%D"), FMT("000100dfffffff", "iorwf %F,%D"), FMT("000101dfffffff", "andwf %F,%D"), FMT("000110dfffffff", "xorwf %F,%D"), FMT("000111dfffffff", "addwf %F,%D"), FMT("001000dfffffff", "movf %F,%D"), FMT("001001dfffffff", "comf %F,%D"),
.bpc_a = BPC ## a ## A, \ .bpc_r = BPC ## r, \ .bpc_g = BPC ## g, \ .bpc_b = BPC ## b, \ .unpack = { e0, e1, e2, e3 }, \ .alpha_enable = alpha, \ .unpack_tight = tight, \ .cpp = c, \ .unpack_count = cnt, \ } #define BPC0A 0 static const struct mdp4_format formats[] = { /* name a r g b e0 e1 e2 e3 alpha tight cpp cnt */ FMT(ARGB8888, 8, 8, 8, 8, 1, 0, 2, 3, true, true, 4, 4), FMT(XRGB8888, 8, 8, 8, 8, 1, 0, 2, 3, false, true, 4, 4), FMT(RGB888, 0, 8, 8, 8, 1, 0, 2, 0, false, true, 3, 3), FMT(BGR888, 0, 8, 8, 8, 2, 0, 1, 0, false, true, 3, 3), FMT(RGB565, 0, 5, 6, 5, 1, 0, 2, 0, false, true, 2, 3), FMT(BGR565, 0, 5, 6, 5, 2, 0, 1, 0, false, true, 2, 3), }; uint32_t mdp4_get_formats(enum mdp4_pipe pipe_id, uint32_t *pixel_formats, uint32_t max_formats) { uint32_t i; for (i = 0; i < ARRAY_SIZE(formats); i++) { const struct mdp4_format *f = &formats[i]; if (i == max_formats)