Files
swift-mirror/lib/IRGen/GenPointerAuth.cpp

640 lines
24 KiB
C++

//===--- GenPointerAuth.cpp - IRGen for pointer authentication ------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
//
// This file implements general support for pointer authentication in Swift.
//
//===----------------------------------------------------------------------===//
#include "GenPointerAuth.h"
#include "Callee.h"
#include "ConstantBuilder.h"
#include "GenType.h"
#include "IRGenFunction.h"
#include "IRGenMangler.h"
#include "IRGenModule.h"
#include "swift/AST/GenericEnvironment.h"
#include "swift/Basic/Assertions.h"
#include "swift/SIL/TypeLowering.h"
#include "clang/CodeGen/CodeGenABITypes.h"
#include "llvm/ADT/APInt.h"
#include "llvm/Support/SipHash.h"
#include "llvm/Support/raw_ostream.h"
using namespace swift;
using namespace irgen;
/**************************** INTRINSIC OPERATIONS ****************************/
/// Return the key and discriminator value for the given auth info,
/// as demanded by the ptrauth intrinsics.
static std::pair<llvm::Constant*, llvm::Value*>
getPointerAuthPair(IRGenFunction &IGF, const PointerAuthInfo &authInfo) {
auto key = llvm::ConstantInt::get(IGF.IGM.Int32Ty, authInfo.getKey());
llvm::Value *discriminator = authInfo.getDiscriminator();
if (discriminator->getType()->isPointerTy()) {
discriminator = IGF.Builder.CreatePtrToInt(discriminator, IGF.IGM.Int64Ty);
}
return { key, discriminator };
}
llvm::Value *irgen::emitPointerAuthBlend(IRGenFunction &IGF,
llvm::Value *address,
llvm::Value *other) {
address = IGF.Builder.CreatePtrToInt(address, IGF.IGM.Int64Ty);
return IGF.Builder.CreateIntrinsicCall(llvm::Intrinsic::ptrauth_blend,
{address, other});
}
llvm::Value *irgen::emitPointerAuthStrip(IRGenFunction &IGF,
llvm::Value *fnPtr,
unsigned Key) {
auto fnVal = IGF.Builder.CreatePtrToInt(fnPtr, IGF.IGM.Int64Ty);
auto keyArg = llvm::ConstantInt::get(IGF.IGM.Int32Ty, Key);
auto strippedPtr = IGF.Builder.CreateIntrinsicCall(
llvm::Intrinsic::ptrauth_strip, {fnVal, keyArg});
return IGF.Builder.CreateIntToPtr(strippedPtr, fnPtr->getType());
}
FunctionPointer irgen::emitPointerAuthResign(IRGenFunction &IGF,
const FunctionPointer &fn,
const PointerAuthInfo &newAuthInfo) {
llvm::Value *fnPtr = emitPointerAuthResign(IGF, fn.getRawPointer(),
fn.getAuthInfo(), newAuthInfo);
return FunctionPointer::createSigned(fn.getKind(), fnPtr, newAuthInfo,
fn.getSignature());
}
llvm::Value *irgen::emitPointerAuthResign(IRGenFunction &IGF,
llvm::Value *fnPtr,
const PointerAuthInfo &oldAuthInfo,
const PointerAuthInfo &newAuthInfo) {
// If the signatures match, there's nothing to do.
if (oldAuthInfo == newAuthInfo)
return fnPtr;
// If the pointer is not currently signed, sign it.
if (!oldAuthInfo.isSigned()) {
return emitPointerAuthSign(IGF, fnPtr, newAuthInfo);
}
// If the pointer is not supposed to be signed, auth it.
if (!newAuthInfo.isSigned()) {
return emitPointerAuthAuth(IGF, fnPtr, oldAuthInfo);
}
// Otherwise, auth and resign it.
auto origTy = fnPtr->getType();
fnPtr = IGF.Builder.CreatePtrToInt(fnPtr, IGF.IGM.Int64Ty);
auto oldPair = getPointerAuthPair(IGF, oldAuthInfo);
auto newPair = getPointerAuthPair(IGF, newAuthInfo);
llvm::Value *args[] = {
fnPtr, oldPair.first, oldPair.second, newPair.first, newPair.second
};
fnPtr =
IGF.Builder.CreateIntrinsicCall(llvm::Intrinsic::ptrauth_resign, args);
return IGF.Builder.CreateIntToPtr(fnPtr, origTy);
}
llvm::Value *irgen::emitPointerAuthAuth(IRGenFunction &IGF, llvm::Value *fnPtr,
const PointerAuthInfo &oldAuthInfo) {
auto origTy = fnPtr->getType();
fnPtr = IGF.Builder.CreatePtrToInt(fnPtr, IGF.IGM.Int64Ty);
auto oldPair = getPointerAuthPair(IGF, oldAuthInfo);
llvm::Value *args[] = {
fnPtr, oldPair.first, oldPair.second
};
fnPtr = IGF.Builder.CreateIntrinsicCall(llvm::Intrinsic::ptrauth_auth, args);
return IGF.Builder.CreateIntToPtr(fnPtr, origTy);
}
llvm::Value *irgen::emitPointerAuthSign(IRGenFunction &IGF, llvm::Value *fnPtr,
const PointerAuthInfo &newAuthInfo) {
if (!newAuthInfo.isSigned())
return fnPtr;
// Special-case constants.
if (auto constantFnPtr = dyn_cast<llvm::Constant>(fnPtr)) {
if (auto constantDiscriminator =
dyn_cast<llvm::Constant>(newAuthInfo.getDiscriminator())) {
llvm::Constant *address = nullptr;
llvm::ConstantInt *other = nullptr;
if (constantDiscriminator->getType()->isPointerTy()) {
address = constantDiscriminator;
} else if (auto otherDiscriminator =
dyn_cast<llvm::ConstantInt>(constantDiscriminator)) {
other = otherDiscriminator;
}
return IGF.IGM.getConstantSignedPointer(constantFnPtr,
newAuthInfo.getKey(),
address, other);
}
}
auto origTy = fnPtr->getType();
fnPtr = IGF.Builder.CreatePtrToInt(fnPtr, IGF.IGM.Int64Ty);
auto newPair = getPointerAuthPair(IGF, newAuthInfo);
llvm::Value *args[] = {
fnPtr, newPair.first, newPair.second
};
fnPtr = IGF.Builder.CreateIntrinsicCall(llvm::Intrinsic::ptrauth_sign, args);
return IGF.Builder.CreateIntToPtr(fnPtr, origTy);
}
/******************************* DISCRIMINATORS *******************************/
struct IRGenModule::PointerAuthCachesType {
llvm::DenseMap<SILDeclRef, llvm::ConstantInt*> Decls;
llvm::DenseMap<CanType, llvm::ConstantInt*> Types;
llvm::DenseMap<CanType, llvm::ConstantInt*> YieldTypes;
llvm::DenseMap<AssociatedTypeDecl *, llvm::ConstantInt*> AssociatedTypes;
llvm::DenseMap<AssociatedConformance, llvm::ConstantInt*> AssociatedConformances;
};
IRGenModule::PointerAuthCachesType &IRGenModule::getPointerAuthCaches() {
if (!PointerAuthCaches)
PointerAuthCaches = new PointerAuthCachesType();
return *PointerAuthCaches;
}
void IRGenModule::destroyPointerAuthCaches() {
delete PointerAuthCaches;
}
static const PointerAuthSchema &getFunctionPointerSchema(IRGenModule &IGM,
CanSILFunctionType fnType) {
auto &options = IGM.getOptions().PointerAuth;
switch (fnType->getRepresentation()) {
case SILFunctionTypeRepresentation::CXXMethod:
case SILFunctionTypeRepresentation::CFunctionPointer:
return options.FunctionPointers;
case SILFunctionTypeRepresentation::Thin:
case SILFunctionTypeRepresentation::Thick:
case SILFunctionTypeRepresentation::Method:
case SILFunctionTypeRepresentation::WitnessMethod:
case SILFunctionTypeRepresentation::Closure:
case SILFunctionTypeRepresentation::KeyPathAccessorGetter:
case SILFunctionTypeRepresentation::KeyPathAccessorSetter:
case SILFunctionTypeRepresentation::KeyPathAccessorEquals:
case SILFunctionTypeRepresentation::KeyPathAccessorHash:
if (fnType->isAsync()) {
return options.AsyncSwiftFunctionPointers;
} else if (fnType->isCalleeAllocatedCoroutine()) {
return options.CoroSwiftFunctionPointers;
}
return options.SwiftFunctionPointers;
case SILFunctionTypeRepresentation::ObjCMethod:
case SILFunctionTypeRepresentation::Block:
llvm_unreachable("not just a function pointer");
}
llvm_unreachable("bad representation");
}
PointerAuthInfo PointerAuthInfo::forFunctionPointer(IRGenModule &IGM,
CanSILFunctionType fnType) {
auto &schema = getFunctionPointerSchema(IGM, fnType);
// If the target doesn't sign function pointers, we're done.
if (!schema) return PointerAuthInfo();
assert(!schema.isAddressDiscriminated() &&
"function pointer cannot be address-discriminated");
auto discriminator = getOtherDiscriminator(IGM, schema, fnType);
return PointerAuthInfo(schema.getKey(), discriminator);
}
PointerAuthInfo PointerAuthInfo::emit(IRGenFunction &IGF,
const PointerAuthSchema &schema,
llvm::Value *storageAddress,
const PointerAuthEntity &entity) {
if (!schema) return PointerAuthInfo();
unsigned key = schema.getKey();
// Produce the 'other' discriminator.
auto otherDiscriminator = getOtherDiscriminator(IGF.IGM, schema, entity);
llvm::Value *discriminator = otherDiscriminator;
// Factor in the address.
if (schema.isAddressDiscriminated()) {
assert(storageAddress &&
"no storage address for address-discriminated schema");
if (!otherDiscriminator->isZero()) {
discriminator = emitPointerAuthBlend(IGF, storageAddress, discriminator);
} else {
discriminator =
IGF.Builder.CreatePtrToInt(storageAddress, IGF.IGM.Int64Ty);
}
}
return PointerAuthInfo(key, discriminator);
}
PointerAuthInfo
PointerAuthInfo::emit(IRGenFunction &IGF,
clang::PointerAuthQualifier pointerAuthQual,
llvm::Value *storageAddress) {
unsigned key = pointerAuthQual.getKey();
// Produce the 'other' discriminator.
auto otherDiscriminator = pointerAuthQual.getExtraDiscriminator();
llvm::Value *discriminator =
llvm::ConstantInt::get(IGF.IGM.Int64Ty, otherDiscriminator);
// Factor in the address.
if (pointerAuthQual.isAddressDiscriminated()) {
assert(storageAddress &&
"no storage address for address-discriminated schema");
if (otherDiscriminator != 0) {
discriminator = emitPointerAuthBlend(IGF, storageAddress, discriminator);
} else {
discriminator =
IGF.Builder.CreatePtrToInt(storageAddress, IGF.IGM.Int64Ty);
}
}
return PointerAuthInfo(key, discriminator);
}
PointerAuthInfo PointerAuthInfo::emit(IRGenFunction &IGF,
const PointerAuthSchema &schema,
llvm::Value *storageAddress,
llvm::ConstantInt *otherDiscriminator) {
if (!schema)
return PointerAuthInfo();
unsigned key = schema.getKey();
llvm::Value *discriminator = otherDiscriminator;
// Factor in the address.
if (schema.isAddressDiscriminated()) {
assert(storageAddress &&
"no storage address for address-discriminated schema");
if (!otherDiscriminator->isZero()) {
discriminator = emitPointerAuthBlend(IGF, storageAddress, discriminator);
} else {
discriminator =
IGF.Builder.CreatePtrToInt(storageAddress, IGF.IGM.Int64Ty);
}
}
return PointerAuthInfo(key, discriminator);
}
llvm::ConstantInt *
PointerAuthInfo::getOtherDiscriminator(IRGenModule &IGM,
const PointerAuthSchema &schema,
const PointerAuthEntity &entity) {
assert(schema);
switch (schema.getOtherDiscrimination()) {
case PointerAuthSchema::Discrimination::None:
return llvm::ConstantInt::get(IGM.Int64Ty, 0);
case PointerAuthSchema::Discrimination::Decl:
return entity.getDeclDiscriminator(IGM);
case PointerAuthSchema::Discrimination::Type:
return entity.getTypeDiscriminator(IGM);
case PointerAuthSchema::Discrimination::Constant:
return llvm::ConstantInt::get(IGM.Int64Ty,
schema.getConstantDiscrimination());
}
llvm_unreachable("bad kind");
}
static llvm::ConstantInt *getDiscriminatorForString(IRGenModule &IGM,
StringRef string) {
return llvm::ConstantInt::get(IGM.Int64Ty,
llvm::getPointerAuthStableSipHash(string));
}
static std::string mangle(AssociatedTypeDecl *assocType) {
return IRGenMangler(assocType->getASTContext())
.mangleAssociatedTypeAccessFunctionDiscriminator(assocType);
}
static std::string mangle(const AssociatedConformance &association) {
return IRGenMangler(association.getAssociatedRequirement()->getASTContext())
.mangleAssociatedTypeWitnessTableAccessFunctionDiscriminator(association);
}
llvm::ConstantInt *
PointerAuthEntity::getDeclDiscriminator(IRGenModule &IGM) const {
switch (StoredKind) {
case Kind::None:
case Kind::CanSILFunctionType:
case Kind::CoroutineYieldTypes:
llvm_unreachable("no declaration for schema using decl discrimination");
case Kind::Special: {
auto getSpecialDiscriminator = [](Special special) -> uint16_t {
switch (special) {
case Special::HeapDestructor:
return SpecialPointerAuthDiscriminators::HeapDestructor;
case Special::TypeDescriptor:
case Special::TypeDescriptorAsArgument:
return SpecialPointerAuthDiscriminators::TypeDescriptor;
case Special::ProtocolConformanceDescriptor:
case Special::ProtocolConformanceDescriptorAsArgument:
return SpecialPointerAuthDiscriminators::ProtocolConformanceDescriptor;
case Special::ProtocolDescriptorAsArgument:
return SpecialPointerAuthDiscriminators::ProtocolDescriptor;
case Special::OpaqueTypeDescriptorAsArgument:
return SpecialPointerAuthDiscriminators::OpaqueTypeDescriptor;
case Special::ContextDescriptorAsArgument:
return SpecialPointerAuthDiscriminators::ContextDescriptor;
case Special::PartialApplyCapture:
return PointerAuthDiscriminator_PartialApplyCapture;
case Special::KeyPathDestroy:
return SpecialPointerAuthDiscriminators::KeyPathDestroy;
case Special::KeyPathCopy:
return SpecialPointerAuthDiscriminators::KeyPathCopy;
case Special::KeyPathEquals:
return SpecialPointerAuthDiscriminators::KeyPathEquals;
case Special::KeyPathHash:
return SpecialPointerAuthDiscriminators::KeyPathHash;
case Special::KeyPathGetter:
return SpecialPointerAuthDiscriminators::KeyPathGetter;
case Special::KeyPathNonmutatingSetter:
return SpecialPointerAuthDiscriminators::KeyPathNonmutatingSetter;
case Special::KeyPathMutatingSetter:
return SpecialPointerAuthDiscriminators::KeyPathMutatingSetter;
case Special::KeyPathGetLayout:
return SpecialPointerAuthDiscriminators::KeyPathGetLayout;
case Special::KeyPathInitializer:
return SpecialPointerAuthDiscriminators::KeyPathInitializer;
case Special::KeyPathMetadataAccessor:
return SpecialPointerAuthDiscriminators::KeyPathMetadataAccessor;
case Special::DynamicReplacementKey:
return SpecialPointerAuthDiscriminators::DynamicReplacementKey;
case Special::TypeLayoutString:
return SpecialPointerAuthDiscriminators::TypeLayoutString;
case Special::BlockCopyHelper:
case Special::BlockDisposeHelper:
llvm_unreachable("no known discriminator for these foreign entities");
case Special::CoroAllocationFunction:
return SpecialPointerAuthDiscriminators::CoroAllocationFunction;
case Special::CoroDeallocationFunction:
return SpecialPointerAuthDiscriminators::CoroDeallocationFunction;
case Special::CoroFrameAllocationFunction:
return SpecialPointerAuthDiscriminators::CoroFrameAllocationFunction;
case Special::CoroFrameDeallocationFunction:
return SpecialPointerAuthDiscriminators::CoroFrameDeallocationFunction;
}
llvm_unreachable("bad kind");
};
auto specialKind = Storage.get<Special>(StoredKind);
return llvm::ConstantInt::get(IGM.Int64Ty,
getSpecialDiscriminator(specialKind));
}
case Kind::ValueWitness: {
auto getValueWitnessDiscriminator = [](ValueWitness witness) -> uint16_t {
switch (witness) {
#define WANT_ALL_VALUE_WITNESSES
#define DATA_VALUE_WITNESS(LOWER, UPPER, TYPE)
#define FUNCTION_VALUE_WITNESS(LOWER, ID, RET, PARAMS) \
case ValueWitness::ID: return SpecialPointerAuthDiscriminators::ID;
#include "swift/ABI/ValueWitness.def"
case ValueWitness::Size:
case ValueWitness::Flags:
case ValueWitness::Stride:
case ValueWitness::ExtraInhabitantCount:
llvm_unreachable("not a function value witness");
}
llvm_unreachable("bad kind");
};
auto witness = Storage.get<ValueWitness>(StoredKind);
return llvm::ConstantInt::get(IGM.Int64Ty,
getValueWitnessDiscriminator(witness));
}
case Kind::AssociatedType: {
auto association = Storage.get<AssociatedTypeDecl *>(StoredKind);
llvm::ConstantInt *&cache =
IGM.getPointerAuthCaches().AssociatedTypes[association];
if (cache) return cache;
auto mangling = mangle(association);
cache = getDiscriminatorForString(IGM, mangling);
return cache;
}
case Kind::AssociatedConformance: {
auto conformance = Storage.get<AssociatedConformance>(StoredKind);
llvm::ConstantInt *&cache =
IGM.getPointerAuthCaches().AssociatedConformances[conformance];
if (cache) return cache;
auto mangling = mangle(conformance);
cache = getDiscriminatorForString(IGM, mangling);
return cache;
}
case Kind::SILDeclRef: {
auto constant = Storage.get<SILDeclRef>(StoredKind);
llvm::ConstantInt *&cache = IGM.getPointerAuthCaches().Decls[constant];
if (cache) return cache;
// Getting the discriminator for a foreign SILDeclRef just means
// converting it to a foreign declaration and asking Clang IRGen
// for the corresponding discriminator, but that's not completely
// trivial.
assert(!constant.isForeign &&
"discriminator for foreign declaration not supported yet!");
auto mangling = constant.mangle();
cache = getDiscriminatorForString(IGM, mangling);
return cache;
}
case Kind::SILFunction: {
auto fn = Storage.get<SILFunction*>(StoredKind);
return getDiscriminatorForString(IGM, fn->getName());
}
}
llvm_unreachable("bad kind");
}
static llvm::ConstantInt *getTypeDiscriminator(IRGenModule &IGM,
CanSILFunctionType type) {
return llvm::ConstantInt::get(
IGM.Int64Ty, type->getPointerAuthDiscriminator(&IGM.getSILModule()));
}
static llvm::ConstantInt *
getCoroutineYieldTypesDiscriminator(IRGenModule &IGM, CanSILFunctionType type) {
return llvm::ConstantInt::get(
IGM.Int64Ty, type->getCoroutineYieldTypesDiscriminator(IGM.getSILModule()));
}
llvm::ConstantInt *
PointerAuthEntity::getTypeDiscriminator(IRGenModule &IGM) const {
auto getTypeDiscriminator = [&](CanSILFunctionType fnType) {
switch (fnType->getRepresentation()) {
// Swift function types are type-discriminated.
case SILFunctionTypeRepresentation::Thick:
case SILFunctionTypeRepresentation::Thin:
case SILFunctionTypeRepresentation::Method:
case SILFunctionTypeRepresentation::WitnessMethod:
case SILFunctionTypeRepresentation::Closure:
case SILFunctionTypeRepresentation::KeyPathAccessorGetter:
case SILFunctionTypeRepresentation::KeyPathAccessorSetter:
case SILFunctionTypeRepresentation::KeyPathAccessorEquals:
case SILFunctionTypeRepresentation::KeyPathAccessorHash: {
llvm::ConstantInt *&cache = IGM.getPointerAuthCaches().Types[fnType];
if (cache) return cache;
cache = ::getTypeDiscriminator(IGM, fnType);
return cache;
}
// C function pointers are undiscriminated.
case SILFunctionTypeRepresentation::CXXMethod:
case SILFunctionTypeRepresentation::CFunctionPointer:
return llvm::ConstantInt::get(IGM.Int64Ty, 0);
case SILFunctionTypeRepresentation::ObjCMethod:
case SILFunctionTypeRepresentation::Block: {
llvm_unreachable("not type discriminated");
}
}
llvm_unreachable("invalid representation");
};
switch (StoredKind) {
case Kind::None:
case Kind::Special:
case Kind::ValueWitness:
case Kind::AssociatedType:
case Kind::AssociatedConformance:
case Kind::SILFunction:
llvm_unreachable("no type for schema using type discrimination");
case Kind::CoroutineYieldTypes: {
auto fnType = Storage.get<CanSILFunctionType>(StoredKind);
llvm::ConstantInt *&cache = IGM.getPointerAuthCaches().Types[fnType];
if (cache)
return cache;
cache = getCoroutineYieldTypesDiscriminator(IGM, fnType);
return cache;
}
case Kind::CanSILFunctionType: {
auto fnType = Storage.get<CanSILFunctionType>(StoredKind);
return getTypeDiscriminator(fnType);
}
case Kind::SILDeclRef: {
SILDeclRef decl = Storage.get<SILDeclRef>(StoredKind);
auto fnType = IGM.getSILTypes().getConstantFunctionType(
TypeExpansionContext::minimal(), decl);
return getTypeDiscriminator(fnType);
}
}
llvm_unreachable("bad kind");
}
llvm::Constant *
IRGenModule::getConstantSignedFunctionPointer(llvm::Constant *fn,
CanSILFunctionType fnType) {
if (auto &schema = getFunctionPointerSchema(*this, fnType)) {
return getConstantSignedPointer(fn, schema, fnType, nullptr);
}
return fn;
}
llvm::Constant *
IRGenModule::getConstantSignedCFunctionPointer(llvm::Constant *fn) {
if (auto &schema = getOptions().PointerAuth.FunctionPointers) {
assert(!schema.hasOtherDiscrimination());
return getConstantSignedPointer(fn, schema, PointerAuthEntity(), nullptr);
}
return fn;
}
llvm::Constant *
IRGenModule::getConstantSignedPointer(llvm::Constant *pointer, unsigned key,
llvm::Constant *storageAddress,
llvm::ConstantInt *otherDiscriminator) {
return clang::CodeGen::getConstantSignedPointer(getClangCGM(), pointer, key,
storageAddress,
otherDiscriminator);
}
llvm::Constant *IRGenModule::getConstantSignedPointer(llvm::Constant *pointer,
const PointerAuthSchema &schema,
const PointerAuthEntity &entity,
llvm::Constant *storageAddress) {
// If the schema doesn't sign pointers, do nothing.
if (!schema)
return pointer;
auto otherDiscriminator =
PointerAuthInfo::getOtherDiscriminator(*this, schema, entity);
return getConstantSignedPointer(pointer, schema.getKey(), storageAddress,
otherDiscriminator);
}
void ConstantAggregateBuilderBase::addSignedPointer(llvm::Constant *pointer,
const PointerAuthSchema &schema,
const PointerAuthEntity &entity) {
// If the schema doesn't sign pointers, do nothing.
if (!schema)
return add(pointer);
auto otherDiscriminator =
PointerAuthInfo::getOtherDiscriminator(IGM(), schema, entity);
addSignedPointer(pointer, schema.getKey(), schema.isAddressDiscriminated(),
otherDiscriminator);
}
void ConstantAggregateBuilderBase::addSignedPointer(llvm::Constant *pointer,
const PointerAuthSchema &schema,
uint16_t otherDiscriminator) {
// If the schema doesn't sign pointers, do nothing.
if (!schema)
return add(pointer);
addSignedPointer(pointer, schema.getKey(), schema.isAddressDiscriminated(),
llvm::ConstantInt::get(IGM().Int64Ty, otherDiscriminator));
}
llvm::ConstantInt *IRGenModule::getMallocTypeId(llvm::Function *fn) {
if (!getOptions().EmitTypeMallocForCoroFrame) {
// Even when typed malloc isn't enabled, a type id may be required for ABI
// reasons (e.g. as an argument to swift_coro_alloc). Use a cheaply
// materialized value.
return llvm::ConstantInt::get(Int64Ty, 0);
}
return getDiscriminatorForString(*this, fn->getName());
}
llvm::ConstantInt* IRGenFunction::getMallocTypeId() {
return IGM.getMallocTypeId(CurFn);
}