Currently, our intrinsics are generated as functions that have the
usual setup, which means an alloca, and therefore also a jump, for
those intrinsics that return an immediate value. This is especially bad
for unoptimized builds because it means that an intrinsic like
"contains_managed" that should be just "ret 0" or "ret 1" actually ends
up allocating stack space, doing a jump and a store/load sequence
before it finally returns the value.
To fix that, we need a way to stop the generic function declaration
mechanism from allocating stack space for the return value. This
implicitly also kills the jump, because the block for static allocas
isn't required anymore.
Additionally, trans_intrinsic needs to build the return itself instead
of calling finish_fn, because the latter relies on the availability of
the return value pointer.
With these changes, we get the bare minimum code required for our
intrinsics, which makes them small enough that inlining them makes the
resulting code smaller, so we can mark them as "always inline" to get
better performing unoptimized builds.
Optimized builds also benefit slightly from this change as there's less
code for LLVM to translate and the smaller intrinsics help it to make
better inlining decisions for a few code paths.
Building stage2 librustc gets ~1% faster for the optimized version and 5% for
the unoptimized version.
Most arms of the huge match contain the same code, differing only in
small details like the name of the llvm intrinsic that is to be called.
Thus the duplicated code can be factored out into a few functions that
take some parameters to handle the differences.
Simulates borrow checks for '@mut' boxes, or at least it's the same idea. This allows you to store owned values, but mutate them while they're owned by TLS.
This should remove the necessity for a `pop`/`set` pattern to mutate data structures in TLS.
Whenever a lang_item is required, some relevant message is displayed, often with
a span of what triggered the usage of the lang item.
Now "hello word" is as small as:
```rust
#[no_std];
extern {
fn puts(s: *u8);
}
extern "rust-intrinsic" {
fn transmute<T, U>(t: T) -> U;
}
#[start]
fn main(_: int, _: **u8, _: *u8) -> int {
unsafe {
let (ptr, _): (*u8, uint) = transmute("Hello!");
puts(ptr);
}
return 0;
}
```
Allowing them in type signatures is a significant amount of extra work, unfortunately. This also doesn't apply to static values, which takes a different code path.
Changes int/uint range_rev to iterate over range `(hi,lo]` instead of `[hi,lo)`.
Fix#5270.
Also:
* Adds unit tests for int/uint range functions
* Updates the uses of `range_rev` to account for the new semantics. (Note that pretty much all of the updates there were strict improvements to the code in question; yay!)
* Exposes new function, `range_step_inclusive`, which does the range `[hi,lo]`, (at least when `hi-lo` is a multiple of the `step` parameter).
* Special-cases when `|step| == 1` removing unnecessary bounds-check. (I did not check whether LLVM was already performing this optimization; I figure it would be a net win to not leave that analysis to the compiler. If reviewer objects, I can easily remove that from the refactored code.)
(This pull request is a rebased version of PR #7524, which went stale due to recent unrelated changes to num libraries.)
As per @pcwalton's request, `debug!(..)` is only activated when the `debug` cfg is set; that is, for `RUST_LOG=some_module=4 ./some_program` to work, it needs to be compiled with `rustc --cfg debug some_program.rs`. (Although, there is the sneaky `__debug!(..)` macro that is always active, if you *really* need it.)
It functions by making `debug!` expand to `if false { __debug!(..) }` (expanding to an `if` like this is required to make sure `debug!` statements are typechecked and to avoid unused variable warnings), and adjusting trans to skip the pointless branches in `if true ...` and `if false ...`.
The conditional expansion change also required moving the inject-std-macros step into a new pass, and makes it actually insert them at the top of the crate; this means that the cfg stripping traverses over the macros and so filters out the unused ones.
This appears to takes an unoptimised build of `librustc` from 65s to 59s; and the full bootstrap from 18m41s to 18m26s on my computer (with general background use).
`./configure --enable-debug` will enable `debug!` statements in the bootstrap build.
That is, the `b` branch in `if true { a } else { b }` will not be
trans'd, and that expression will be exactly the same as `a`. This
means that, for example, macros conditionally expanding to `if false
{ .. }` (like debug!) will not waste time in LLVM (or trans).
An alloca in an unreachable block would shortcircuit with Undef, but with type
`Type`, rather than type `*Type` (i.e. a plain value, not a pointer) but it is
expected to return a pointer into the stack, leading to confusion and LLVM
asserts later.
Similarly, attaching the range metadata to a Load in an unreachable block
makes LLVM unhappy, since the Load returns Undef.
Fixes#7344.
The Ord impl of Version refered to the algorithm in release candidate versions of semver. [Semantic Versioning 2.0.0](http://semver.org/spec/v2.0.0.html) says, "Build metadata SHOULD be ignored when determining version precedence."
Note that Version's `le` is not "less than or equal to" now, since `lt` ignores build metadata. I think the new ordering algorithm satisfies strict weak ordering which C++ STL requires, instead of strict total ordering.
BTW, is `a || b || ... || x`-style code better or idiomatic in Rust than `if a { return true; } if b { return true; } ... if x { return true; } return false;`-style one?
Note that Version's `le` is not "less than or equal to" now, since `lt`
ignores build metadata. I think the new ordering algorithm satisfies
strict weak ordering which C++ STL requires, instead of strict total
ordering.
This commit fixes some oversights in the Makefile where rustc could be
invoked without some of its dependencies yet in place. (I encountered
the problem in practice; its not just theoretical.)
As written in Makefile.in, $(STAGE$(1)_T_$(2)_H_$(3)) is the way one
writes an invocation of rustc where $(1) is the stage number $(2) is
the target triple $(3) is the host triple. (Other uses of the macro
may plug in actual values or different parameters in for those three
formal parameters.)
When you have invocations of $(STAGE...), you need to make sure that
its dependences are satisfied; otherwise, if someone is using `make
-jN` for certain (large-ish) `N`, one can encounter situations where
GNU make attempts to invoke `rustc` before it has actually copied some
of its libraries into place, such as libmorestack.a, which causes a
link failure when the rustc invocation attempts to link in those
libraries.
In this case, the main prerequisite to add is TSREQ$(1)_T_$(2)_H_$(3),
which is described in Makefile.in as "Prerequisites for using the
stageN compiler to build target artifacts"
----
In addition to adding the extra dependences on TSREQ..., I also
replaced occurrences of the pattern:
TSREQ$(1)_T_$(2)_H_$(3)
$$(TLIB$(1)_T_$(2)_H_$(3))/$(CFG_STDLIB_$(2))
$$(TLIB$(1)_T_$(2)_H_$(3))/$(CFG_EXTRALIB_$(2))
with:
SREQ$(1)_T_$(2)_H_$(3)
which is equivalent to the above, as defined in Makefile.in
----
Finally, for the cases where TSREQ was missing in tests.mk, I went
ahead and put in a dependence on SREQ rather than just TSREQ, since it
was not clear to me how one could expect to compile those cases
without stdlib and extralib.
(It could well be that I should have gone ahead and done the same in
other cases where I saw TSREQ was missing, and put SREQ in those
cases as well. But this seemed like a good measure for now, without
needing to tax my understanding of the overall makefile
infrastructure much further.)
Macros can be conditionally defined because stripping occurs before macro
expansion, but, the built-in macros were only added as part of the actual
expansion process and so couldn't be stripped to have definitions conditional
on cfg flags.
debug! is defined conditionally in terms of the debug config, expanding to
nothing unless the --cfg debug flag is passed (to be precise it expands to
`if false { normal_debug!(...) }` so that they are still type checked, and
to avoid unused variable lints).
Note that the headers are still on `~[T]` when `T` is managed. This is continued from #7605, which removed all the code relying on the headers and removed them from `~T` for non-managed `T`.
Implement set difference, sym. difference, intersection and union using Iterators.
The set methods are left since they are part of the Set trait. A grep over the tree indicates that the four hashset operations have no users at all.
Also remove HashMap::mutate_values since it is unused, replaced by .mut_iter(), and not part of a trait.
Implement the difference, union, etc iterators with the help of a custom
iterator combinator with explicit closure environment. Reported issue #7814
to be able to use the std::iterator filter combinator.