mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
The change replaces 'set bit enumeration' with arithmetic and bitwise operations. For example, the formula '(((x & -x) + x) & x) ^ x' can be used to find the rightmost contiguous bit mask. This is essentially the operation that SetBitEnumerator.findNext() performed. Removing this functionality reduces the complexity of the ClusteredBitVector (a.k.a. SpareBitVector) implementation and, more importantly, API which will make it easier to modify the implementation of spare bit masks going forward. My end goal being to make spare bit operations work more reliably on big endian systems. Side note: This change modifies the emit gather/scatter functions so that they work with an APInt, rather than a SpareBitVector, which makes these functions a bit more generic. These functions emit instructions that are essentially equivalent to the parallel bit extract/deposit (PEXT and PDEP) instructions in BMI2 on x86_64 (although we don't emit those directly currently). They also map well to bitwise manipulation instructions on other platforms (e.g. RISBG on IBM Z). So we might find uses for them outside spare bit manipulation in the future.
212 lines
8.5 KiB
C++
212 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 "IRGenModule.h"
|
|
#include "IRGenFunction.h"
|
|
#include "SwiftTargetInfo.h"
|
|
#include "swift/ABI/MetadataValues.h"
|
|
|
|
using namespace swift;
|
|
using namespace irgen;
|
|
|
|
static unsigned 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();
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
|
|
/// Return the number of extra inhabitants for a pointer that reserves
|
|
/// the given number of low bits.
|
|
static unsigned getPointerExtraInhabitantCount(const IRGenModule &IGM,
|
|
unsigned numReservedLowBits) {
|
|
// FIXME: We could also make extra inhabitants using spare bits, but we
|
|
// probably don't need to.
|
|
uint64_t rawCount =
|
|
IGM.TargetInfo.LeastValidPointerValue >> numReservedLowBits;
|
|
|
|
// 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 getPointerExtraInhabitantCount(IGM, getNumLowObjCReservedBits(IGM));
|
|
}
|
|
|
|
unsigned irgen::getFunctionPointerExtraInhabitantCount(IRGenModule &IGM) {
|
|
return getPointerExtraInhabitantCount(IGM, 0);
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
|
|
static APInt
|
|
getPointerFixedExtraInhabitantValue(const IRGenModule &IGM, unsigned bits,
|
|
unsigned index, unsigned offset,
|
|
unsigned numReservedLowBits) {
|
|
assert(index < getPointerExtraInhabitantCount(IGM, numReservedLowBits) &&
|
|
"pointer extra inhabitant out of bounds");
|
|
uint64_t value = (uint64_t)index << numReservedLowBits;
|
|
APInt apValue(bits, value);
|
|
if (offset > 0)
|
|
apValue = apValue.shl(offset);
|
|
|
|
return apValue;
|
|
}
|
|
|
|
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 getPointerFixedExtraInhabitantValue(IGM, bits, index, offset,
|
|
getNumLowObjCReservedBits(IGM));
|
|
}
|
|
|
|
APInt irgen::getFunctionPointerFixedExtraInhabitantValue(IRGenModule &IGM,
|
|
unsigned bits,
|
|
unsigned index,
|
|
unsigned offset) {
|
|
return getPointerFixedExtraInhabitantValue(IGM, bits, index, offset, 0);
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
|
|
static llvm::Value *getPointerExtraInhabitantIndex(IRGenFunction &IGF,
|
|
Address src,
|
|
unsigned numReservedLowBits) {
|
|
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.CreateBitCast(src, IGF.IGM.SizeTy->getPointerTo());
|
|
|
|
// 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);
|
|
}
|
|
|
|
// 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,
|
|
llvm::ConstantInt::get(IGF.IGM.SizeTy, numReservedLowBits));
|
|
}
|
|
|
|
// 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 getPointerExtraInhabitantIndex(IGF, src,
|
|
getNumLowObjCReservedBits(IGF.IGM));
|
|
}
|
|
|
|
llvm::Value *irgen::getFunctionPointerExtraInhabitantIndex(IRGenFunction &IGF,
|
|
Address src) {
|
|
return getPointerExtraInhabitantIndex(IGF, src, 0);
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
|
|
static void storePointerExtraInhabitant(IRGenFunction &IGF,
|
|
llvm::Value *index,
|
|
Address dest,
|
|
unsigned numReservedLowBits) {
|
|
if (index->getType() != IGF.IGM.SizeTy) {
|
|
index = IGF.Builder.CreateZExt(index, IGF.IGM.SizeTy);
|
|
}
|
|
|
|
if (numReservedLowBits) {
|
|
index = IGF.Builder.CreateShl(index,
|
|
llvm::ConstantInt::get(IGF.IGM.SizeTy, numReservedLowBits));
|
|
}
|
|
|
|
dest = IGF.Builder.CreateBitCast(dest, IGF.IGM.SizeTy->getPointerTo());
|
|
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.
|
|
storePointerExtraInhabitant(IGF, index, dest,
|
|
getNumLowObjCReservedBits(IGF.IGM));
|
|
}
|
|
|
|
void irgen::storeFunctionPointerExtraInhabitant(IRGenFunction &IGF,
|
|
llvm::Value *index,
|
|
Address dest) {
|
|
storePointerExtraInhabitant(IGF, index, dest, 0);
|
|
}
|