//===--- 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()->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()) { APInt zero(type->getWidth().getLeastWidth(), 0); return llvm::ConstantInt::get(IGM.getLLVMContext(), zero); } if (auto type = astType->getAs()) { 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()) { 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 &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 llvm::Constant *emitConstantStructOrTuple(IRGenModule &IGM, InstTy inst, NextIndexFunc nextIndex) { auto type = inst->getType(); auto *sTy = cast(IGM.getTypeInfo(type).getStorageType()); SmallVector 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 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(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(operand)) { return emitConstantStructOrTuple(IGM, TI, irgen::getPhysicalTupleElementStructIndex); } else if (auto *ILI = dyn_cast(operand)) { return emitConstantInt(IGM, ILI); } else if (auto *FLI = dyn_cast(operand)) { return emitConstantFP(IGM, FLI); } else if (auto *SLI = dyn_cast(operand)) { return emitAddrOfConstantString(IGM, SLI); } else if (auto *BI = dyn_cast(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(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(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(ClassLayout->getType()); SmallVector 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); }