The part needing most attention was ddmd.root.ctfloat, ddmd.target (incl.
gen/target.cpp) and ddmd.builtin. The front-end is now prepared for
elaborate compile-time floating-point types to allow for proper cross-
compilation.
This version still uses the host's `real` type for compile-time reals,
except for MSVC hosts, which still use 64-bit doubles (when compiled with
DMD host compiler too).
Some other changes:
* semantic*() of Statements extracted from statement.d to statementsem.d
* mangle() -> mangleToBuffer()
* Identifier::string -> toChars()
* Token::float80value => floatvalue
* Dsymbol::isAggregateMember() => isMember()
* BoolExp is no more
* ddmd.root.ctfloat: LDC-specific CTFE builtins
Fixes issue #1822.
DtoResolveFunction() explicitly excludes body-less abstract functions from
being automatically declared. If we want to emit linking errors like DMD,
we need a LL function for the call (we previously didn't for abstract
functions, so it was null and LDC crashed). Thus make sure the function is
resolved and declared by invoking DtoDeclareFunction().
The front-end fills in missing init expressions (except for the nested
context pointer in most cases), so there are no implicitly initialized
fields for dynamically initialized struct literals.
The front-end is also supposed to make sure there are no overlapping
initializers by using null-expressions for overridden fields, but doesn't
in some cases (DMD issue 16471).
Instead of preferring the first one in lexical field order, now use the
lexically last one to mimic DMD.
The previous code iterated over the fields in lexical order and ignored
the initializer for a field if there were earlier declared fields with
greater offset (and an initializer expression), which is wrong for
anonymous structs inside a union:
union {
struct { int i1; long l = 123; }
struct { int i2; int x = 1; }
}
`x` was previously initialized with 0 (treated as padding).
This was hit when compiling ddmd/lexer.d:1189, where a const(T)* is
implicitly cast to a const(T*).
The DLValue ctor makes sure the LL pointer and the D type are compatible.
Previously, the transitory state only needed and valid during
generation of the LLVM IR for the function body was conflated
with the general codegen metadata for the function declaration
in IrFunction.
There is further potential for cleanup regarding the use of
gIR->func() and so on all over the code base, but this is out
of scope of this commit, which is only concerned with those
IrFunction members moved to FuncGenState.
GitHub: Fixes#1661.
We only needed that findLvalueExp() thing to 1. skip over casts and 2. to
use a (bin)assign's lhs instead of the (bin)assign's result.
Well, by making sure most (bin)assign expression actually return the lhs
lvalue, we don't have this problem anymore and only need to skip over casts
to get to the nested lvalue.
This gets rid of a hacky workaround and brings our AST traversal order
back to normal again.
Just cast it to the full lhs type, except for shift-assignments (always
perform the shift op in the lvalue precision).
The front-end likes to cast the lhs to the type it wants for the
intermediate binop. E.g., incrementing a ubyte lvalue by an integer leads
to `lval += 3` being rewritten to `cast(int)lval += 3`.
Now if we use the full lhs value for the binop, we get an rvalue result
due to the cast. I.e., `cast(int)lval` before evaluating the rhs. So what
we actually want is to load the lhs lvalue `lval` AFTER evaluating the rhs
and cast it to an integer so that the binop is performed in that
precision. The result is casted back to the lvalue type when assigning.
For binassign expressions, return the lhs lvalue directly and don't bother
casting it to the expression's type - the base types apparently always match.
Don't perform a vtable lookup for those, resolve them directly instead.
Fixes issue #1450, where calling the base method in the overwritten
method resulted in an infinite loop and corresponding stack overflow.
* Introduce a DRValue base class to be able to discriminate between
DLValues and DRValues (e.g., function parameters).
* Let DValue::getRVal() return each DValue's value as DRValue.
This allows to convert a DLValue to a DRValue, a snapshot of the
lvalue's current state, while retaining the D type, something we've
previously lost when returning the low-level rvalue directly.
* Let the DtoR/LVal() helpers be the only way to convert a DValue to a
low-level value.
Add the commandline options -fprofile-instr-generate[=filename] and -profile-instr-use=filename
-fprofile-instr-generate
-- Add instrumentation on branches, switches, and function entry; uses LLVM's InstrProf pass.
-- Link to profile runtime that writes instrumentation counters to a file.
-fprofile-instr-use
-- Read profile data from a file and apply branch weights to branches and switches, and annotate functions with entrycount in LLVM IR.
-- Functions with low or high entrycount are marked with 'cold' or 'inlinehint'.
The only statement type without PGO yet is "try-finally".
A new pragma, `pragma(LDC_profile_instr, [ true | false ])`, is added to selectively disable/enable instrumentation of functions (granularity = whole functions).
The runtime library ldc-profile-rt is a copy of LLVM compiler-rt lib/profile. It has to be exactly in-sync with the LLVM version, and thus we need a copy for each PGO-supported LLVM (>=3.7).
import ldc.profile for a D interface to ldc-profile-rt (for example to reset execution counts after a program startup phase).
The instrumentation data is mainly passed on to LLVM: function-entry counts and branch counts/probabilities. LDC marks functions as hot when "execution count is 30% of the maximum function execution count", and marks functions as cold if their count is 1% of maximum function execution count.
The source of LLVM's llvm-profdata tool is hereby included in LDCs repository (different source for each LLVM version), and the binary is included in the install bin folder.
The executable is named "ldc-profdata" to avoid clashing with llvm-profdata on the same machine. This is needed because profdata executable has to be in-sync with the LLVM version used to build LDC.
Maintenance burden: for trunk LLVM, we have to keep ldc-profile-rt and llvm-profdata in sync. There is no diff with upstream; but because of active development there are the occasional API changes.