This commit allows starting a new goroutine directly from a func value,
not just when the static callee is known.
This is necessary to support the whole time package, not just the
commonly used subset that was compiled with the SimpleDCE pass enabled.
A bug was introduced in the previous commit that led to miscompilations
in the time.Sleep function when the scheduler was disabled, because
time.Sleep (implemented in the runtime) tried to switch to the scheduler
stack.
This commit restores the binary size of most examples to what it was
before, but still reduces static RAM consumption (.bss) slightly. This
gives me some confidence that it does indeed fix the introduced bug.
This scheduler is intended to live along the (stackless) coroutine based
scheduler which is needed for WebAssembly and unsupported platforms. The
stack based scheduler is somewhat simpler in implementation as it does
not require full program transform passes and supports things like
function pointers and interface methods out of the box with no changes.
Code size is reduced in most cases, even in the case where no scheduler
scheduler is used at all. I'm not exactly sure why but these changes
likely allowed some further optimizations somewhere. Even RAM is
slightly reduced, perhaps some global was elminated in the process as
well.
Previously it would use a bitcast, which cannot directly be used on AVR
because functions live in a different address space on AVR. To fix this,
use a ptrtoint/inttoptr pair.
This allows testdata/coroutines.go to be compiled, but due to what
appears to be an LLVM bug cannot be optimized and codegen'ed:
tinygo: /home/ayke/src/github.com/tinygo-org/tinygo/llvm-project/llvm/lib/IR/Constants.cpp:1776: static llvm::Constant *llvm::ConstantExpr::getBitCast(llvm::Constant *, llvm::Type *, bool): Assertion `CastInst::castIsValid(Instruction::BitCast, C, DstTy) && "Invalid constantexpr bitcast!"' failed.
This happens as one of the function passes after the TinyGo passes and
after the module has been verified so most likely it is a bug somewhere
in LLVM.
This is directly useful to avoid some unsafety around runtime.alloc and
should be useful in general.
This pragma has the same form as in the main Go compiler:
https://github.com/golang/go/issues/12312
dumb -> leaking:
make it more clear what this "GC" does: leak everything.
marksweep -> conservative:
"marksweep" is too generic, use "conservative" to differentiate
between future garbage collectors: precise marksweep / mark-compact /
refcounting.
This is part of a larger rafactor that tries to shrink the ir package
and in general tries to shrink the amount of state that is kept around
in the compiler. The end goal is being able to compile packages
independent of each other, linking them together in a later stage. Along
the way, it cleans up lots of old cruft that has accumulated over the
months.
This refactor also results in globals being loaded lazily. This may be a
problem for some specific programs but will probably change back in a
commit in the near future.
Returning a nil value may lead to problems later on. Just return undef
here, so that further compilation will at least be safe (the result
will be discarded anyway).
This allows importing (for example) both
"github.com/tinygo-org/tinygo/src/machine" and "machine" without issues.
The former is renamed to just "machine".
strings.IndexByte was implemented in the runtime up to Go 1.11. It is
implemented using a direct call to internal/bytealg.IndexByte since Go
1.12.
Make sure we remain compatible with both.
Make sure all allocas are created in the entry block and are given the
right lifetimes. This is good for code quality:
* Moving allocas to the entry block makes sure they are always
allocated statically (avoiding the need for a frame pointer) and do
not grow the stack on each new alloca instruction. This is
especially useful in loops where it could otherwise lead to a stack
overflow even though there is no recursion.
* Adding lifetime markers allows LLVM to reuse stack areas for
different allocas as long as their lifetimes do not overlap.
All in all, this reduces code size in all tested cases for the BBC
micro:bit, and reduces code size for most cases for WebAssembly.
This commit adds debug info to function arguments, so that in many cases
you can see them when compiling with less optimizations enabled.
Unfortunately, due to the way Go SSA works, it is hard to preserve them
in many cases.
Local variables are not yet saved.
Also, change the language type to C, to make sure lldb shows function
arguments. The previous language was Modula 3, apparently due to a
off-by-one error somewhere.
No error is produced, so no error needs to be returned. It was missed in
https://github.com/tinygo-org/tinygo/pull/294.
Also, it fixes this smelly code:
if err != nil {
return <something>, nil
}
There could never be an error, so the code was already dead.
Check various locations that $GOROOT may live, including the location of
the go binary. But make it possible to override this autodetection by
setting GOROOT manually as an environment variable.
Instead of assuming all declared (but not defined) functions are CGo
functions, mark all pointer params of externally visible symbols
'nocapture'. This means you may not store pointers between function
calls.
This is already the case when calling CGo functions upstream:
https://golang.org/cmd/cgo/#hdr-Passing_pointers
Instead of storing the value to send/receive in the coroutine promise,
store only a pointer in the promise. This simplifies the code a lot and
allows larger value sizes to be sent across a channel.
Unfortunately, this new system has a code size impact. For example,
compiling testdata/channel.go for the BBC micro:bit, there is an
increase in code size from 4776 bytes to 4856 bytes. However, the
improved flexibility and simplicity of the code should be worth it. If
this becomes an issue, we can always refactor the code at a later time.
This is implemented as follows:
* The parent coroutine allocates space for the return value in its
frame and stores a pointer to this frame in the parent coroutine
handle.
* The child coroutine obtains the alloca from its parent using the
parent coroutine handle. It then stores the result value there.
* The parent value reads the data from the alloca on resumption.
When compiling a piece of code where a function value is called,
the compiler panics if the function value's type is a defined type,
and not just a type literal (function signature): The type assertion
(*types.Signature) fails, because the type of the func value is a
*types.Named.
This patch fixes this by using the type's underlying type, so that a
types.Named is properly turned into its underlying types.Signature,
before the type assertion takes place.
It takes advantage of the property that all types have an underlying type
(both are the same, if a type is not named).
Fixes#320
In Go, it is not possible to construct pointers that are out of bounds
(and not null), so let LLVM know about this fact.
This leads to a significant code size reduction, around 3% in many
cases.
Most of these errors are actually "todo" or "unimplemented" errors, so
the return type is known. This means that compilation can proceed (with
errors) even though the output will be incorrect. This is useful because
this way, all errors in a compilation unit can be shown together to the
user.
This commit adds getValue which gets a const, global, or result of a
local SSA expression and replaces (almost) all uses of parseExpr with
getValue. The only remaining use is in parseInstr, which makes sure an
instruction is only evaluated once.
This commit replaces "unknown type" errors in getLLVMType with panics.
The main reason this is done is that it simplifies the code *a lot*.
Many `if err != nil` lines were there just because of type information.
Additionally, simply panicking is probably a better approach as the only
way this error can be produced is either with big new language features
or a serious compiler bug. Panicking is probably a better way to handle
this error anyway.
The LLVM library we use does not (yet) provide a llvm.Zero (like it
provides a llvm.Undef) so we have implemented our own. However, in
theory it might return an error in some cases.
No real-world errors have been seen in a while and errors would likely
indicate a serious compiler bug anyway (not an external error), so make
it panic instead of returning an error.