In the future, we can consider adding a G_VACOPY opcode instead of going
through the GIntrinsic for all targets. We do the approach in this patch
because that is what other targets do today.
G_VAARG can be expanded similiar to SelectionDAG::expandVAArg through
LegalizerHelper::lower. This patch implements the lowering through this
style of expansion.
The expansion gets the head of the va_list by loading the pointer to
va_list. Then, the head of the list is adjusted depending on argument
alignment information. This gives a pointer to the element to be read
out of the va_list. Next, the head of the va_list is bumped to the next
element in the list. The new head of the list is stored back to the
original pointer to the head of the va_list so that subsequent G_VAARG
instructions get the next element in the list. Lastly, the element is
loaded from the alignment adjusted pointer constructed earlier.
This change is stacked on #73062.
Previously we allocated one object for each GPR. We also allocated the
same offset twice, once to save for VASTART and then again for the first
register in the save loop.
This patch uses a single object for all the registers and shares this
with VASTART. This is more consistent with other targets like AArch64
and ARM.
I've removed the setValue(nullptr) from the memory operand now. Having a
single object makes me a lot more comfortable about alias analysis being
able to see what is going on. This led to the scheduling changes in
push-pop-popret.ll and vararg.ll.
The computation we use for computing the size already returns 0 when all
registers are allocated. We don't need an if to set it to 0.
Use the size being 0 to check for whether we need to spill registers or
not.
I have another change I want to make to this code, but this change
seemed to stand on its own. I left the curly braces since I need them
for the other change.
MIRBuilder already tells the observer when an instruction is created.
No other legalizer code on any target tells the observer when it
erases the instruction it was asked to legalize.
…[UN]MERGE_VALUES
When MERGE or UNMERGE s64 on a subtarget that is non-64bit, it must have
the D extension and use FPR in order to be legal.
All other instances of MERGE and UNMERGE that can be made legal should
be narrowed, widend, or replaced by the combiner.
Try to pick the FP register bank based on surrounding use/defs. Code is
basically copied from AArch64.
Need legalizer changes to make this more useful. Right now we're stuck
with only being able to FP select types less than or equal to XLen.
All known linkers handle R_RISCV_CALL and R_RISCV_CALL_PLT in the same
way (GNU ld since
https://sourceware.org/pipermail/binutils/2020-August/112750.html).
MO_CALL is for R_RISCV_CALL, a deprecated relocation type. We don't
migrate away from MO_CALL yet.
For GISel we don't have the output difference concern and should weigh
more on simplicity.
Vector Register banks are created for the various register vector
register groupings. getRegBankFromRegClass is implemented to go from
vector TargetRegisterClass to the corresponding vector RegisterBank.
Use a SmallVector of `ValueMapping *` that we populate in the switch for
each register operand. The entry in the SmallVector defaults to nullptr
for each operand so we don't need to write explicit `nullptr` in the
cases.
After this we can generically fill in GPR for registers as a default
case and remove some opcodes from the switch.
Add helper that creates a lambda similar to typeIs, but containing the
predicate check for hasStdExtF and hasStdD. We can use this with legalIf
and all to reduce the number of manual lambdas we need to write.
Coerce the register bank based on the users of the G_LOAD or the
defining instruction for the G_STORE.
s64 on rv32 is handled by forcing the FPRB register bank.