mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
Save a couple relocations per concrete value type, leaving only the value witness table as an absolute symbol.
242 lines
8.0 KiB
C++
242 lines
8.0 KiB
C++
//===--- 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 Base = ConstantBuilderBase>
|
|
class ConstantBuilder : public Base {
|
|
protected:
|
|
template <class... T>
|
|
ConstantBuilder(T &&...args) : Base(std::forward<T>(args)...) {}
|
|
|
|
IRGenModule &IGM = Base::IGM;
|
|
|
|
private:
|
|
llvm::GlobalVariable *relativeAddressBase = nullptr;
|
|
llvm::SmallVector<llvm::Constant*, 16> 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<Base>;
|
|
};
|
|
ReservationToken reserveFields(unsigned numFields, Size size) {
|
|
unsigned index = Fields.size();
|
|
Fields.append(numFields, nullptr);
|
|
NextOffset += size;
|
|
return ReservationToken(index);
|
|
}
|
|
MutableArrayRef<llvm::Constant*> claimReservation(ReservationToken token,
|
|
unsigned numFields) {
|
|
return MutableArrayRef<llvm::Constant*>(&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
|