diff options
author | John Hodge <tpg@mutabah.net> | 2018-05-11 08:02:00 +0800 |
---|---|---|
committer | John Hodge <tpg@mutabah.net> | 2018-05-11 08:02:00 +0800 |
commit | 174c4f47160dba499c84986d15180fe4307d4adc (patch) | |
tree | 9d4f154d404efed09c54e27041eaaa9852773e3b /src | |
parent | 3b8d8f1a392a2cb5cad1d57d08ced693a0d197d8 (diff) | |
parent | ba9b4c4da6b9117529370f402e1015bf1730ccb2 (diff) | |
download | mrust-174c4f47160dba499c84986d15180fe4307d4adc.tar.gz |
Merge branch 'master' of https://github.com/thepowersgang/mrustc
Diffstat (limited to 'src')
-rw-r--r-- | src/mir/optimise.cpp | 470 | ||||
-rw-r--r-- | src/trans/codegen_c.cpp | 24 | ||||
-rw-r--r-- | src/trans/target.cpp | 67 |
3 files changed, 311 insertions, 250 deletions
diff --git a/src/mir/optimise.cpp b/src/mir/optimise.cpp index 2cc81258..ae1f3120 100644 --- a/src/mir/optimise.cpp +++ b/src/mir/optimise.cpp @@ -30,6 +30,246 @@ #define DUMP_AFTER_DONE 0 #define CHECK_AFTER_DONE 2 // 1 = Check before GC, 2 = check before and after GC +// ---- +// List of optimisations avaliable +// ---- +bool MIR_Optimise_BlockSimplify(::MIR::TypeResolve& state, ::MIR::Function& fcn); +bool MIR_Optimise_Inlining(::MIR::TypeResolve& state, ::MIR::Function& fcn, bool minimal, const TransList* list=nullptr); +bool MIR_Optimise_SplitAggregates(::MIR::TypeResolve& state, ::MIR::Function& fcn); +bool MIR_Optimise_PropagateSingleAssignments(::MIR::TypeResolve& state, ::MIR::Function& fcn); +bool MIR_Optimise_PropagateKnownValues(::MIR::TypeResolve& state, ::MIR::Function& fcn); +bool MIR_Optimise_DeTemporary(::MIR::TypeResolve& state, ::MIR::Function& fcn); // Eliminate useless temporaries +bool MIR_Optimise_UnifyTemporaries(::MIR::TypeResolve& state, ::MIR::Function& fcn); +bool MIR_Optimise_CommonStatements(::MIR::TypeResolve& state, ::MIR::Function& fcn); +bool MIR_Optimise_UnifyBlocks(::MIR::TypeResolve& state, ::MIR::Function& fcn); +bool MIR_Optimise_ConstPropagte(::MIR::TypeResolve& state, ::MIR::Function& fcn); +bool MIR_Optimise_DeadDropFlags(::MIR::TypeResolve& state, ::MIR::Function& fcn); +bool MIR_Optimise_DeadAssignments(::MIR::TypeResolve& state, ::MIR::Function& fcn); +bool MIR_Optimise_NoopRemoval(::MIR::TypeResolve& state, ::MIR::Function& fcn); +bool MIR_Optimise_GarbageCollect_Partial(::MIR::TypeResolve& state, ::MIR::Function& fcn); +bool MIR_Optimise_GarbageCollect(::MIR::TypeResolve& state, ::MIR::Function& fcn); + +/// A minimum set of optimisations: +/// - Inlines `#[inline(always)]` functions +/// - Simplifies the call graph (by removing chained gotos) +/// - Sorts blocks into a rough flow order +void MIR_OptimiseMin(const StaticTraitResolve& resolve, const ::HIR::ItemPath& path, ::MIR::Function& fcn, const ::HIR::Function::args_t& args, const ::HIR::TypeRef& ret_type) +{ + static Span sp; + TRACE_FUNCTION_F(path); + ::MIR::TypeResolve state { sp, resolve, FMT_CB(ss, ss << path;), ret_type, args, fcn }; + + while( MIR_Optimise_Inlining(state, fcn, true) ) + { + MIR_Cleanup(resolve, path, fcn, args, ret_type); + //MIR_Dump_Fcn(::std::cout, fcn); + #if CHECK_AFTER_ALL + MIR_Validate(resolve, path, fcn, args, ret_type); + #endif + } + + MIR_Optimise_BlockSimplify(state, fcn); + MIR_Optimise_UnifyBlocks(state, fcn); + + //MIR_Optimise_GarbageCollect_Partial(state, fcn); + + MIR_Optimise_GarbageCollect(state, fcn); + //MIR_Validate_Full(resolve, path, fcn, args, ret_type); + MIR_SortBlocks(resolve, path, fcn); + +#if CHECK_AFTER_DONE > 1 + MIR_Validate(resolve, path, fcn, args, ret_type); +#endif + return ; +} +/// Perfom inlining only, using a list of monomorphised functions, then cleans up the flow graph +/// +/// Returns true if any optimisation was performed +bool MIR_OptimiseInline(const StaticTraitResolve& resolve, const ::HIR::ItemPath& path, ::MIR::Function& fcn, const ::HIR::Function::args_t& args, const ::HIR::TypeRef& ret_type, const TransList& list) +{ + static Span sp; + bool rv = false; + TRACE_FUNCTION_FR(path, rv); + ::MIR::TypeResolve state { sp, resolve, FMT_CB(ss, ss << path;), ret_type, args, fcn }; + + while( MIR_Optimise_Inlining(state, fcn, false, &list) ) + { + MIR_Cleanup(resolve, path, fcn, args, ret_type); +#if CHECK_AFTER_ALL + MIR_Validate(resolve, path, fcn, args, ret_type); +#endif + rv = true; + } + + if( rv ) + { + // - Constant propagation (inlining may have lead to some more constant information + MIR_Optimise_ConstPropagte(state, fcn); + // - Unify non-overlapping locals + if(MIR_Optimise_UnifyTemporaries(state, fcn)) + { +#if CHECK_AFTER_ALL + MIR_Validate(resolve, path, fcn, args, ret_type); +#endif + } + // - Remove no-op statements + MIR_Optimise_NoopRemoval(state, fcn); + + // - Simplify the CFG then unify equal blocks + MIR_Optimise_BlockSimplify(state, fcn); + MIR_Optimise_UnifyBlocks(state, fcn); + + // - Remove dead code + MIR_Optimise_GarbageCollect(state, fcn); + // - Sort blocks into a rough flow + MIR_SortBlocks(resolve, path, fcn); + +#if CHECK_AFTER_DONE > 1 + //MIR_Validate_Full(resolve, path, fcn, args, ret_type); + MIR_Validate(resolve, path, fcn, args, ret_type); +#endif + } + + return rv; +} +void MIR_Optimise(const StaticTraitResolve& resolve, const ::HIR::ItemPath& path, ::MIR::Function& fcn, const ::HIR::Function::args_t& args, const ::HIR::TypeRef& ret_type) +{ + static Span sp; + TRACE_FUNCTION_F(path); + ::MIR::TypeResolve state { sp, resolve, FMT_CB(ss, ss << path;), ret_type, args, fcn }; + + bool change_happened; + unsigned int pass_num = 0; + do + { + MIR_ASSERT(state, pass_num < 100, "Too many MIR optimisation iterations"); + + change_happened = false; + TRACE_FUNCTION_FR("Pass " << pass_num, change_happened); + + // >> Simplify call graph (removes gotos to blocks with a single use) + MIR_Optimise_BlockSimplify(state, fcn); + + // >> Apply known constants + change_happened |= MIR_Optimise_ConstPropagte(state, fcn); + #if CHECK_AFTER_ALL + MIR_Validate(resolve, path, fcn, args, ret_type); + #endif + + // Attempt to remove useless temporaries + while( MIR_Optimise_DeTemporary(state, fcn) ) + { + change_happened = true; + } +#if CHECK_AFTER_ALL + MIR_Validate(resolve, path, fcn, args, ret_type); +#endif + + // TODO: Split apart aggregates (just tuples?) where it's never used + // as an aggregate. (Written once, never used directly) + change_happened |= MIR_Optimise_SplitAggregates(state, fcn); + + // >> Replace values from composites if they're known + // - Undoes the inefficiencies from the `match (a, b) { ... }` pattern + change_happened |= MIR_Optimise_PropagateKnownValues(state, fcn); +#if CHECK_AFTER_ALL + MIR_Validate(resolve, path, fcn, args, ret_type); +#endif + + // TODO: Convert `&mut *mut_foo` into `mut_foo` if the source is movable and not used afterwards + +#if DUMP_BEFORE_ALL || DUMP_BEFORE_PSA + if( debug_enabled() ) MIR_Dump_Fcn(::std::cout, fcn); +#endif + // >> Propagate/remove dead assignments + while( MIR_Optimise_PropagateSingleAssignments(state, fcn) ) + change_happened = true; +#if CHECK_AFTER_ALL + MIR_Validate(resolve, path, fcn, args, ret_type); +#endif + + // >> Move common statements (assignments) across gotos. + change_happened |= MIR_Optimise_CommonStatements(state, fcn); + + // >> Combine Duplicate Blocks + change_happened |= MIR_Optimise_UnifyBlocks(state, fcn); + // >> Remove assignments of unsed drop flags + change_happened |= MIR_Optimise_DeadDropFlags(state, fcn); + // >> Remove assignments that are never read + change_happened |= MIR_Optimise_DeadAssignments(state, fcn); + // >> Remove no-op assignments + change_happened |= MIR_Optimise_NoopRemoval(state, fcn); + + #if CHECK_AFTER_ALL + MIR_Validate(resolve, path, fcn, args, ret_type); + #endif + + // >> Inline short functions + if( !change_happened ) + { + bool inline_happened = MIR_Optimise_Inlining(state, fcn, false); + if( inline_happened ) + { + // Apply cleanup again (as monomorpisation in inlining may have exposed a vtable call) + MIR_Cleanup(resolve, path, fcn, args, ret_type); + //MIR_Dump_Fcn(::std::cout, fcn); + change_happened = true; + } + #if CHECK_AFTER_ALL + MIR_Validate(resolve, path, fcn, args, ret_type); + #endif + } + + if( change_happened ) + { + #if DUMP_AFTER_PASS + if( debug_enabled() ) { + MIR_Dump_Fcn(::std::cout, fcn); + } + #endif + #if CHECK_AFTER_PASS && !CHECK_AFTER_ALL + MIR_Validate(resolve, path, fcn, args, ret_type); + #endif + } + + MIR_Optimise_GarbageCollect_Partial(state, fcn); + pass_num += 1; + } while( change_happened ); + + // Run UnifyTemporaries last, then unify blocks, then run some + // optimisations that might be affected + if(MIR_Optimise_UnifyTemporaries(state, fcn)) + { +#if CHECK_AFTER_ALL + MIR_Validate(resolve, path, fcn, args, ret_type); +#endif + MIR_Optimise_UnifyBlocks(state, fcn); + //MIR_Optimise_ConstPropagte(state, fcn); + MIR_Optimise_NoopRemoval(state, fcn); + } + + + #if DUMP_AFTER_DONE + if( debug_enabled() ) { + MIR_Dump_Fcn(::std::cout, fcn); + } + #endif + #if CHECK_AFTER_DONE + // DEFENCE: Run validation _before_ GC (so validation errors refer to the pre-gc numbers) + MIR_Validate(resolve, path, fcn, args, ret_type); + #endif + // GC pass on blocks and variables + // - Find unused blocks, then delete and rewrite all references. + MIR_Optimise_GarbageCollect(state, fcn); + + //MIR_Validate_Full(resolve, path, fcn, args, ret_type); + + MIR_SortBlocks(resolve, path, fcn); +#if CHECK_AFTER_DONE > 1 + MIR_Validate(resolve, path, fcn, args, ret_type); +#endif +} + namespace { ::MIR::BasicBlockId get_new_target(const ::MIR::TypeResolve& state, ::MIR::BasicBlockId bb) { @@ -517,231 +757,6 @@ namespace { } } -// TODO: Move this block of definitions+code above the namespace above. - -bool MIR_Optimise_BlockSimplify(::MIR::TypeResolve& state, ::MIR::Function& fcn); -bool MIR_Optimise_Inlining(::MIR::TypeResolve& state, ::MIR::Function& fcn, bool minimal, const TransList* list=nullptr); -bool MIR_Optimise_SplitAggregates(::MIR::TypeResolve& state, ::MIR::Function& fcn); -bool MIR_Optimise_PropagateSingleAssignments(::MIR::TypeResolve& state, ::MIR::Function& fcn); -bool MIR_Optimise_PropagateKnownValues(::MIR::TypeResolve& state, ::MIR::Function& fcn); -bool MIR_Optimise_DeTemporary(::MIR::TypeResolve& state, ::MIR::Function& fcn); // Eliminate useless temporaries -bool MIR_Optimise_UnifyTemporaries(::MIR::TypeResolve& state, ::MIR::Function& fcn); -bool MIR_Optimise_CommonStatements(::MIR::TypeResolve& state, ::MIR::Function& fcn); -bool MIR_Optimise_UnifyBlocks(::MIR::TypeResolve& state, ::MIR::Function& fcn); -bool MIR_Optimise_ConstPropagte(::MIR::TypeResolve& state, ::MIR::Function& fcn); -bool MIR_Optimise_DeadDropFlags(::MIR::TypeResolve& state, ::MIR::Function& fcn); -bool MIR_Optimise_DeadAssignments(::MIR::TypeResolve& state, ::MIR::Function& fcn); -bool MIR_Optimise_NoopRemoval(::MIR::TypeResolve& state, ::MIR::Function& fcn); -bool MIR_Optimise_GarbageCollect_Partial(::MIR::TypeResolve& state, ::MIR::Function& fcn); -bool MIR_Optimise_GarbageCollect(::MIR::TypeResolve& state, ::MIR::Function& fcn); - -/// A minimum set of optimisations: -/// - Inlines `#[inline(always)]` functions -/// - Simplifies the call graph (by removing chained gotos) -/// - Sorts blocks into a rough flow order -void MIR_OptimiseMin(const StaticTraitResolve& resolve, const ::HIR::ItemPath& path, ::MIR::Function& fcn, const ::HIR::Function::args_t& args, const ::HIR::TypeRef& ret_type) -{ - static Span sp; - TRACE_FUNCTION_F(path); - ::MIR::TypeResolve state { sp, resolve, FMT_CB(ss, ss << path;), ret_type, args, fcn }; - - while( MIR_Optimise_Inlining(state, fcn, true) ) - { - MIR_Cleanup(resolve, path, fcn, args, ret_type); - //MIR_Dump_Fcn(::std::cout, fcn); - #if CHECK_AFTER_ALL - MIR_Validate(resolve, path, fcn, args, ret_type); - #endif - } - - MIR_Optimise_BlockSimplify(state, fcn); - MIR_Optimise_UnifyBlocks(state, fcn); - - //MIR_Optimise_GarbageCollect_Partial(state, fcn); - - MIR_Optimise_GarbageCollect(state, fcn); - //MIR_Validate_Full(resolve, path, fcn, args, ret_type); - MIR_SortBlocks(resolve, path, fcn); - -#if CHECK_AFTER_DONE > 1 - MIR_Validate(resolve, path, fcn, args, ret_type); -#endif - return ; -} -/// Optimise doing inlining then cleaning up the mess -/// -/// Returns true if any optimisation was performed -/// -/// NOTE: This function can only be called after enumeration and monomorphisation, so it takes the TransList by reference not nullable pointer -bool MIR_OptimiseInline(const StaticTraitResolve& resolve, const ::HIR::ItemPath& path, ::MIR::Function& fcn, const ::HIR::Function::args_t& args, const ::HIR::TypeRef& ret_type, const TransList& list) -{ - static Span sp; - bool rv = false; - TRACE_FUNCTION_FR(path, rv); - ::MIR::TypeResolve state { sp, resolve, FMT_CB(ss, ss << path;), ret_type, args, fcn }; - - while( MIR_Optimise_Inlining(state, fcn, false, &list) ) - { - MIR_Cleanup(resolve, path, fcn, args, ret_type); -#if CHECK_AFTER_ALL - MIR_Validate(resolve, path, fcn, args, ret_type); -#endif - rv = true; - } - - if( rv ) - { - MIR_Optimise_BlockSimplify(state, fcn); - MIR_Optimise_UnifyBlocks(state, fcn); - - MIR_Optimise_GarbageCollect(state, fcn); - //MIR_Validate_Full(resolve, path, fcn, args, ret_type); - MIR_SortBlocks(resolve, path, fcn); - -#if CHECK_AFTER_DONE > 1 - MIR_Validate(resolve, path, fcn, args, ret_type); -#endif - } - - return rv; -} -void MIR_Optimise(const StaticTraitResolve& resolve, const ::HIR::ItemPath& path, ::MIR::Function& fcn, const ::HIR::Function::args_t& args, const ::HIR::TypeRef& ret_type) -{ - static Span sp; - TRACE_FUNCTION_F(path); - ::MIR::TypeResolve state { sp, resolve, FMT_CB(ss, ss << path;), ret_type, args, fcn }; - - bool change_happened; - unsigned int pass_num = 0; - do - { - MIR_ASSERT(state, pass_num < 100, "Too many MIR optimisation iterations"); - - change_happened = false; - TRACE_FUNCTION_FR("Pass " << pass_num, change_happened); - - // >> Simplify call graph (removes gotos to blocks with a single use) - MIR_Optimise_BlockSimplify(state, fcn); - - // >> Apply known constants - change_happened |= MIR_Optimise_ConstPropagte(state, fcn); - #if CHECK_AFTER_ALL - MIR_Validate(resolve, path, fcn, args, ret_type); - #endif - - // Attempt to remove useless temporaries - while( MIR_Optimise_DeTemporary(state, fcn) ) - { - change_happened = true; - } -#if CHECK_AFTER_ALL - MIR_Validate(resolve, path, fcn, args, ret_type); -#endif - - // TODO: Split apart aggregates (just tuples?) where it's never used - // as an aggregate. (Written once, never used directly) - change_happened |= MIR_Optimise_SplitAggregates(state, fcn); - - // >> Replace values from composites if they're known - // - Undoes the inefficiencies from the `match (a, b) { ... }` pattern - change_happened |= MIR_Optimise_PropagateKnownValues(state, fcn); -#if CHECK_AFTER_ALL - MIR_Validate(resolve, path, fcn, args, ret_type); -#endif - - // TODO: Convert `&mut *mut_foo` into `mut_foo` if the source is movable and not used afterwards - -#if DUMP_BEFORE_ALL || DUMP_BEFORE_PSA - if( debug_enabled() ) MIR_Dump_Fcn(::std::cout, fcn); -#endif - // >> Propagate/remove dead assignments - while( MIR_Optimise_PropagateSingleAssignments(state, fcn) ) - change_happened = true; -#if CHECK_AFTER_ALL - MIR_Validate(resolve, path, fcn, args, ret_type); -#endif - - // >> Move common statements (assignments) across gotos. - change_happened |= MIR_Optimise_CommonStatements(state, fcn); - - // >> Combine Duplicate Blocks - change_happened |= MIR_Optimise_UnifyBlocks(state, fcn); - // >> Remove assignments of unsed drop flags - change_happened |= MIR_Optimise_DeadDropFlags(state, fcn); - // >> Remove assignments that are never read - change_happened |= MIR_Optimise_DeadAssignments(state, fcn); - // >> Remove no-op assignments - change_happened |= MIR_Optimise_NoopRemoval(state, fcn); - - #if CHECK_AFTER_ALL - MIR_Validate(resolve, path, fcn, args, ret_type); - #endif - - // >> Inline short functions - if( !change_happened ) - { - bool inline_happened = MIR_Optimise_Inlining(state, fcn, false); - if( inline_happened ) - { - // Apply cleanup again (as monomorpisation in inlining may have exposed a vtable call) - MIR_Cleanup(resolve, path, fcn, args, ret_type); - //MIR_Dump_Fcn(::std::cout, fcn); - change_happened = true; - } - #if CHECK_AFTER_ALL - MIR_Validate(resolve, path, fcn, args, ret_type); - #endif - } - - if( change_happened ) - { - #if DUMP_AFTER_PASS - if( debug_enabled() ) { - MIR_Dump_Fcn(::std::cout, fcn); - } - #endif - #if CHECK_AFTER_PASS && !CHECK_AFTER_ALL - MIR_Validate(resolve, path, fcn, args, ret_type); - #endif - } - - MIR_Optimise_GarbageCollect_Partial(state, fcn); - pass_num += 1; - } while( change_happened ); - - // Run UnifyTemporaries last, then unify blocks, then run some - // optimisations that might be affected - if(MIR_Optimise_UnifyTemporaries(state, fcn)) - { -#if CHECK_AFTER_ALL - MIR_Validate(resolve, path, fcn, args, ret_type); -#endif - MIR_Optimise_UnifyBlocks(state, fcn); - //MIR_Optimise_ConstPropagte(state, fcn); - MIR_Optimise_NoopRemoval(state, fcn); - } - - - #if DUMP_AFTER_DONE - if( debug_enabled() ) { - MIR_Dump_Fcn(::std::cout, fcn); - } - #endif - #if CHECK_AFTER_DONE - // DEFENCE: Run validation _before_ GC (so validation errors refer to the pre-gc numbers) - MIR_Validate(resolve, path, fcn, args, ret_type); - #endif - // GC pass on blocks and variables - // - Find unused blocks, then delete and rewrite all references. - MIR_Optimise_GarbageCollect(state, fcn); - - //MIR_Validate_Full(resolve, path, fcn, args, ret_type); - - MIR_SortBlocks(resolve, path, fcn); -#if CHECK_AFTER_DONE > 1 - MIR_Validate(resolve, path, fcn, args, ret_type); -#endif -} // -------------------------------------------------------------------- // Performs basic simplications on the call graph (merging/removing blocks) @@ -1540,7 +1555,7 @@ bool MIR_Optimise_CommonStatements(::MIR::TypeResolve& state, ::MIR::Function& f bool skip = false; ::std::vector<size_t> sources; // Find source blocks - for(size_t bb2_idx = 0; bb2_idx < fcn.blocks.size(); bb2_idx ++) + for(size_t bb2_idx = 0; bb2_idx < fcn.blocks.size() && !skip; bb2_idx ++) { const auto& blk = fcn.blocks[bb2_idx]; // TODO: Handle non-Goto branches? (e.g. calls) @@ -1566,6 +1581,7 @@ bool MIR_Optimise_CommonStatements(::MIR::TypeResolve& state, ::MIR::Function& f else { visit_terminator_target(blk.terminator, [&](const auto& dst_idx) { + // If this terminator points to the current BB, don't attempt to merge if( dst_idx == bb_idx ) { DEBUG(state << " BB" << bb2_idx << " doesn't end Goto - instead " << blk.terminator); skip = true; @@ -1576,6 +1592,8 @@ bool MIR_Optimise_CommonStatements(::MIR::TypeResolve& state, ::MIR::Function& f if( !skip && sources.size() > 1 ) { + // TODO: Should this search for any common statements? + // Found a common assignment, add to the start and remove from sources. auto stmt = ::std::move(fcn.blocks[sources.front()].statements.back()); MIR_DEBUG(state, "Move common final statements from " << sources << " to " << bb_idx << " - " << stmt); diff --git a/src/trans/codegen_c.cpp b/src/trans/codegen_c.cpp index 0171f19f..5df20334 100644 --- a/src/trans/codegen_c.cpp +++ b/src/trans/codegen_c.cpp @@ -559,12 +559,24 @@ namespace { switch( m_compiler ) { case Compiler::Gcc: - if( getenv("CC") ) { - args.push_back( getenv("CC") ); - } - else { - //args.push_back( Target_GetCurSpec().m_c_compiler + "-gcc" ); - args.push_back( "gcc" ); + // Pick the compiler + // - from `CC-${TRIPLE}` environment variable + // - from the $CC environment variable + // - `gcc-${TRIPLE}` (if available) + // - `gcc` as fallback + { + ::std::string varname = "CC-" + Target_GetCurSpec().m_c_compiler; + if( getenv(varname.c_str()) ) { + args.push_back( getenv(varname.c_str()) ); + } + else if( getenv("CC") ) { + args.push_back( getenv("CC") ); + } + else { + // TODO: Determine if the compiler can't be found, and fall back to `gcc` if that's the case + args.push_back( Target_GetCurSpec().m_c_compiler + "-gcc" ); + //args.push_back( "gcc" ); + } } args.push_back("-ffunction-sections"); args.push_back("-pthread"); diff --git a/src/trans/target.cpp b/src/trans/target.cpp index 2bf655a9..81dc8c0c 100644 --- a/src/trans/target.cpp +++ b/src/trans/target.cpp @@ -54,7 +54,18 @@ namespace auto check_path_length = [&](const TomlKeyValue& kv, unsigned len) { if( kv.path.size() != len ) { - // TODO: Error. + if( kv.path.size() > len ) { + ::std::cerr << "ERROR: Unexpected sub-node to " << kv.path << " in " << filename << ::std::endl; + } + else { + ::std::cerr << "ERROR: Expected sub-nodes in " << kv.path << " in " << filename << ::std::endl; + } + exit(1); + } + }; + auto check_path_length_min = [&](const TomlKeyValue& kv, unsigned len) { + if( kv.path.size() < len ) { + ::std::cerr << "ERROR: Expected sub-nodes in " << kv.path << " in " << filename << ::std::endl; } }; @@ -62,6 +73,7 @@ namespace { if( key_val.path[0] == "target" ) { + check_path_length_min(key_val, 2); if( key_val.path[1] == "family" ) { check_path_length(key_val, 2); @@ -77,11 +89,6 @@ namespace check_path_length(key_val, 2); rv.m_env_name = key_val.value.as_string(); } - else if( key_val.path[1] == "env-name" ) - { - check_path_length(key_val, 2); - rv.m_env_name = key_val.value.as_string(); - } else if( key_val.path[1] == "arch" ) { check_path_length(key_val, 2); @@ -103,22 +110,23 @@ namespace } else { - // TODO: Error. + // Error. + ::std::cerr << "ERROR: Unknown architecture name '" << key_val.value.as_string() << "' in " << filename << ::std::endl; + exit(1); } } else { - // TODO: Error/warning + // Warning + ::std::cerr << "Warning: Unknown configuration item " << key_val.path[0] << "." << key_val.path[1] << " in " << filename << ::std::endl; } } else if( key_val.path[0] == "backend" ) { + check_path_length_min(key_val, 2); if( key_val.path[1] == "c" ) { - if( key_val.path.size() <= 2 ) { - // TODO: Error. - continue ; - } + check_path_length_min(key_val, 3); if( key_val.path[2] == "variant" ) { @@ -133,7 +141,8 @@ namespace } else { - // TODO: Error. + ::std::cerr << "ERROR: Unknown C variant name '" << key_val.value.as_string() << "' in " << filename << ::std::endl; + exit(1); } } else if( key_val.path[2] == "target" ) @@ -143,71 +152,90 @@ namespace } else { - // TODO: Warning/error + ::std::cerr << "WARNING: Unknown field backend.c." << key_val.path[2] << " in " << filename << ::std::endl; } } // Does MMIR need configuration? else { - // TODO: Error/warning + ::std::cerr << "WARNING: Unknown configuration item backend." << key_val.path[1] << " in " << filename << ::std::endl; } } else if( key_val.path[0] == "arch" ) { + check_path_length_min(key_val, 2); if( key_val.path[1] == "name" ) { + check_path_length(key_val, 2); + if( rv.m_arch.m_name != "" ) { + ::std::cerr << "ERROR: Architecture already specified to be '" << rv.m_arch.m_name << "'" << ::std::endl; + exit(1); + } rv.m_arch.m_name = key_val.value.as_string(); } else if( key_val.path[1] == "pointer-bits" ) { + check_path_length(key_val, 2); rv.m_arch.m_pointer_bits = key_val.value.as_int(); } else if( key_val.path[1] == "is-big-endian" ) { + check_path_length(key_val, 2); rv.m_arch.m_big_endian = key_val.value.as_bool(); } else if( key_val.path[1] == "has-atomic-u8" ) { + check_path_length(key_val, 2); rv.m_arch.m_atomics.u8 = key_val.value.as_bool(); } else if( key_val.path[1] == "has-atomic-u16" ) { + check_path_length(key_val, 2); rv.m_arch.m_atomics.u16 = key_val.value.as_bool(); } else if( key_val.path[1] == "has-atomic-u32" ) { + check_path_length(key_val, 2); rv.m_arch.m_atomics.u32 = key_val.value.as_bool(); } else if( key_val.path[1] == "has-atomic-u64" ) { + check_path_length(key_val, 2); rv.m_arch.m_atomics.u64 = key_val.value.as_bool(); } else if( key_val.path[1] == "has-atomic-ptr" ) { + check_path_length(key_val, 2); rv.m_arch.m_atomics.ptr = key_val.value.as_bool(); } else { - // TODO: warning/error + ::std::cerr << "WARNING: Unknown field arch." << key_val.path[1] << " in " << filename << ::std::endl; } } else { + ::std::cerr << "WARNING: Unknown configuration item " << key_val.path[0] << " in " << filename << ::std::endl; } } catch(const TomlValue::TypeError& e) { - // TODO: error + ::std::cerr << "ERROR: Invalid type for " << key_val.path << " - " << e << ::std::endl; + exit(1); } } // TODO: Ensure that everything is set + if( rv.m_arch.m_name == "" ) { + ::std::cerr << "ERROR: Architecture not specified in " << filename << ::std::endl; + exit(1); + } return rv; } TargetSpec init_from_spec_name(const ::std::string& target_name) { - // TODO: If there's a '/' or a '\' in the filename, open it as a path, otherwise it has to be a triple. + // If there's a '/' or a '\' in the filename, open it as a path, otherwise assume it's a triple. if( target_name.find('/') != ::std::string::npos || target_name.find('\\') != ::std::string::npos ) { return load_spec_from_file(target_name); @@ -355,6 +383,9 @@ void Target_SetCfg(const ::std::string& target_name) Cfg_SetValue("target_arch", g_target.m_arch.m_name); Cfg_SetValueCb("target_has_atomic", [&](const ::std::string& s) { if(s == "8") return g_target.m_arch.m_atomics.u8; // Has an atomic byte + if(s == "16") return g_target.m_arch.m_atomics.u16; + if(s == "32") return g_target.m_arch.m_atomics.u32; + if(s == "64") return g_target.m_arch.m_atomics.u64; if(s == "ptr") return g_target.m_arch.m_atomics.ptr; // Has an atomic pointer-sized value return false; }); |