#include "llvm/ADT/SmallSet.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/CodeGen/FunctionLoweringInfo.h"
+#include "llvm/CodeGen/MachineFrameInfo.h"
#include "llvm/CodeGen/GCMetadata.h"
#include "llvm/CodeGen/GCStrategy.h"
#include "llvm/CodeGen/SelectionDAG.h"
SDValue SpillSlot = Builder.DAG.CreateStackTemporary(ValueType);
const unsigned FI = cast<FrameIndexSDNode>(SpillSlot)->getIndex();
+ auto *MFI = Builder.DAG.getMachineFunction().getFrameInfo();
+ MFI->markAsStatepointSpillSlotObjectIndex(FI);
+
Builder.FuncInfo.StatepointStackSlots.push_back(FI);
AllocatedStackSlots.push_back(true);
return SpillSlot;
// ch, glue = callseq_end ch, glue
// get_return_value ch, glue
//
- // get_return_value can either be a CopyFromReg to grab the return value from
- // %RAX, or it can be a LOAD to load a value returned by reference via a stack
- // slot.
+ // get_return_value can either be a sequence of CopyFromReg instructions
+ // to grab the return value from the return register(s), or it can be a LOAD
+ // to load a value returned by reference via a stack slot.
- if (HasDef && (CallEnd->getOpcode() == ISD::CopyFromReg ||
- CallEnd->getOpcode() == ISD::LOAD))
- CallEnd = CallEnd->getOperand(0).getNode();
+ if (HasDef) {
+ if (CallEnd->getOpcode() == ISD::LOAD)
+ CallEnd = CallEnd->getOperand(0).getNode();
+ else
+ while (CallEnd->getOpcode() == ISD::CopyFromReg)
+ CallEnd = CallEnd->getOperand(0).getNode();
+ }
assert(CallEnd->getOpcode() == ISD::CALLSEQ_END && "expected!");
- if (HasDef) {
- if (CS.isInvoke()) {
- // Result value will be used in different basic block for invokes
- // so we need to export it now. But statepoint call has a different type
- // than the actual call. It means that standard exporting mechanism will
- // create register of the wrong type. So instead we need to create
- // register with correct type and save value into it manually.
+ // Export the result value if needed
+ const Instruction *GCResult = ISP.getGCResult();
+ if (HasDef && GCResult) {
+ if (GCResult->getParent() != CS.getParent()) {
+ // Result value will be used in a different basic block so we need to
+ // export it now.
+ // Default exporting mechanism will not work here because statepoint call
+ // has a different type than the actual call. It means that by default
+ // llvm will create export register of the wrong type (always i32 in our
+ // case). So instead we need to create export register with correct type
+ // manually.
// TODO: To eliminate this problem we can remove gc.result intrinsics
// completely and make statepoint call to return a tuple.
unsigned Reg = Builder.FuncInfo.CreateRegs(ISP.getActualReturnType());
PendingExports.push_back(Chain);
Builder.FuncInfo.ValueMap[CS.getInstruction()] = Reg;
} else {
- // The value of the statepoint itself will be the value of call itself.
- // We'll replace the actually call node shortly. gc_result will grab
+ // Result value will be used in a same basic block. Don't export it or
+ // perform any explicit register copies.
+ // We'll replace the actuall call node shortly. gc_result will grab
// this value.
Builder.setValue(CS.getInstruction(), ReturnValue);
}
// to the GCStrategy from there (yet).
GCStrategy &S = Builder.GFI->getStrategy();
for (const Value *V : Bases) {
- auto Opt = S.isGCManagedPointer(V);
+ auto Opt = S.isGCManagedPointer(V->getType());
if (Opt.hasValue()) {
assert(Opt.getValue() &&
"non gc managed base pointer found in statepoint");
}
}
for (const Value *V : Ptrs) {
- auto Opt = S.isGCManagedPointer(V);
+ auto Opt = S.isGCManagedPointer(V->getType());
if (Opt.hasValue()) {
assert(Opt.getValue() &&
"non gc managed derived pointer found in statepoint");
}
}
for (const Value *V : Relocations) {
- auto Opt = S.isGCManagedPointer(V);
+ auto Opt = S.isGCManagedPointer(V->getType());
if (Opt.hasValue()) {
assert(Opt.getValue() && "non gc managed pointer relocated");
}
// uses of the corresponding values so that it would automatically
// export them. Relocates of the spilled values does not use original
// value.
- if (StatepointSite.getCallSite().isInvoke())
+ if (RelocateOpers.getUnderlyingCallSite().getParent() !=
+ StatepointInstr->getParent())
Builder.ExportFromCurrentBlock(V);
}
}
ImmutableCallSite CS(ISP.getCallSite());
#ifndef NDEBUG
- // Consistency check. Don't do this for invokes. It would be too
- // expensive to preserve this information across different basic blocks
- if (!CS.isInvoke()) {
- for (const User *U : CS->users()) {
- const CallInst *Call = cast<CallInst>(U);
- if (isGCRelocate(Call))
- StatepointLowering.scheduleRelocCall(*Call);
- }
+ // Consistency check. Check only relocates in the same basic block as thier
+ // statepoint.
+ for (const User *U : CS->users()) {
+ const CallInst *Call = cast<CallInst>(U);
+ if (isGCRelocate(Call) && Call->getParent() == CS.getParent())
+ StatepointLowering.scheduleRelocCall(*Call);
}
#endif
Instruction *I = cast<Instruction>(CI.getArgOperand(0));
assert(isStatepoint(I) && "first argument must be a statepoint token");
- if (isa<InvokeInst>(I)) {
- // For invokes we should have stored call result in a virtual register.
+ if (I->getParent() != CI.getParent()) {
+ // Statepoint is in different basic block so we should have stored call
+ // result in a virtual register.
// We can not use default getValue() functionality to copy value from this
// register because statepoint and actuall call return types can be
// different, and getValue() will use CopyFromReg of the wrong type,
#ifndef NDEBUG
// Consistency check
- // We skip this check for invoke statepoints. It would be too expensive to
- // preserve validation info through different basic blocks.
- if (!RelocateOpers.isTiedToInvoke()) {
+ // We skip this check for relocates not in the same basic block as thier
+ // statepoint. It would be too expensive to preserve validation info through
+ // different basic blocks.
+ if (RelocateOpers.getStatepoint()->getParent() == CI.getParent()) {
StatepointLowering.relocCallVisited(CI);
}
#endif