| //===--- 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"); |
| } |
| } |