blob: 0e2d7212f60f47aecee889c7314ae32bd159c5b5 [file] [log] [blame]
//===--- GenIntegerLiteral.cpp - IRGen for Builtin.IntegerLiteral ---------===//
//
// 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 IR generation for Builtin.IntegerLiteral.
//
//===----------------------------------------------------------------------===//
#include "GenIntegerLiteral.h"
#include "llvm/IR/Constants.h"
#include "llvm/IR/GlobalVariable.h"
#include "swift/ABI/MetadataValues.h"
#include "Explosion.h"
#include "ExtraInhabitants.h"
#include "GenType.h"
#include "IRGenFunction.h"
#include "IRGenModule.h"
#include "LoadableTypeInfo.h"
#include "ScalarPairTypeInfo.h"
using namespace swift;
using namespace irgen;
namespace {
/// A TypeInfo implementation for Builtin.IntegerLiteral.
class IntegerLiteralTypeInfo :
public ScalarPairTypeInfo<IntegerLiteralTypeInfo, LoadableTypeInfo> {
public:
IntegerLiteralTypeInfo(llvm::StructType *storageType,
Size size, Alignment align, SpareBitVector &&spareBits)
: ScalarPairTypeInfo(storageType, size, std::move(spareBits), align,
IsPOD, IsFixedSize) {}
static Size getFirstElementSize(IRGenModule &IGM) {
return IGM.getPointerSize();
}
static StringRef getFirstElementLabel() {
return ".data";
}
static bool isFirstElementTrivial() {
return true;
}
void emitRetainFirstElement(IRGenFunction &IGF, llvm::Value *fn,
Optional<Atomicity> atomicity = None) const {}
void emitReleaseFirstElement(IRGenFunction &IGF, llvm::Value *fn,
Optional<Atomicity> atomicity = None) const {}
void emitAssignFirstElement(IRGenFunction &IGF, llvm::Value *fn,
Address fnAddr) const {
IGF.Builder.CreateStore(fn, fnAddr);
}
static Size getSecondElementOffset(IRGenModule &IGM) {
return IGM.getPointerSize();
}
static Size getSecondElementSize(IRGenModule &IGM) {
return IGM.getPointerSize();
}
static StringRef getSecondElementLabel() {
return ".flags";
}
bool isSecondElementTrivial() const {
return true;
}
void emitRetainSecondElement(IRGenFunction &IGF, llvm::Value *data,
Optional<Atomicity> atomicity = None) const {}
void emitReleaseSecondElement(IRGenFunction &IGF, llvm::Value *data,
Optional<Atomicity> atomicity = None) const {}
void emitAssignSecondElement(IRGenFunction &IGF, llvm::Value *context,
Address dataAddr) const {
IGF.Builder.CreateStore(context, dataAddr);
}
// The data pointer isn't a heap object, but it is an aligned pointer.
bool mayHaveExtraInhabitants(IRGenModule &IGM) const override {
return true;
}
unsigned getFixedExtraInhabitantCount(IRGenModule &IGM) const override {
return getHeapObjectExtraInhabitantCount(IGM);
}
APInt getFixedExtraInhabitantValue(IRGenModule &IGM,
unsigned bits,
unsigned index) const override {
return getHeapObjectFixedExtraInhabitantValue(IGM, bits, index, 0);
}
llvm::Value *getExtraInhabitantIndex(IRGenFunction &IGF, Address src,
SILType T,
bool isOutlined) const override {
src = projectFirstElement(IGF, src);
return getHeapObjectExtraInhabitantIndex(IGF, src);
}
APInt getFixedExtraInhabitantMask(IRGenModule &IGM) const override {
auto pointerSize = IGM.getPointerSize().getValueInBits();
APInt bits = APInt::getAllOnesValue(pointerSize);
bits = bits.zext(pointerSize * 2);
return bits;
}
void storeExtraInhabitant(IRGenFunction &IGF, llvm::Value *index,
Address dest, SILType T,
bool isOutlined) const override {
dest = projectFirstElement(IGF, dest);
storeHeapObjectExtraInhabitant(IGF, index, dest);
}
};
}
llvm::StructType *IRGenModule::getIntegerLiteralTy() {
if (!IntegerLiteralTy) {
IntegerLiteralTy =
llvm::StructType::create(LLVMContext, {
SizeTy->getPointerTo(),
SizeTy
}, "swift.int_literal");
}
return IntegerLiteralTy;
}
const LoadableTypeInfo &
TypeConverter::getIntegerLiteralTypeInfo() {
if (!IntegerLiteralTI) {
auto ty = IGM.getIntegerLiteralTy();
SpareBitVector spareBits;
spareBits.append(IGM.getHeapObjectSpareBits());
spareBits.appendClearBits(IGM.getPointerSize().getValueInBits());
IntegerLiteralTI =
new IntegerLiteralTypeInfo(ty, IGM.getPointerSize() * 2,
IGM.getPointerAlignment(),
std::move(spareBits));
}
return *IntegerLiteralTI;
}
ConstantIntegerLiteral
irgen::emitConstantIntegerLiteral(IRGenModule &IGM, IntegerLiteralInst *ILI) {
return IGM.getConstantIntegerLiteral(ILI->getValue());
}
ConstantIntegerLiteral
IRGenModule::getConstantIntegerLiteral(APInt value) {
if (!ConstantIntegerLiterals)
ConstantIntegerLiterals.reset(new ConstantIntegerLiteralMap());
return ConstantIntegerLiterals->get(*this, std::move(value));
}
ConstantIntegerLiteral
ConstantIntegerLiteralMap::get(IRGenModule &IGM, APInt &&value) {
auto &entry = map[value];
if (entry.Data) return entry;
assert(value.getMinSignedBits() == value.getBitWidth() &&
"expected IntegerLiteral value to be maximally compact");
// We're going to break the value down into pointer-sized chunks.
uint64_t chunkSizeInBits = IGM.getPointerSize().getValueInBits();
// Count how many bits are needed to store the value, including the sign bit.
uint64_t minWidthInBits = value.getBitWidth();
// Round up to the nearest multiple of the chunk size.
uint64_t storageWidthInBits = (minWidthInBits + chunkSizeInBits - 1)
& ~(chunkSizeInBits - 1);
// Extend the value to that width. We guarantee that extra bits in the
// chunks will be appropriately sign-extended.
value = value.sextOrTrunc(storageWidthInBits);
// Extract the individual chunks from the extended value.
uint64_t numChunks = storageWidthInBits / chunkSizeInBits;
SmallVector<llvm::Constant *, 4> chunks;
chunks.reserve(numChunks);
for (uint64_t i = 0; i != numChunks; ++i) {
auto chunk = value.extractBits(chunkSizeInBits, i * chunkSizeInBits);
chunks.push_back(llvm::ConstantInt::get(IGM.SizeTy, std::move(chunk)));
}
// Build a global to hold the chunks.
// TODO: make this shared within the image
auto arrayTy = llvm::ArrayType::get(IGM.SizeTy, numChunks);
auto initV = llvm::ConstantArray::get(arrayTy, chunks);
auto globalArray =
new llvm::GlobalVariable(*IGM.getModule(), arrayTy, /*constant*/ true,
llvm::GlobalVariable::PrivateLinkage, initV,
IGM.EnableValueNames
? Twine("intliteral.") + value.toString(10, true)
: "");
globalArray->setUnnamedAddr(llvm::GlobalVariable::UnnamedAddr::Global);
// Various clients expect this to be a i64*, not an [N x i64]*, so cast down.
auto zero = llvm::ConstantInt::get(IGM.Int32Ty, 0);
llvm::Constant *indices[] = { zero, zero };
auto data = llvm::ConstantExpr::getInBoundsGetElementPtr(arrayTy, globalArray,
indices);
// Build the flags word.
auto flags = IntegerLiteralFlags(minWidthInBits, value.isNegative());
auto flagsV = llvm::ConstantInt::get(IGM.SizeTy, flags.getOpaqueValue());
// Cache the global.
entry.Data = data;
entry.Flags = flagsV;
return entry;
}
void irgen::emitIntegerLiteralCheckedTrunc(IRGenFunction &IGF,
Explosion &in,
llvm::IntegerType *resultTy,
bool resultIsSigned,
Explosion &out) {
Address data(in.claimNext(), IGF.IGM.getPointerAlignment());
auto flags = in.claimNext();
size_t chunkWidth = IGF.IGM.getPointerSize().getValueInBits();
size_t resultWidth = resultTy->getBitWidth();
// The number of bits required to express the value, including the sign bit.
auto valueWidth = IGF.Builder.CreateLShr(flags,
IGF.IGM.getSize(Size(IntegerLiteralFlags::BitWidthShift)));
// The maximum number of chunks that we need to read in order to fill the
// result type: ceil(resultWidth / chunkWidth).
// Note that we won't actually end up reading the final chunk if we're
// building an unsigned value that requires e.g. 65 bits to express:
// there's only one meaningful bit there, and we know it's zero from the
// isNegative check.
size_t maxNumChunks = (resultWidth + chunkWidth - 1) / chunkWidth;
// One branch from invalidBB, one branch at each intermediate point in the
// do-we-have-more-chunks chain, and one branch at the end.
auto numPHIEntries = maxNumChunks + /*overflow*/ 1;
auto boolTy = IGF.IGM.Int1Ty;
auto doneBB = IGF.createBasicBlock("intliteral.trunc.done");
auto resultPHI = llvm::PHINode::Create(resultTy, numPHIEntries, "", doneBB);
auto overflowPHI = llvm::PHINode::Create(boolTy, numPHIEntries, "", doneBB);
out.add(resultPHI);
out.add(overflowPHI);
auto validBB = IGF.createBasicBlock("intliteral.trunc.valid");
auto invalidBB = IGF.createBasicBlock("intliteral.trunc.invalid");
// Check whether the value fits in the result type.
// If the result is signed, then we need valueWidth <= resultWidth.
// Otherwise we need valueWidth <= resultWidth + 1 && !isNegative.
{
llvm::Value *hasOverflow;
if (resultIsSigned) {
hasOverflow = IGF.Builder.CreateICmpUGT(valueWidth,
IGF.IGM.getSize(Size(resultWidth)));
} else {
static_assert(IntegerLiteralFlags::IsNegativeFlag == 1,
"hardcoded in this truncation");
auto isNegative = IGF.Builder.CreateTrunc(flags, boolTy);
auto tooBig = IGF.Builder.CreateICmpUGT(valueWidth,
IGF.IGM.getSize(Size(resultWidth + 1)));
hasOverflow = IGF.Builder.CreateOr(isNegative, tooBig);
}
IGF.Builder.CreateCondBr(hasOverflow, invalidBB, validBB);
}
// In the invalid block, we just need to construct the result. This block
// only exists to split the otherwise-critical edge.
IGF.Builder.emitBlock(invalidBB);
{
resultPHI->addIncoming(llvm::ConstantInt::get(resultTy, 0), invalidBB);
overflowPHI->addIncoming(llvm::ConstantInt::get(boolTy, 1), invalidBB);
IGF.Builder.CreateBr(doneBB);
}
// Okay, the value fits in the result type, so overflow is off the table
// and we just need to assemble a value of resultTy. But we might not have
// the full complement of chunks.
IGF.Builder.emitBlock(validBB);
{
auto firstChunk = IGF.Builder.CreateLoad(data);
// The easy case is if resultWidth <= chunkWidth, in which case knowing
// that we haven't overflowed is sufficient to say that we can just
// use the first chunk.
if (resultWidth <= chunkWidth) {
auto result = IGF.Builder.CreateTrunc(firstChunk, resultTy);
resultPHI->addIncoming(result, validBB);
overflowPHI->addIncoming(llvm::ConstantInt::get(boolTy, 0), validBB);
IGF.Builder.CreateBr(doneBB);
// Otherwise, we're going to have to test dynamically how many chunks
// we need to read.
} else {
assert(maxNumChunks >= 2);
llvm::Value *cur = firstChunk;
for (size_t i = 1; i != maxNumChunks; ++i) {
auto extendBB = IGF.createBasicBlock("intliteral.trunc.finish");
auto nextBB = IGF.createBasicBlock("intliteral.trunc.next");
// If the result is signed, then we're done if:
// valueWidth <= bitsInChunksReadSoFar
// If the result is unsigned, then we're done if:
// valueWidth <= bitsInChunksReadSoFar + 1
// (because we know the next bit will be zero)
auto limit = i * chunkWidth + size_t(!resultIsSigned);
auto isComplete =
IGF.Builder.CreateICmpULE(valueWidth, IGF.IGM.getSize(Size(limit)));
IGF.Builder.CreateCondBr(isComplete, extendBB, nextBB);
// If we're done, extend the current value to the result type and
// then branch out.
IGF.Builder.emitBlock(extendBB);
{
auto extendedResult =
resultIsSigned ? IGF.Builder.CreateSExt(cur, resultTy)
: IGF.Builder.CreateZExt(cur, resultTy);
resultPHI->addIncoming(extendedResult, extendBB);
overflowPHI->addIncoming(llvm::ConstantInt::get(boolTy, 0), extendBB);
IGF.Builder.CreateBr(doneBB);
}
// Otherwise, load the next chunk.
IGF.Builder.emitBlock(nextBB);
auto nextChunkAddr =
IGF.Builder.CreateConstArrayGEP(data, i, IGF.IGM.getPointerSize());
auto nextChunk = IGF.Builder.CreateLoad(nextChunkAddr);
// Zero-extend the current value and the chunk and then shift the
// chunk into place. If this is the last iteration, we should use
// the final result type; the shift might then drop bits, but they
// should just be sign-extension bits.
auto nextTy = (i + 1 == maxNumChunks
? resultTy
: llvm::IntegerType::get(IGF.IGM.getLLVMContext(),
(i + 1) * chunkWidth));
cur = IGF.Builder.CreateZExt(cur, nextTy);
auto shiftedNextChunk =
IGF.Builder.CreateShl(IGF.Builder.CreateZExt(nextChunk, nextTy),
i * chunkWidth);
cur = IGF.Builder.CreateAdd(cur, shiftedNextChunk);
}
// Given the overflow check before, we know we don't need to look at
// any more chunks.
assert(cur->getType() == resultTy);
auto curBB = IGF.Builder.GetInsertBlock();
resultPHI->addIncoming(cur, curBB);
overflowPHI->addIncoming(llvm::ConstantInt::get(boolTy, 0), curBB);
IGF.Builder.CreateBr(doneBB);
}
}
// Emit the continuation block. We've already set up the PHIs here and
// add them to `out`, so there's nothing else to do.
IGF.Builder.emitBlock(doneBB);
}
static llvm::Value *emitIntegerLiteralToFloatCall(IRGenFunction &IGF,
llvm::Value *data,
llvm::Value *flags,
unsigned bitWidth) {
assert(bitWidth == 32 || bitWidth == 64);
auto fn = bitWidth == 32 ? IGF.IGM.getIntToFloat32Fn()
: IGF.IGM.getIntToFloat64Fn();
auto call = IGF.Builder.CreateCall(fn, {data, flags});
call->setCallingConv(IGF.IGM.SwiftCC);
call->setDoesNotThrow();
call->setOnlyReadsMemory();
call->setOnlyAccessesArgMemory();
return call;
}
llvm::Value *irgen::emitIntegerLiteralToFP(IRGenFunction &IGF,
Explosion &in,
llvm::Type *toType) {
auto data = in.claimNext();
auto flags = in.claimNext();
assert(toType->isFloatingPointTy());
switch (toType->getTypeID()) {
case llvm::Type::HalfTyID: {
auto flt = emitIntegerLiteralToFloatCall(IGF, data, flags, 32);
return IGF.Builder.CreateFPTrunc(flt, toType);
}
case llvm::Type::FloatTyID:
return emitIntegerLiteralToFloatCall(IGF, data, flags, 32);
case llvm::Type::DoubleTyID:
return emitIntegerLiteralToFloatCall(IGF, data, flags, 64);
// TODO: add runtime functions for some of these?
case llvm::Type::X86_FP80TyID:
case llvm::Type::FP128TyID:
case llvm::Type::PPC_FP128TyID: {
auto dbl = emitIntegerLiteralToFloatCall(IGF, data, flags, 64);
return IGF.Builder.CreateFPExt(dbl, toType);
}
default:
llvm_unreachable("not a floating-point type");
}
}