Skip to content

IRGen: More fixes for LLVM's opaque pointers #61459

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 9 commits into from
Oct 18, 2022
28 changes: 23 additions & 5 deletions lib/IRGen/Callee.h
Original file line number Diff line number Diff line change
Expand Up @@ -317,6 +317,7 @@ namespace irgen {
// If this is an await function pointer contains the signature of the await
// call (without return values).
llvm::Type *awaitSignature = nullptr;
bool useSignature = false;

explicit FunctionPointer(Kind kind, llvm::Value *value,
const Signature &signature)
Expand Down Expand Up @@ -364,14 +365,28 @@ namespace irgen {
}

static FunctionPointer createSigned(Kind kind, llvm::Value *value,
PointerAuthInfo authInfo,
const Signature &signature,
bool useSignature = false) {
auto res = FunctionPointer(kind, value, authInfo, signature);
res.useSignature = useSignature;
return res;
}
static FunctionPointer createSignedClosure(Kind kind, llvm::Value *value,
PointerAuthInfo authInfo,
const Signature &signature) {
return FunctionPointer(kind, value, authInfo, signature);
auto res = FunctionPointer(kind, value, authInfo, signature);
res.useSignature = true;
return res;
}


static FunctionPointer createUnsigned(Kind kind, llvm::Value *value,
const Signature &signature) {
return FunctionPointer(kind, value, signature);
const Signature &signature,
bool useSignature = false) {
auto res = FunctionPointer(kind, value, signature);
res.useSignature = useSignature;
return res;
}

static FunctionPointer forDirect(IRGenModule &IGM, llvm::Constant *value,
Expand All @@ -380,9 +395,12 @@ namespace irgen {

static FunctionPointer forDirect(Kind kind, llvm::Constant *value,
llvm::Constant *secondaryValue,
const Signature &signature) {
return FunctionPointer(kind, value, secondaryValue, PointerAuthInfo(),
const Signature &signature,
bool useSignature = false) {
auto res = FunctionPointer(kind, value, secondaryValue, PointerAuthInfo(),
signature);
res.useSignature = useSignature;
return res;
}

static FunctionPointer forExplosionValue(IRGenFunction &IGF,
Expand Down
37 changes: 30 additions & 7 deletions lib/IRGen/GenCall.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5014,13 +5014,13 @@ Callee irgen::getBlockPointerCallee(IRGenFunction &IGF,

Callee irgen::getSwiftFunctionPointerCallee(
IRGenFunction &IGF, llvm::Value *fnPtr, llvm::Value *dataPtr,
CalleeInfo &&calleeInfo, bool castOpaqueToRefcountedContext) {
CalleeInfo &&calleeInfo, bool castOpaqueToRefcountedContext, bool isClosure) {
auto sig = emitCastOfFunctionPointer(IGF, fnPtr, calleeInfo.OrigFnType);
auto authInfo =
PointerAuthInfo::forFunctionPointer(IGF.IGM, calleeInfo.OrigFnType);

auto fn = FunctionPointer::createSigned(calleeInfo.OrigFnType, fnPtr,
authInfo, sig);
auto fn = isClosure ? FunctionPointer::createSignedClosure(calleeInfo.OrigFnType, fnPtr, authInfo, sig) :
FunctionPointer::createSigned(calleeInfo.OrigFnType, fnPtr, authInfo, sig);
if (castOpaqueToRefcountedContext) {
assert(dataPtr && dataPtr->getType() == IGF.IGM.OpaquePtrTy &&
"Expecting trivial closure context");
Expand Down Expand Up @@ -5054,11 +5054,18 @@ StringRef FunctionPointer::getName(IRGenModule &IGM) const {
switch (getBasicKind()) {
case BasicKind::Function:
return getRawPointer()->getName();
case BasicKind::AsyncFunctionPointer:
case BasicKind::AsyncFunctionPointer: {
auto *asyncFnPtr = getDirectPointer();
// Handle windows style async function pointers.
if (auto *ce = dyn_cast<llvm::ConstantExpr>(asyncFnPtr)) {
if (ce->getOpcode() == llvm::Instruction::IntToPtr) {
asyncFnPtr = cast<llvm::Constant>(asyncFnPtr->getOperand(0));
}
}
asyncFnPtr = cast<llvm::Constant>(asyncFnPtr->stripPointerCasts());
return IGM
.getSILFunctionForAsyncFunctionPointer(
cast<llvm::Constant>(getDirectPointer()->getOperand(0)))
->getName();
.getSILFunctionForAsyncFunctionPointer(asyncFnPtr)->getName();
}
}
llvm_unreachable("unhandled case");
}
Expand Down Expand Up @@ -5341,6 +5348,13 @@ void irgen::forwardAsyncCallResult(IRGenFunction &IGF,
}

llvm::FunctionType *FunctionPointer::getFunctionType() const {
// Static async function pointers can read the type off the secondary value
// (the function definition.
if (SecondaryValue) {
assert(kind == FunctionPointer::Kind::AsyncFunctionPointer);
return cast<llvm::Function>(SecondaryValue)->getFunctionType();
}

// Read the function type off the global or else from the Signature.
if (auto *constant = dyn_cast<llvm::Constant>(Value)) {
auto *gv = dyn_cast<llvm::GlobalValue>(Value);
Expand All @@ -5349,6 +5363,15 @@ llvm::FunctionType *FunctionPointer::getFunctionType() const {
->isOpaqueOrPointeeTypeMatches(Sig.getType()));
return Sig.getType();
}

if (useSignature) { // Because of various casting (e.g thin_to_thick) the
// signature of the function Value might mismatch
// (e.g no context argument).
assert(llvm::cast<llvm::PointerType>(Value->getType())
->isOpaqueOrPointeeTypeMatches(Sig.getType()));
return Sig.getType();
}

assert(llvm::cast<llvm::PointerType>(Value->getType())
->isOpaqueOrPointeeTypeMatches(gv->getValueType()));
return cast<llvm::FunctionType>(gv->getValueType());
Expand Down
3 changes: 2 additions & 1 deletion lib/IRGen/GenCall.h
Original file line number Diff line number Diff line change
Expand Up @@ -198,7 +198,8 @@ namespace irgen {
llvm::Value *fnPtr,
llvm::Value *contextPtr,
CalleeInfo &&info,
bool castOpaqueToRefcountedContext);
bool castOpaqueToRefcountedContext,
bool isClosure);

Address emitAllocYieldOnceCoroutineBuffer(IRGenFunction &IGF);
void emitDeallocYieldOnceCoroutineBuffer(IRGenFunction &IGF, Address buffer);
Expand Down
4 changes: 2 additions & 2 deletions lib/IRGen/GenClass.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2798,7 +2798,7 @@ FunctionPointer irgen::emitVirtualMethodValue(IRGenFunction &IGF,
auto authInfo =
PointerAuthInfo::emit(IGF, schema, slot.getAddress(), method);
return FunctionPointer::createSigned(methodType, fnPtr, authInfo,
signature);
signature, true);
}
case ClassMetadataLayout::MethodInfo::Kind::DirectImpl: {
auto fnPtr = llvm::ConstantExpr::getBitCast(methodInfo.getDirectImpl(),
Expand All @@ -2811,7 +2811,7 @@ FunctionPointer irgen::emitVirtualMethodValue(IRGenFunction &IGF,
IGF.IGM.getAddrOfSILFunction(silFn, NotForDefinition));
}
return FunctionPointer::forDirect(methodType, fnPtr, secondaryValue,
signature);
signature, true);
}
}
llvm_unreachable("covered switch");
Expand Down
8 changes: 3 additions & 5 deletions lib/IRGen/GenEnum.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -183,7 +183,7 @@ unsigned EnumImplStrategy::getPayloadSizeForMetadata() const {
llvm_unreachable("don't need payload size for this enum kind");
}

llvm::Value *EnumImplStrategy::
LoadedRef EnumImplStrategy::
loadRefcountedPtr(IRGenFunction &IGF, SourceLoc loc, Address addr) const {
IGF.IGM.error(loc, "Can only load from an address of an optional "
"reference.");
Expand Down Expand Up @@ -2803,13 +2803,11 @@ namespace {
}
}

llvm::Value *loadRefcountedPtr(IRGenFunction &IGF, SourceLoc loc,
LoadedRef loadRefcountedPtr(IRGenFunction &IGF, SourceLoc loc,
Address addr) const override {
// There is no need to bitcast from the enum address. Loading from the
// reference type emits a bitcast to the proper reference type first.
return getLoadablePayloadTypeInfo()
.loadRefcountedPtr(IGF, loc, addr)
.getValue();
return getLoadablePayloadTypeInfo().loadRefcountedPtr(IGF, loc, addr);
}
private:
llvm::ConstantInt *getZeroExtraTagConstant(IRGenModule &IGM) const {
Expand Down
5 changes: 3 additions & 2 deletions lib/IRGen/GenEnum.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
#define SWIFT_IRGEN_GENENUM_H

#include "TypeInfo.h"
#include "LoadableTypeInfo.h"

namespace llvm {
class BasicBlock;
Expand Down Expand Up @@ -441,8 +442,8 @@ class EnumImplStrategy {
virtual bool needsPayloadSizeInMetadata() const = 0;
virtual unsigned getPayloadSizeForMetadata() const;

virtual llvm::Value *loadRefcountedPtr(IRGenFunction &IGF, SourceLoc loc,
Address addr) const;
virtual LoadedRef loadRefcountedPtr(IRGenFunction &IGF, SourceLoc loc,
Address addr) const;

void callOutlinedCopy(IRGenFunction &IGF, Address dest, Address src,
SILType T, IsInitialization_t isInit,
Expand Down
2 changes: 1 addition & 1 deletion lib/IRGen/GenExistential.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1266,7 +1266,7 @@ class ClassExistentialTypeInfo final
LoadedRef loadRefcountedPtr(IRGenFunction &IGF, SourceLoc loc,
Address existential) const override {
Address valueAddr = projectValue(IGF, existential);
return LoadedRef(IGF.emitLoadRefcountedPtr(valueAddr, Refcounting), true);
return LoadedRef(IGF.emitLoadRefcountedPtr(valueAddr, Refcounting), true, Refcounting);
}

llvm::StructType *buildReferenceStorageType(IRGenModule &IGM,
Expand Down
39 changes: 25 additions & 14 deletions lib/IRGen/GenHeap.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1345,17 +1345,31 @@ llvm::Value *IRGenFunction::emitLoadRefcountedPtr(Address addr,
}

llvm::Value *IRGenFunction::
emitIsUniqueCall(llvm::Value *value, SourceLoc loc, bool isNonNull) {
emitIsUniqueCall(llvm::Value *value, ReferenceCounting style, SourceLoc loc, bool isNonNull) {
FunctionPointer fn;
bool nonObjC = !IGM.getAvailabilityContext().isContainedIn(
IGM.Context.getObjCIsUniquelyReferencedAvailability());

if (value->getType() == IGM.RefCountedPtrTy) {
switch (style) {
case ReferenceCounting::Native: {
if (isNonNull)
fn = IGM.getIsUniquelyReferenced_nonNull_nativeFunctionPointer();
else
fn = IGM.getIsUniquelyReferenced_nativeFunctionPointer();
} else if (value->getType() == IGM.UnknownRefCountedPtrTy) {
}
break;
case ReferenceCounting::Bridge: {
if (!isNonNull)
unimplemented(loc, "optional bridge ref");

if (nonObjC)
fn =
IGM.getIsUniquelyReferencedNonObjC_nonNull_bridgeObjectFunctionPointer();
else
fn = IGM.getIsUniquelyReferenced_nonNull_bridgeObjectFunctionPointer();
}
break;
case ReferenceCounting::ObjC:
case ReferenceCounting::Unknown: {
if (nonObjC) {
if (isNonNull)
fn = IGM.getIsUniquelyReferencedNonObjC_nonNullFunctionPointer();
Expand All @@ -1367,18 +1381,15 @@ emitIsUniqueCall(llvm::Value *value, SourceLoc loc, bool isNonNull) {
else
fn = IGM.getIsUniquelyReferencedFunctionPointer();
}
} else if (value->getType() == IGM.BridgeObjectPtrTy) {
if (!isNonNull)
unimplemented(loc, "optional bridge ref");

if (nonObjC)
fn =
IGM.getIsUniquelyReferencedNonObjC_nonNull_bridgeObjectFunctionPointer();
else
fn = IGM.getIsUniquelyReferenced_nonNull_bridgeObjectFunctionPointer();
} else {
}
break;
case ReferenceCounting::Error:
case ReferenceCounting::Block:
case ReferenceCounting::Custom:
case ReferenceCounting::None:
llvm_unreachable("Unexpected LLVM type for a refcounted pointer.");
}

llvm::CallInst *call = Builder.CreateCall(fn, value);
call->setDoesNotThrow();
return call;
Expand Down
3 changes: 2 additions & 1 deletion lib/IRGen/GenObjC.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -664,7 +664,8 @@ Callee irgen::getObjCMethodCallee(IRGenFunction &IGF,

auto fn =
FunctionPointer::forDirect(FunctionPointer::Kind::Function, messenger,
/*secondaryValue*/ nullptr, sig);
/*secondaryValue*/ nullptr, sig,
/*useSignature*/ true);
return Callee(std::move(info), fn, receiverValue, selectorValue);
}

Expand Down
18 changes: 11 additions & 7 deletions lib/IRGen/GenStruct.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -480,10 +480,12 @@ namespace {
clangFnAddr = emitCXXConstructorThunkIfNeeded(
IGF.IGM, signature, copyConstructor, name, clangFnAddr);
callee = cast<llvm::Function>(clangFnAddr);
dest = IGF.coerceValue(dest, callee->getFunctionType()->getParamType(0),
IGF.IGM.DataLayout);
src = IGF.coerceValue(src, callee->getFunctionType()->getParamType(1),
IGF.IGM.DataLayout);
if (IGF.IGM.getLLVMContext().supportsTypedPointers()) {
dest = IGF.coerceValue(dest, callee->getFunctionType()->getParamType(0),
IGF.IGM.DataLayout);
src = IGF.coerceValue(src, callee->getFunctionType()->getParamType(1),
IGF.IGM.DataLayout);
}
IGF.Builder.CreateCall(callee->getFunctionType(), callee, {dest, src});
}

Expand Down Expand Up @@ -532,9 +534,11 @@ namespace {
destructorGlobalDecl, NotForDefinition));

SmallVector<llvm::Value *, 2> args;
auto *thisArg = IGF.coerceValue(address.getAddress(),
destructorFnAddr->getArg(0)->getType(),
IGF.IGM.DataLayout);
auto *thisArg = address.getAddress();
if (IGF.IGM.getLLVMContext().supportsTypedPointers())
thisArg = IGF.coerceValue(address.getAddress(),
destructorFnAddr->getArg(0)->getType(),
IGF.IGM.DataLayout);
args.push_back(thisArg);
llvm::Value *implicitParam =
clang::CodeGen::getCXXDestructorImplicitParam(
Expand Down
5 changes: 3 additions & 2 deletions lib/IRGen/HeapTypeInfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -234,9 +234,10 @@ class HeapTypeInfo

LoadedRef loadRefcountedPtr(IRGenFunction &IGF, SourceLoc loc,
Address addr) const override {
auto style = asDerived().getReferenceCounting();
llvm::Value *ptr =
IGF.emitLoadRefcountedPtr(addr, asDerived().getReferenceCounting());
return LoadedRef(ptr, true);
IGF.emitLoadRefcountedPtr(addr, style);
return LoadedRef(ptr, true, style);
}

ReferenceCounting getReferenceCountingType() const override {
Expand Down
4 changes: 2 additions & 2 deletions lib/IRGen/IRGenFunction.h
Original file line number Diff line number Diff line change
Expand Up @@ -522,8 +522,8 @@ class IRGenFunction {
void emitErrorStrongRetain(llvm::Value *value);
void emitErrorStrongRelease(llvm::Value *value);

llvm::Value *emitIsUniqueCall(llvm::Value *value, SourceLoc loc,
bool isNonNull);
llvm::Value *emitIsUniqueCall(llvm::Value *value, ReferenceCounting style,
SourceLoc loc, bool isNonNull);

llvm::Value *emitIsEscapingClosureCall(llvm::Value *value, SourceLoc loc,
unsigned verificationType);
Expand Down
Loading