gollvm: add a Go specific "sret" attribute
With -O3, the argument promotion pass can optimize a StructRet
argument to nonnull noalias. The StructRet attribute is lost.
However, the statepoint pass uses this attribute to detect if a
stack slot is initialized at a call.
Introduce a Go specific "sret" attribute and let the statepoint
pass check for it. This attribute is preserved during the
optimization.
Now precise stack scan works with -O3.
Change-Id: I3cbd8bd8ca7421fd2d4900e73d50edd7c963d56c
Reviewed-on: https://go-review.googlesource.com/c/gollvm/+/165239
Reviewed-by: Than McIntosh <thanm@google.com>
diff --git a/bridge/go-llvm-materialize.cpp b/bridge/go-llvm-materialize.cpp
index dce76d1..e8814c2 100644
--- a/bridge/go-llvm-materialize.cpp
+++ b/bridge/go-llvm-materialize.cpp
@@ -1293,8 +1293,10 @@
{
// Sret attribute if needed
const CABIParamInfo &returnInfo = state.oracle.returnInfo();
- if (returnInfo.disp() == ParmIndirect)
+ if (returnInfo.disp() == ParmIndirect) {
call->addAttribute(1, llvm::Attribute::StructRet);
+ call->addAttribute(1, llvm::Attribute::get(call->getContext(), "go_sret"));
+ }
// Nest attribute if needed
const CABIParamInfo &chainInfo = state.oracle.chainInfo();
diff --git a/passes/GoStatepoints.cpp b/passes/GoStatepoints.cpp
index c9e0ab5..1a3a0e4 100644
--- a/passes/GoStatepoints.cpp
+++ b/passes/GoStatepoints.cpp
@@ -2252,6 +2252,13 @@
return nullptr;
}
+static bool
+hasStructRetAttr(CallBase *Call) {
+ return Call->hasStructRetAttr() ||
+ (Call->getNumArgOperands() > 0 &&
+ Call->getParamAttr(0, "go_sret") != Attribute());
+}
+
/// Compute the live-in set for the location rbegin starting from
/// the live-out set of the basic block
static void computeLiveInValues(BasicBlock::reverse_iterator Begin,
@@ -2360,7 +2367,7 @@
}
if (CallInst *CI = dyn_cast<CallInst>(&I)){
- if (CI->hasStructRetAttr()) {
+ if (hasStructRetAttr(CI)) {
Value *V = CI->getOperand(0);
if (Value *Base = isTrackedAlloca(V, DVCache)) {
AllocaDefs.insert(Base);
@@ -2394,7 +2401,7 @@
}
if (InvokeInst *II = dyn_cast<InvokeInst>(&I)) {
- if (II->hasStructRetAttr()) {
+ if (hasStructRetAttr(II)) {
Value *V = II->getOperand(0);
if (Value *Base = isTrackedAlloca(V, DVCache)) {
AllocaDefs.insert(Base);
@@ -2563,7 +2570,7 @@
if (isTrackedAlloca(Ptr, DVCache) == V)
StoreSize += DL.getTypeStoreSize(SI->getValueOperand()->getType());
} else if (CallInst *CI = dyn_cast<CallInst>(&I)) {
- if (CI->hasStructRetAttr()) {
+ if (hasStructRetAttr(CI)) {
Value *Ptr = CI->getOperand(0);
if (isTrackedAlloca(Ptr, DVCache) == V)
StoreSize += DL.getTypeStoreSize(Ptr->getType()->getPointerElementType());
@@ -2587,7 +2594,7 @@
break;
}
} else if (InvokeInst *II = dyn_cast<InvokeInst>(&I)) {
- if (II->hasStructRetAttr()) {
+ if (hasStructRetAttr(II)) {
Value *Ptr = II->getOperand(0);
if (isTrackedAlloca(Ptr, DVCache) == V)
if (DL.getTypeStoreSize(Ptr->getType()->getPointerElementType()) + PtrSize - 1 >= Size)
@@ -2883,7 +2890,7 @@
// result (passed directly, or indirectly as outgoing arg).
LiveOut.remove(Inst);
if (InvokeInst *II = dyn_cast<InvokeInst>(Inst))
- if (II->hasStructRetAttr()) {
+ if (hasStructRetAttr(II)) {
Value *Ptr = II->getOperand(0);
Value *V = Ptr->stripPointerCasts();
const DataLayout &DL = Inst->getModule()->getDataLayout();
diff --git a/unittests/BackendCore/BackendCABIOracleTests.cpp b/unittests/BackendCore/BackendCABIOracleTests.cpp
index 99f8108..5d7e1b6 100644
--- a/unittests/BackendCore/BackendCABIOracleTests.cpp
+++ b/unittests/BackendCore/BackendCABIOracleTests.cpp
@@ -395,7 +395,7 @@
const char *exp = R"RAW_RESULT(
%cast.0 = bitcast [2 x float]* %p0.addr to <2 x float>*
%ld.0 = load <2 x float>, <2 x float>* %cast.0
- call addrspace(0) void @foo([3 x double]* sret %sret.actual.0, i8* nest undef, <2 x float> %ld.0)
+ call addrspace(0) void @foo([3 x double]* sret "go_sret" %sret.actual.0, i8* nest undef, <2 x float> %ld.0)
%cast.1 = bitcast [3 x double]* %sret.formal.0 to i8*
%cast.2 = bitcast [3 x double]* %sret.actual.0 to i8*
call addrspace(0) void @llvm.memcpy.p0i8.p0i8.i64(i8* align 8 %cast.1, i8* align 8 %cast.2, i64 24, i1 false)