mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
This change modifies spare bit masks so that they are arranged in the byte order of the target platform. It also modifies and consolidates the code that gathers and scatters bits into enum values. All enum-related validation tests are now passing on IBM Z (s390x) which is a big-endian platform.
217 lines
8.8 KiB
C++
217 lines
8.8 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"
|
|
|
|
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) {
|
|
unsigned pointerSizeInBits = IGM.getPointerSize().getValueInBits();
|
|
assert(index < getPointerExtraInhabitantCount(IGM, numReservedLowBits) &&
|
|
"pointer extra inhabitant out of bounds");
|
|
assert(bits >= pointerSizeInBits + offset);
|
|
|
|
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().getValue();
|
|
}
|
|
|
|
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);
|
|
}
|