mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
Although I don't plan to bring over new assertions wholesale into the current qualification branch, it's entirely possible that various minor changes in main will use the new assertions; having this basic support in the release branch will simplify that. (This is why I'm adding the includes as a separate pass from rewriting the individual assertions)
223 lines
8.5 KiB
C++
223 lines
8.5 KiB
C++
//===--- ExtraInhabitants.cpp - Routines for extra inhabitants ------------===//
|
|
//
|
|
// 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 routines for working with extra inhabitants.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "ExtraInhabitants.h"
|
|
|
|
#include "BitPatternBuilder.h"
|
|
#include "IRGenModule.h"
|
|
#include "IRGenFunction.h"
|
|
#include "SwiftTargetInfo.h"
|
|
#include "swift/ABI/MetadataValues.h"
|
|
#include "swift/Basic/Assertions.h"
|
|
|
|
using namespace swift;
|
|
using namespace irgen;
|
|
|
|
static uint8_t getNumLowObjCReservedBits(const IRGenModule &IGM) {
|
|
if (!IGM.ObjCInterop)
|
|
return 0;
|
|
|
|
// Get the index of the first non-reserved bit.
|
|
auto &mask = IGM.TargetInfo.ObjCPointerReservedBits;
|
|
return mask.asAPInt().countTrailingOnes();
|
|
}
|
|
|
|
PointerInfo PointerInfo::forHeapObject(const IRGenModule &IGM) {
|
|
return { Alignment(1), getNumLowObjCReservedBits(IGM), IsNotNullable };
|
|
}
|
|
|
|
PointerInfo PointerInfo::forFunction(const IRGenModule &IGM) {
|
|
return { Alignment(1), 0, IsNotNullable };
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
|
|
/// Return the number of extra inhabitants for a pointer that reserves
|
|
/// the given number of low bits.
|
|
unsigned PointerInfo::getExtraInhabitantCount(const IRGenModule &IGM) const {
|
|
// FIXME: We could also make extra inhabitants using spare bits, but we
|
|
// probably don't need to.
|
|
uint64_t rawCount =
|
|
IGM.TargetInfo.LeastValidPointerValue >> NumReservedLowBits;
|
|
|
|
if (Nullable) rawCount--;
|
|
|
|
// The runtime limits the count.
|
|
return std::min(uint64_t(ValueWitnessFlags::MaxNumExtraInhabitants),
|
|
rawCount);
|
|
}
|
|
|
|
unsigned irgen::getHeapObjectExtraInhabitantCount(const IRGenModule &IGM) {
|
|
// This must be consistent with the extra inhabitant count produced
|
|
// by the runtime's getHeapObjectExtraInhabitantCount function in
|
|
// KnownMetadata.cpp.
|
|
return PointerInfo::forHeapObject(IGM).getExtraInhabitantCount(IGM);
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
|
|
APInt PointerInfo::getFixedExtraInhabitantValue(const IRGenModule &IGM,
|
|
unsigned bits,
|
|
unsigned index,
|
|
unsigned offset) const {
|
|
unsigned pointerSizeInBits = IGM.getPointerSize().getValueInBits();
|
|
assert(index < getExtraInhabitantCount(IGM) &&
|
|
"pointer extra inhabitant out of bounds");
|
|
assert(bits >= pointerSizeInBits + offset);
|
|
|
|
if (Nullable) index++;
|
|
|
|
uint64_t value = (uint64_t)index << NumReservedLowBits;
|
|
|
|
auto valueBits = BitPatternBuilder(IGM.Triple.isLittleEndian());
|
|
valueBits.appendClearBits(offset);
|
|
valueBits.append(APInt(pointerSizeInBits, value));
|
|
valueBits.padWithClearBitsTo(bits);
|
|
return valueBits.build().value();
|
|
}
|
|
|
|
APInt irgen::getHeapObjectFixedExtraInhabitantValue(const IRGenModule &IGM,
|
|
unsigned bits,
|
|
unsigned index,
|
|
unsigned offset) {
|
|
// This must be consistent with the extra inhabitant calculation implemented
|
|
// in the runtime's storeHeapObjectExtraInhabitant and
|
|
// getHeapObjectExtraInhabitantIndex functions in KnownMetadata.cpp.
|
|
return PointerInfo::forHeapObject(IGM)
|
|
.getFixedExtraInhabitantValue(IGM, bits, index, offset);
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
|
|
llvm::Value *PointerInfo::getExtraInhabitantIndex(IRGenFunction &IGF,
|
|
Address src) const {
|
|
llvm::BasicBlock *contBB = IGF.createBasicBlock("is-valid-pointer");
|
|
SmallVector<std::pair<llvm::BasicBlock*, llvm::Value*>, 3> phiValues;
|
|
auto invalidIndex = llvm::ConstantInt::getSigned(IGF.IGM.Int32Ty, -1);
|
|
|
|
src = IGF.Builder.CreateElementBitCast(src, IGF.IGM.SizeTy);
|
|
|
|
// Check if the inhabitant is below the least valid pointer value.
|
|
llvm::Value *val = IGF.Builder.CreateLoad(src);
|
|
{
|
|
llvm::Value *leastValid = llvm::ConstantInt::get(IGF.IGM.SizeTy,
|
|
IGF.IGM.TargetInfo.LeastValidPointerValue);
|
|
llvm::Value *isValid = IGF.Builder.CreateICmpUGE(val, leastValid);
|
|
|
|
phiValues.push_back({IGF.Builder.GetInsertBlock(), invalidIndex});
|
|
llvm::BasicBlock *invalidBB = IGF.createBasicBlock("is-invalid-pointer");
|
|
IGF.Builder.CreateCondBr(isValid, contBB, invalidBB);
|
|
IGF.Builder.emitBlock(invalidBB);
|
|
}
|
|
|
|
// If null is not an extra inhabitant, check if the inhabitant is null.
|
|
if (Nullable) {
|
|
auto null = llvm::ConstantInt::get(IGF.IGM.SizeTy, 0);
|
|
auto isNonNull = IGF.Builder.CreateICmpNE(val, null);
|
|
phiValues.push_back({IGF.Builder.GetInsertBlock(), invalidIndex});
|
|
llvm::BasicBlock *nonnullBB = IGF.createBasicBlock("is-nonnull-pointer");
|
|
IGF.Builder.CreateCondBr(isNonNull, nonnullBB, contBB);
|
|
IGF.Builder.emitBlock(nonnullBB);
|
|
}
|
|
|
|
// Check if the inhabitant has any reserved low bits set.
|
|
// FIXME: This check is unneeded if the type is known to be pure Swift.
|
|
if (NumReservedLowBits) {
|
|
auto objcMask =
|
|
llvm::ConstantInt::get(IGF.IGM.SizeTy, (1 << NumReservedLowBits) - 1);
|
|
llvm::Value *masked = IGF.Builder.CreateAnd(val, objcMask);
|
|
llvm::Value *maskedZero = IGF.Builder.CreateICmpEQ(masked,
|
|
llvm::ConstantInt::get(IGF.IGM.SizeTy, 0));
|
|
|
|
phiValues.push_back({IGF.Builder.GetInsertBlock(), invalidIndex});
|
|
llvm::BasicBlock *untaggedBB = IGF.createBasicBlock("is-untagged-pointer");
|
|
IGF.Builder.CreateCondBr(maskedZero, untaggedBB, contBB);
|
|
IGF.Builder.emitBlock(untaggedBB);
|
|
}
|
|
|
|
// The inhabitant is an invalid pointer. Derive its extra inhabitant index.
|
|
{
|
|
llvm::Value *index = val;
|
|
|
|
// Shift away the reserved bits.
|
|
if (NumReservedLowBits) {
|
|
index = IGF.Builder.CreateLShr(index,
|
|
IGF.IGM.getSize(Size(NumReservedLowBits)));
|
|
}
|
|
|
|
// Subtract one if we have a nullable type.
|
|
if (Nullable) {
|
|
index = IGF.Builder.CreateSub(index, IGF.IGM.getSize(Size(1)));
|
|
}
|
|
|
|
// Truncate down to i32 if necessary.
|
|
if (index->getType() != IGF.IGM.Int32Ty) {
|
|
index = IGF.Builder.CreateTrunc(index, IGF.IGM.Int32Ty);
|
|
}
|
|
|
|
phiValues.push_back({IGF.Builder.GetInsertBlock(), index});
|
|
IGF.Builder.CreateBr(contBB);
|
|
IGF.Builder.emitBlock(contBB);
|
|
}
|
|
|
|
// Build the result phi.
|
|
auto phi = IGF.Builder.CreatePHI(IGF.IGM.Int32Ty, phiValues.size());
|
|
for (auto &entry : phiValues) {
|
|
phi->addIncoming(entry.second, entry.first);
|
|
}
|
|
return phi;
|
|
}
|
|
|
|
llvm::Value *irgen::getHeapObjectExtraInhabitantIndex(IRGenFunction &IGF,
|
|
Address src) {
|
|
// This must be consistent with the extra inhabitant calculation implemented
|
|
// in the runtime's getHeapObjectExtraInhabitantIndex function in
|
|
// KnownMetadata.cpp.
|
|
return PointerInfo::forHeapObject(IGF.IGM).getExtraInhabitantIndex(IGF, src);
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
|
|
void PointerInfo::storeExtraInhabitant(IRGenFunction &IGF,
|
|
llvm::Value *index,
|
|
Address dest) const {
|
|
if (index->getType() != IGF.IGM.SizeTy) {
|
|
index = IGF.Builder.CreateZExt(index, IGF.IGM.SizeTy);
|
|
}
|
|
|
|
if (Nullable) {
|
|
index = IGF.Builder.CreateAdd(index, IGF.IGM.getSize(Size(1)));
|
|
}
|
|
|
|
if (NumReservedLowBits) {
|
|
index = IGF.Builder.CreateShl(index,
|
|
llvm::ConstantInt::get(IGF.IGM.SizeTy, NumReservedLowBits));
|
|
}
|
|
|
|
dest = IGF.Builder.CreateElementBitCast(dest, IGF.IGM.SizeTy);
|
|
IGF.Builder.CreateStore(index, dest);
|
|
}
|
|
|
|
void irgen::storeHeapObjectExtraInhabitant(IRGenFunction &IGF,
|
|
llvm::Value *index,
|
|
Address dest) {
|
|
// This must be consistent with the extra inhabitant calculation implemented
|
|
// in the runtime's storeHeapObjectExtraInhabitant function in
|
|
// KnownMetadata.cpp.
|
|
PointerInfo::forHeapObject(IGF.IGM)
|
|
.storeExtraInhabitant(IGF, index, dest);
|
|
}
|