summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--README.md14
-rw-r--r--docs/target.md50
-rw-r--r--src/mir/optimise.cpp470
-rw-r--r--src/trans/codegen_c.cpp24
-rw-r--r--src/trans/target.cpp67
-rw-r--r--tools/common/toml.h15
6 files changed, 390 insertions, 250 deletions
diff --git a/README.md b/README.md
index 439bae83..49677984 100644
--- a/README.md
+++ b/README.md
@@ -46,6 +46,18 @@ Windows
- Run `vsproject/build_rustc_minicargo.cmd` to attempt to build libstd
+Building non-rustc code
+=======================
+
+To build your own code with mrustc, first you need to build at least libcore (and probably the full standard library).
+This can be done on linux by running `make -f minicargo.mk LIBS`, or on windows with `build_std.cmd`.
+
+Next, run
+- `minicargo -L <path_to_libstd> <crate_path>` to build a cargo project.
+- or, `mrustc -L <path_to_libstd> --out-dir <output_directory> <path_to_main.rs>` to directly invoke mrustc.
+
+For additional options, both programs have a `--help` option.
+
Diagnosing Issues and Reporting Bugs
====================================
@@ -77,6 +89,8 @@ Current Features
- Functional cargo clone (minicargo)
- Includes build script support
- Procedural macros (custom derive)
+- Custom target specifications
+ - See `docs/target.md`
Plans
=====
diff --git a/docs/target.md b/docs/target.md
new file mode 100644
index 00000000..6b5b088d
--- /dev/null
+++ b/docs/target.md
@@ -0,0 +1,50 @@
+
+Target Overrides
+================
+
+Mrustc supports a few targets out of the box (of varying levels of usablity), these are listed in
+`src/trans/target.cpp`. If the built-in targets aren't suitable, a custom target can be specified with the help of a
+custom target toml file.
+
+To specify a target when running `mrustc` (or `minicaro`), pass `--target <triple>` or `--target
+./path/to/target.toml` (the presence of a slash, backwards or forwards, is what determines if the target is treated as
+a custom target file.
+
+
+Custom target format
+--------------------
+
+Recreation of the `arm-linux-gnu` target
+```toml
+[target]
+family = "unix"
+os-name = "linux"
+env-name = "gnu"
+arch = "arm"
+
+[backend.c]
+variant = "gnu"
+target = "arm-linux-gnu"
+```
+
+Recreation of the `i586-windows-gnu` target (with architecture)
+```toml
+[target]
+family = "windows"
+os-name = "windows"
+env-name = "gnu"
+
+[backend.c]
+variant = "gnu"
+target = "mingw32"
+
+[arch]
+name = "x86"
+pointer-bits = 32
+is-big-endian = false
+has-atomic-u8 = true
+has-atomic-u16 = true
+has-atomic-u32 = true
+has-atomic-u64 = false
+has-atomic-ptr = true
+```
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;
});
diff --git a/tools/common/toml.h b/tools/common/toml.h
index e57c28ae..a2c03bf1 100644
--- a/tools/common/toml.h
+++ b/tools/common/toml.h
@@ -42,7 +42,18 @@ struct TomlValue
String,
Integer,
List,
+
};
+ friend ::std::ostream& operator<<(::std::ostream& os, const Type& e) {
+ switch(e)
+ {
+ case Type::Boolean: os << "boolean"; break;
+ case Type::String: os << "string"; break;
+ case Type::Integer: os << "integer"; break;
+ case Type::List: os << "list"; break;
+ }
+ return os;
+ }
struct TypeError:
public ::std::exception
{
@@ -58,6 +69,10 @@ struct TomlValue
const char* what() const noexcept override {
return "toml type error";
}
+ friend ::std::ostream& operator<<(::std::ostream& os, const TypeError& e) {
+ os << "expected " << e.exp << ", got " << e.have;
+ return os;
+ }
};
Type m_type;