//===--- 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 "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.LLVMContext, value); } llvm::Constant *irgen::emitConstantFP(IRGenModule &IGM, FloatLiteralInst *FLI) { return llvm::ConstantFP::get(IGM.LLVMContext, 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::UTF16: { // This is always a GEP of a GlobalVariable with a nul terminator. auto addr = IGM.getAddrOfGlobalUTF16String(SLI->getValue()); // Cast to Builtin.RawPointer. return llvm::ConstantExpr::getBitCast(addr, IGM.Int8PtrTy); } case StringLiteralInst::Encoding::ObjCSelector: llvm_unreachable("cannot get the address of an Objective-C selector"); } llvm_unreachable("bad string encoding"); } static llvm::Constant *emitConstantValue(IRGenModule &IGM, SILValue operand) { if (auto *SI = dyn_cast(operand)) { return emitConstantStruct(IGM, SI); } else if (auto *TI = dyn_cast(operand)) { return emitConstantTuple(IGM, TI); } 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::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!"); } } 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::emitConstantStruct(IRGenModule &IGM, StructInst *SI) { // 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); }); } llvm::Constant *irgen::emitConstantTuple(IRGenModule &IGM, TupleInst *TI) { return emitConstantStructOrTuple(IGM, TI, irgen::getPhysicalTupleElementStructIndex); } 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); }