passes: handle FCA in statepoint pass
FCA (First Class Aggregate) may appear in the IR and may contain
live pointers. We need to handle them in the statepoint pass.
Change-Id: I4e23ab7614a84719de49edbda5031f2511743a15
Reviewed-on: https://go-review.googlesource.com/c/157139
Reviewed-by: Than McIntosh <thanm@google.com>
diff --git a/passes/GoStatepoints.cpp b/passes/GoStatepoints.cpp
index 9fca55f..8a00427 100644
--- a/passes/GoStatepoints.cpp
+++ b/passes/GoStatepoints.cpp
@@ -357,6 +357,9 @@
if (auto VT = dyn_cast<VectorType>(T))
if (isGCPointerType(VT->getElementType()))
return true;
+ // FCA is supported.
+ if (T->isStructTy())
+ return hasPointer(T);
return false;
}
@@ -525,6 +528,17 @@
/// (i.e. a PHI or Select of two derived pointers), or c) involves a change
/// from pointer to vector type or back.
static BaseDefiningValueResult findBaseDefiningValue(Value *I) {
+ if (I->getType()->isStructTy())
+ // Assuming FCA is always base.
+ // FCAs appear mostly in the call sequnce where we pass/return multiple
+ // values in registers, e.g. { i8*, i64 }. If it contains the address of
+ // an alloca, the alloca should already be address taken (at least when
+ // creating the FCA), so we don't need to link the FCA back to the alloca.
+ // It is also unlikely to contain past-the-end pointer (we cannot do
+ // pointer arithmetic directly with FCA). So it is safe to treat FCA as
+ // base.
+ return BaseDefiningValueResult(I, true);
+
assert(I->getType()->isPtrOrPtrVectorTy() &&
"Illegal to ask for the base pointer of a non-pointer type");
@@ -1359,6 +1373,22 @@
LandingPad->setOperand(0, C);
}
+// Extract pointer fields from an FCA.
+static void
+extractPointerFromFCA(Value *V, IRBuilder<> &Builder,
+ SmallVectorImpl<Value *> &PtrFields) {
+ Type *T = V->getType();
+ assert(T->isStructTy());
+ for (unsigned i = 0, e = T->getStructNumElements(); i < e; ++i) {
+ Type *ElemT = T->getStructElementType(i);
+ if (ElemT->isPointerTy()) {
+ Value *Field = Builder.CreateExtractValue(V, {i});
+ PtrFields.push_back(Field);
+ } else
+ assert(!hasPointer(ElemT) && "nested FCA is not supported");
+ }
+}
+
static void
makeStatepointExplicitImpl(const CallSite CS, /* to replace */
SmallVectorImpl<Value *> &BasePtrs,
@@ -1392,6 +1422,11 @@
PtrFields.push_back(V);
getPtrBitmapForType(T, DL, PtrFields);
}
+ } else if (V->getType()->isStructTy()) {
+ // Statepoint lowering doesn't handle FCA. So we do it ourselves by
+ // extracting all the pointer fields and letting the statepoint lowering
+ // spill them.
+ extractPointerFromFCA(V, Builder, PtrFields);
} else
PtrFields.push_back(V);
}
@@ -2181,11 +2216,8 @@
// USE - Add to the LiveIn set for this instruction
for (Value *V : I.operands()) {
- // FIXME: skip FCA for now. They appear when pass/return aggregate type
- // in registers (e.g. {i8*, i8*}). They don't seem live across
- // statepoints, so we are probably fine.
- //assert(!isUnhandledGCPointerType(V->getType()) &&
- // "support for FCA unimplemented");
+ assert(!isUnhandledGCPointerType(V->getType()) &&
+ "unexpected value type");
if (isHandledGCPointerType(V->getType()) && !isa<Constant>(V)) {
// The choice to exclude all things constant here is slightly subtle.
// There are two independent reasons:
@@ -2365,9 +2397,8 @@
break;
Value *V = PN->getIncomingValueForBlock(BB);
- // FIXME: skip FCA for now, see the comment in computeLiveInValues.
- //assert(!isUnhandledGCPointerType(V->getType()) &&
- // "support for FCA unimplemented");
+ assert(!isUnhandledGCPointerType(V->getType()) &&
+ "unexpected value type");
if (isHandledGCPointerType(V->getType()) && !isa<Constant>(V)) {
if (isAlloca(V, DVCache))
// Alloca is tracked separately. (It is a Phi arg so it