//===--- ConstantBuilder.h - IR generation for constant structs -*- C++ -*-===// // // This source file is part of the Swift.org open source project // // Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information // See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors // //===----------------------------------------------------------------------===// // // This file implements IR generation of constant packed LLVM structs. //===----------------------------------------------------------------------===// #include "swift/AST/Mangle.h" #include "swift/ABI/MetadataValues.h" #include "llvm/IR/Constants.h" #include "llvm/IR/DerivedTypes.h" #include "llvm/IR/GlobalVariable.h" #include "llvm/IR/Instructions.h" #include "Address.h" #include "IRGenModule.h" #include "IRGenFunction.h" namespace swift { namespace irgen { class ConstantBuilderBase { protected: IRGenModule &IGM; ConstantBuilderBase(IRGenModule &IGM) : IGM(IGM) {} }; template class ConstantBuilder : public Base { protected: template ConstantBuilder(T &&...args) : Base(std::forward(args)...) {} IRGenModule &IGM = Base::IGM; private: llvm::GlobalVariable *relativeAddressBase = nullptr; llvm::SmallVector Fields; Size NextOffset = Size(0); protected: Size getNextOffset() const { return NextOffset; } void addStruct(llvm::Constant *st) { assert(st->getType()->isStructTy()); Fields.push_back(st); NextOffset += Size(IGM.DataLayout.getTypeStoreSize(st->getType())); } /// Add a constant word-sized value. void addConstantWord(int64_t value) { addWord(llvm::ConstantInt::get(IGM.SizeTy, value)); } /// Add a word-sized value. void addWord(llvm::Constant *value) { assert(value->getType() == IGM.IntPtrTy || value->getType()->isPointerTy()); Fields.push_back(value); NextOffset += IGM.getPointerSize(); } void setRelativeAddressBase(llvm::GlobalVariable *base) { relativeAddressBase = base; } llvm::Constant *getRelativeAddressFromNextField(llvm::Constant *referent, llvm::IntegerType *addressTy = nullptr) { assert(relativeAddressBase && "no relative address base set"); if (!addressTy) addressTy = IGM.RelativeAddressTy; // Determine the address of the next field in the initializer. llvm::Constant *fieldAddr = llvm::ConstantExpr::getPtrToInt(relativeAddressBase, IGM.SizeTy); fieldAddr = llvm::ConstantExpr::getAdd(fieldAddr, llvm::ConstantInt::get(IGM.SizeTy, getNextOffset().getValue())); referent = llvm::ConstantExpr::getPtrToInt(referent, IGM.SizeTy); llvm::Constant *relative = llvm::ConstantExpr::getSub(referent, fieldAddr); if (relative->getType() != addressTy) relative = llvm::ConstantExpr::getTrunc(relative, addressTy); return relative; } /// Add a 32-bit relative address from the current location in the local /// being built to another global variable. void addRelativeAddress(llvm::Constant *referent) { addInt32(getRelativeAddressFromNextField(referent)); } /// Add a pointer-sized relative address from the current location in the /// local being built to another global variable. void addFarRelativeAddress(llvm::Constant *referent) { addWord(getRelativeAddressFromNextField(referent, IGM.FarRelativeAddressTy)); } /// Add a 32-bit relative address from the current location in the local /// being built to another global variable, or null if a null referent /// is passed. void addRelativeAddressOrNull(llvm::Constant *referent) { if (referent) addRelativeAddress(referent); else addConstantInt32(0); } /// Add a pointer-sized relative address from the current location in the /// local being built to another global variable, or null if a null referent /// is passed. void addFarRelativeAddressOrNull(llvm::Constant *referent) { if (referent) addFarRelativeAddress(referent); else addConstantWord(0); } /// Add a 32-bit relative address from the current location in the local /// being built to another global variable. Pack a constant integer into /// the alignment bits of the pointer. void addRelativeAddressWithTag(llvm::Constant *referent, unsigned tag) { assert(tag < 4 && "tag too big to pack in relative address"); llvm::Constant *relativeAddr = getRelativeAddressFromNextField(referent); relativeAddr = llvm::ConstantExpr::getAdd(relativeAddr, llvm::ConstantInt::get(IGM.RelativeAddressTy, tag)); addInt32(relativeAddr); } /// Add a pointer-size relative address from the current location in the /// local being built to another global variable. Pack a constant integer /// into the alignment bits of the pointer. void addFarRelativeAddressWithTag(llvm::Constant *referent, unsigned tag) { // FIXME: could be 8 when targeting 64-bit platforms assert(tag < 4 && "tag too big to pack in relative address"); llvm::Constant *relativeAddr = getRelativeAddressFromNextField(referent, IGM.FarRelativeAddressTy); relativeAddr = llvm::ConstantExpr::getAdd(relativeAddr, llvm::ConstantInt::get(IGM.FarRelativeAddressTy, tag)); addWord(relativeAddr); } /// Add a uint32_t value that represents the given offset /// scaled to a number of words. void addConstantInt32InWords(Size value) { addConstantInt32(IGM.getOffsetInWords(value)); } /// Add a constant 32-bit value. void addConstantInt32(int32_t value) { addInt32(llvm::ConstantInt::get(IGM.Int32Ty, value)); } /// Add a 32-bit value. void addInt32(llvm::Constant *value) { assert(value->getType() == IGM.Int32Ty); Fields.push_back(value); NextOffset += Size(4); } /// Add a constant 16-bit value. void addConstantInt16(int16_t value) { addInt16(llvm::ConstantInt::get(IGM.Int16Ty, value)); } /// Add a 16-bit value. void addInt16(llvm::Constant *value) { assert(value->getType() == IGM.Int16Ty); Fields.push_back(value); NextOffset += Size(2); } /// Add a constant 8-bit value. void addConstantInt8(int8_t value) { addInt8(llvm::ConstantInt::get(IGM.Int8Ty, value)); } /// Add an 8-bit value. void addInt8(llvm::Constant *value) { assert(value->getType() == IGM.Int8Ty); Fields.push_back(value); NextOffset += Size(1); } /// Add a constant of the given size. void addStruct(llvm::Constant *value, Size size) { assert(size.getValue() == IGM.DataLayout.getTypeStoreSize(value->getType())); Fields.push_back(value); NextOffset += size; } class ReservationToken { size_t Index; ReservationToken(size_t index) : Index(index) {} friend ConstantBuilder; }; ReservationToken reserveFields(unsigned numFields, Size size) { unsigned index = Fields.size(); Fields.append(numFields, nullptr); NextOffset += size; return ReservationToken(index); } MutableArrayRef claimReservation(ReservationToken token, unsigned numFields) { return MutableArrayRef(&Fields[0] + token.Index, numFields); } public: llvm::Constant *getInit() const { return llvm::ConstantStruct::getAnon(Fields, /*packed*/ true); } /// An optimization of getInit for when we have a known type we /// can use when there aren't any extra fields. llvm::Constant *getInitWithSuggestedType(unsigned numFields, llvm::StructType *type) { if (Fields.size() == numFields) { return llvm::ConstantStruct::get(type, Fields); } else { return getInit(); } } }; } // end namespace irgen } // end namespace swift