We don't handle methods that return structs correctly yet so we need to throw NYI.
Failure to do so resulted in a runtime failure when trying to build "Baby Roslyn".
LLVM assumes that the first parameter to methods returning structs is a pointer to the return buffer.
This reduces our percentages somewhat:
All tests:
129 tests, 38679 methods, 34482 good, 4197 bad (89% good)
goes down to
129 tests, 38163 methods, 33708 good, 4455 bad (88% good)
HelloWorld:
1 tests, 328 methods, 294 good, 34 bad (89% good)
goes down to
1 tests, 325 methods, 289 good, 36 bad (88% good)
@pagavlin is working on struct params/returns so we should get these back soon.
`loadAtAddress` of a struct type was always passing true for `IsField` when it is also used for array accesses. This caused failures for arrays of structs. Fix is to look at the ResolvedToken to determine whether the access is a field or not.
`conditionalDerefAddress` had a bug introduced when I refactored it. Since the method that hits this fails later in the reader the IR validation error hasn't yet surfaced. But Roslyn has methods where this bug causes validation errors.
GenIR::castOp incorrectly assumed that the target type of a cast
operation (i.e. castclass or isinst) must be a reference type.
According to ECMA-335, it is legal for the target type to be a value
type: under such a circumstance, the target type is interpreted to be
the boxed version of that value type.
I had hoped to simply use ICorStaticInfo::getTypeForBox to calculate
the boxed type (as in makeBoxDstOperand), but as it turns out, this
confusingly-named method only handles normalization of Nullable<T>.
If the argument to this method is not an instantiation of Nullable<T>,
it simply hands the argument back unchanged. As a result, I had to
write a helper to calculate the boxed type.
Remove CLR headers and add dependency on a prebuild CoreCLR. Most of the headers in the
include\clr subdirectory are removed and now are picked up from a prebuilt coreclr so that
keeping in sync is clearer.
Remaining headers are used to support packing in the PAL. Follow on
work will remove these dependencies.
We need to throw NYI for PInvoke calls until #282 is implemented.
Not doing so caused a crash when building mini-Roslyn.
Remove //TODO that's covered by NYIs.
This sets our numbers back somewhat:
HelloWorld:
before: 1 tests, 323 methods, 293 good, 30 bad (90% good)
after: 1 tests, 323 methods, 282 good, 41 bad (87% good)
All tests:
before: 129 tests, 37905 methods, 33800 good, 4105 bad (89% good)
after: 129 tests, 37905 methods, 32741 good, 5164 bad (86% good)
Closes#364.
Generate an explicit compare+branch+conditional-throw before each integer
divide.
Add a mock configuration flag UseExplicitZeroDivideChecks alongside
UseExplicitNullChecks to facilitate future experiments on what code
size/shape would look like with checks implicit in divide operations.
Closes#64
This method checks the low bit of address, and if set, clears it and dereferences. Otherwise it just returns the unmodified address.
This generates plausible looking code but the method that contains it also has a convertHandle, so the codegen hasn't been tested at runtime yet.
As part of this I refactored the existing conditional expansion code somewhat. No diffs in IR other than changing the failure reason for one method.
Closes#356.
For integer cases, add explicit inline tests immediately prior to
conversion that branch to a block that throws OverflowException if the
source is out-of-bounds.
For floating-point cases, invoke the appropriate runtime helper (with
possibly an up-conversion from float to double first and possibly an
integer narrowing after).
Resolves#48
The code for keeping this alive as a the generic context wasn't careful enough with insertion points. So the store to make a copy of the unmodified this was ending up in the wrong place.
Closes#352.
- For VSD calls, pass the indirection cell as the first parameter and
set the calling convention to CLR_VirtualDispatchStub, which will pass
the first parameter in the appropriate register (EAX/R11 on X86/AMD64,
respectively).
- For methods with a secret parameter, add a synthetic parameter to the
end of the argument list and mark it with the "CLR_SecretParameter"
attribute, which will be placed in the appropraite register (EAX/R10
on X86/AMD64, respectively).
The line to add a mutually exclusive group caused ccformat to fail when
passing --help. That line was for when we passed base and noindex, which
were mutually exclusive and needs to be removed.
Map these to the appropriate LLVM intrinsics that detect overflow and
compute results together.
Also annotate the invalid type/opcode combinations in the operator map
(floats don't have bitwise operations or unsigned or overflow variants).
Closes#65
This gets us the next part of #40.
We use `llvm.frameescape` to indicate that the context-bearing local's address has escaped. This intrinsic requires that the function have a frame poniter, so disable FPO for these methods.
We're still missing the ability to report the context back to the EE via the GC info. Opened Issue #336 for this.
Also fixed a bug in the static field address computation where we weren't capturing the updated helper call result.
For each finally, generate a continuation selector variable, and end the
finally with a switch that jumps to a continuation based on the selector.
For each leave instruction, set the selector variables appropriately for
each finally handler being exited before jumping to the innermost finally.
These explicit sequences match what Clang generates for gotos across
cleanups and what the WinEHPrepare funclet extractor will expect to see.
The 'default' case for each switch targets a block with just an
Unreachable in it (again following Clang's example).
The instructions to set the selector variables are generated and inserted
in the IR during first-pass flow-graph building. I've added a map to the
reader objects tracking where selector stores have been inserted at which
MSIL offsets, updated fgNodeGetEndInsertIRNode to consult the map, and
updated a few places that were manually grabbing a block's terminator to
instead call fgNodeGetEndInsertIRNode, so that 2nd pass IR insertion can
use the correct insertion point when it adds IR to these blocks.
The switch instruction itself (and selector load feeding it) is generated
when processing the first leave across a particular finally, and inserted
when processing the first endfinally for that finally. Since a finally
region can have an arbitrary number of endfinally instructions, endfinally
becomes a branch that targets a block that holds the switch, so that all
endfinally instructions for a given finally can branch to the shared
switch.
Resolves#260