Files
swift-mirror/lib/IRGen/GenConstant.cpp
Erik Eckstein 44f07aea2b IRGen: a small refactoring in GenConstant
Just moving a few functions around and make emitConstantValue the main entry point for creating constants.

NFC
2021-02-09 19:56:43 +01:00

249 lines
10 KiB
C++

//===--- GenConstant.cpp - Swift IR Generation For Constants --------------===//
//
// 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 constant values.
//
//===----------------------------------------------------------------------===//
#include "llvm/IR/Constants.h"
#include "GenConstant.h"
#include "GenIntegerLiteral.h"
#include "GenStruct.h"
#include "GenTuple.h"
#include "TypeInfo.h"
#include "StructLayout.h"
#include "Callee.h"
#include "swift/Basic/Range.h"
#include "swift/SIL/SILModule.h"
using namespace swift;
using namespace irgen;
llvm::Constant *irgen::emitConstantInt(IRGenModule &IGM,
IntegerLiteralInst *ILI) {
BuiltinIntegerWidth width
= ILI->getType().castTo<AnyBuiltinIntegerType>()->getWidth();
// Handle arbitrary-precision integers.
if (width.isArbitraryWidth()) {
auto pair = emitConstantIntegerLiteral(IGM, ILI);
auto type = IGM.getIntegerLiteralTy();
return llvm::ConstantStruct::get(type, { pair.Data, pair.Flags });
}
APInt value = ILI->getValue();
// The value may need truncation if its type had an abstract size.
if (width.isPointerWidth()) {
unsigned pointerWidth = IGM.getPointerSize().getValueInBits();
assert(pointerWidth <= value.getBitWidth()
&& "lost precision at AST/SIL level?!");
if (pointerWidth < value.getBitWidth())
value = value.trunc(pointerWidth);
} else {
assert(width.isFixedWidth() && "impossible width value");
}
return llvm::ConstantInt::get(IGM.getLLVMContext(), value);
}
llvm::Constant *irgen::emitConstantZero(IRGenModule &IGM, BuiltinInst *BI) {
assert(IGM.getSILModule().getBuiltinInfo(BI->getName()).ID ==
BuiltinValueKind::ZeroInitializer);
auto helper = [&](CanType astType) -> llvm::Constant * {
if (auto type = astType->getAs<BuiltinIntegerType>()) {
APInt zero(type->getWidth().getLeastWidth(), 0);
return llvm::ConstantInt::get(IGM.getLLVMContext(), zero);
}
if (auto type = astType->getAs<BuiltinFloatType>()) {
const llvm::fltSemantics *sema = nullptr;
switch (type->getFPKind()) {
case BuiltinFloatType::IEEE16: sema = &APFloat::IEEEhalf(); break;
case BuiltinFloatType::IEEE32: sema = &APFloat::IEEEsingle(); break;
case BuiltinFloatType::IEEE64: sema = &APFloat::IEEEdouble(); break;
case BuiltinFloatType::IEEE80: sema = &APFloat::x87DoubleExtended(); break;
case BuiltinFloatType::IEEE128: sema = &APFloat::IEEEquad(); break;
case BuiltinFloatType::PPC128: sema = &APFloat::PPCDoubleDouble(); break;
}
auto zero = APFloat::getZero(*sema);
return llvm::ConstantFP::get(IGM.getLLVMContext(), zero);
}
llvm_unreachable("SIL allowed an unknown type?");
};
if (auto vector = BI->getType().getAs<BuiltinVectorType>()) {
auto zero = helper(vector.getElementType());
auto count = llvm::ElementCount::getFixed(vector->getNumElements());
return llvm::ConstantVector::getSplat(count, zero);
}
return helper(BI->getType().getASTType());
}
llvm::Constant *irgen::emitConstantFP(IRGenModule &IGM, FloatLiteralInst *FLI) {
return llvm::ConstantFP::get(IGM.getLLVMContext(), FLI->getValue());
}
llvm::Constant *irgen::emitAddrOfConstantString(IRGenModule &IGM,
StringLiteralInst *SLI) {
switch (SLI->getEncoding()) {
case StringLiteralInst::Encoding::Bytes:
case StringLiteralInst::Encoding::UTF8:
return IGM.getAddrOfGlobalString(SLI->getValue());
case StringLiteralInst::Encoding::ObjCSelector:
llvm_unreachable("cannot get the address of an Objective-C selector");
}
llvm_unreachable("bad string encoding");
}
namespace {
/// Fill in the missing values for padding.
void insertPadding(SmallVectorImpl<llvm::Constant *> &Elements,
llvm::StructType *sTy) {
// fill in any gaps, which are the explicit padding that swiftc inserts.
for (unsigned i = 0, e = Elements.size(); i != e; ++i) {
auto &elt = Elements[i];
if (elt == nullptr) {
auto *eltTy = sTy->getElementType(i);
assert(eltTy->isArrayTy() &&
eltTy->getArrayElementType()->isIntegerTy(8) &&
"Unexpected non-byte-array type for constant struct padding");
elt = llvm::UndefValue::get(eltTy);
}
}
}
template <typename InstTy, typename NextIndexFunc>
llvm::Constant *emitConstantStructOrTuple(IRGenModule &IGM, InstTy inst,
NextIndexFunc nextIndex) {
auto type = inst->getType();
auto *sTy = cast<llvm::StructType>(IGM.getTypeInfo(type).getStorageType());
SmallVector<llvm::Constant *, 32> elts(sTy->getNumElements(), nullptr);
// run over the Swift initializers, putting them into the struct as
// appropriate.
for (unsigned i = 0, e = inst->getElements().size(); i != e; ++i) {
auto operand = inst->getOperand(i);
Optional<unsigned> index = nextIndex(IGM, type, i);
if (index.hasValue()) {
assert(elts[index.getValue()] == nullptr &&
"Unexpected constant struct field overlap");
elts[index.getValue()] = emitConstantValue(IGM, operand);
}
}
insertPadding(elts, sTy);
return llvm::ConstantStruct::get(sTy, elts);
}
} // end anonymous namespace
llvm::Constant *irgen::emitConstantValue(IRGenModule &IGM, SILValue operand) {
if (auto *SI = dyn_cast<StructInst>(operand)) {
// The only way to get a struct's stored properties (which we need to map to
// their physical/LLVM index) is to iterate over the properties
// progressively. Fortunately the iteration order matches the order of
// operands in a StructInst.
auto StoredProperties = SI->getStructDecl()->getStoredProperties();
auto Iter = StoredProperties.begin();
return emitConstantStructOrTuple(
IGM, SI, [&Iter](IRGenModule &IGM, SILType Type, unsigned _i) mutable {
(void)_i;
auto *FD = *Iter++;
return irgen::getPhysicalStructFieldIndex(IGM, Type, FD);
});
} else if (auto *TI = dyn_cast<TupleInst>(operand)) {
return emitConstantStructOrTuple(IGM, TI,
irgen::getPhysicalTupleElementStructIndex);
} else if (auto *ILI = dyn_cast<IntegerLiteralInst>(operand)) {
return emitConstantInt(IGM, ILI);
} else if (auto *FLI = dyn_cast<FloatLiteralInst>(operand)) {
return emitConstantFP(IGM, FLI);
} else if (auto *SLI = dyn_cast<StringLiteralInst>(operand)) {
return emitAddrOfConstantString(IGM, SLI);
} else if (auto *BI = dyn_cast<BuiltinInst>(operand)) {
switch (IGM.getSILModule().getBuiltinInfo(BI->getName()).ID) {
case BuiltinValueKind::ZeroInitializer:
return emitConstantZero(IGM, BI);
case BuiltinValueKind::PtrToInt: {
llvm::Constant *ptr = emitConstantValue(IGM, BI->getArguments()[0]);
return llvm::ConstantExpr::getPtrToInt(ptr, IGM.IntPtrTy);
}
case BuiltinValueKind::ZExtOrBitCast: {
llvm::Constant *value = emitConstantValue(IGM, BI->getArguments()[0]);
return llvm::ConstantExpr::getZExtOrBitCast(value, IGM.getStorageType(BI->getType()));
}
case BuiltinValueKind::StringObjectOr: {
// It is a requirement that the or'd bits in the left argument are
// initialized with 0. Therefore the or-operation is equivalent to an
// addition. We need an addition to generate a valid relocation.
llvm::Constant *rhs = emitConstantValue(IGM, BI->getArguments()[1]);
if (auto *TE = dyn_cast<TupleExtractInst>(BI->getArguments()[0])) {
// Handle StringObjectOr(tuple_extract(usub_with_overflow(x, offset)), bits)
// This pattern appears in UTF8 String literal construction.
// Generate the equivalent: add(x, sub(bits - offset)
BuiltinInst *SubtrBI =
SILGlobalVariable::getOffsetSubtract(TE, IGM.getSILModule());
assert(SubtrBI && "unsupported argument of StringObjectOr");
auto *ptr = emitConstantValue(IGM, SubtrBI->getArguments()[0]);
auto *offset = emitConstantValue(IGM, SubtrBI->getArguments()[1]);
auto *totalOffset = llvm::ConstantExpr::getSub(rhs, offset);
return llvm::ConstantExpr::getAdd(ptr, totalOffset);
}
llvm::Constant *lhs = emitConstantValue(IGM, BI->getArguments()[0]);
return llvm::ConstantExpr::getAdd(lhs, rhs);
}
default:
llvm_unreachable("unsupported builtin for constant expression");
}
} else if (auto *VTBI = dyn_cast<ValueToBridgeObjectInst>(operand)) {
auto *val = emitConstantValue(IGM, VTBI->getOperand());
auto *sTy = IGM.getTypeInfo(VTBI->getType()).getStorageType();
return llvm::ConstantExpr::getIntToPtr(val, sTy);
} else {
llvm_unreachable("Unsupported SILInstruction in static initializer!");
}
}
llvm::Constant *irgen::emitConstantObject(IRGenModule &IGM, ObjectInst *OI,
StructLayout *ClassLayout) {
auto *sTy = cast<llvm::StructType>(ClassLayout->getType());
SmallVector<llvm::Constant *, 32> elts(sTy->getNumElements(), nullptr);
unsigned NumElems = OI->getAllElements().size();
assert(NumElems == ClassLayout->getElements().size());
// Construct the object init value including tail allocated elements.
for (unsigned i = 0; i != NumElems; ++i) {
SILValue Val = OI->getAllElements()[i];
const ElementLayout &EL = ClassLayout->getElements()[i];
if (!EL.isEmpty()) {
unsigned EltIdx = EL.getStructIndex();
assert(EltIdx != 0 && "the first element is the object header");
elts[EltIdx] = emitConstantValue(IGM, Val);
}
}
// Construct the object header.
llvm::Type *ObjectHeaderTy = sTy->getElementType(0);
assert(ObjectHeaderTy->isStructTy());
elts[0] = llvm::Constant::getNullValue(ObjectHeaderTy);
insertPadding(elts, sTy);
return llvm::ConstantStruct::get(sTy, elts);
}