blob: 2163efb6eb2b702418e32bfc621f7ee411dabc11 [file] [log] [blame]
//===--- ScalarPairTypeInfo.h - Type info for scalar pairs ------*- C++ -*-===//
//
// 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 defines ScalarPairTypeInfo, which is a convenient abstract
// implementation of TypeInfo for working with types that are
// efficiently scalarizable.
//
//===----------------------------------------------------------------------===//
#ifndef SWIFT_IRGEN_SCALARPAIRTYPEINFO_H
#define SWIFT_IRGEN_SCALARPAIRTYPEINFO_H
#include "NativeConventionSchema.h"
#include "ScalarTypeInfo.h"
namespace swift {
namespace irgen {
template <class Derived, class Base>
class ScalarPairTypeInfo : public ScalarTypeInfo<Derived, Base> {
using super = ScalarTypeInfo<Derived, Base>;
protected:
template <class... T> ScalarPairTypeInfo(T &&...args)
: super(::std::forward<T>(args)...) {}
const Derived &asDerived() const {
return static_cast<const Derived &>(*this);
}
public:
llvm::StructType *getStorageType() const {
return cast<llvm::StructType>(TypeInfo::getStorageType());
}
Address projectFirstElement(IRGenFunction &IGF, Address address) const {
return IGF.Builder.CreateStructGEP(address, 0, Size(0),
address->getName()
+ asDerived().getFirstElementLabel());
}
Address projectSecondElement(IRGenFunction &IGF, Address address) const {
return IGF.Builder.CreateStructGEP(address, 1,
asDerived().getSecondElementOffset(IGF.IGM),
address->getName() + asDerived().getSecondElementLabel());
}
unsigned getExplosionSize() const override {
return 2;
}
void getSchema(ExplosionSchema &schema) const override {
llvm::StructType *structTy = getStorageType();
schema.add(ExplosionSchema::Element::forScalar(structTy->getElementType(0)));
schema.add(ExplosionSchema::Element::forScalar(structTy->getElementType(1)));
}
void addToAggLowering(IRGenModule &IGM, SwiftAggLowering &lowering,
Size offset) const override {
llvm::StructType *structTy = getStorageType();
this->addScalarToAggLowering(IGM, lowering, structTy->getElementType(0),
offset, asDerived().getFirstElementSize(IGM));
this->addScalarToAggLowering(IGM, lowering, structTy->getElementType(1),
offset + asDerived().getSecondElementOffset(IGM),
asDerived().getSecondElementSize(IGM));
}
void loadAsCopy(IRGenFunction &IGF, Address address,
Explosion &e) const override {
Address firstAddr = projectFirstElement(IGF, address);
auto first =
IGF.Builder.CreateLoad(firstAddr, firstAddr->getName() + ".load");
asDerived().emitRetainFirstElement(IGF, first);
e.add(first);
Address secondAddr = projectSecondElement(IGF, address);
auto second = IGF.Builder.CreateLoad(secondAddr);
asDerived().emitRetainSecondElement(IGF, second);
e.add(second);
}
void loadAsTake(IRGenFunction &IGF, Address addr,
Explosion &e) const override {
// Load the function.
Address firstAddr = projectFirstElement(IGF, addr);
e.add(IGF.Builder.CreateLoad(firstAddr));
Address secondAddr = projectSecondElement(IGF, addr);
e.add(IGF.Builder.CreateLoad(secondAddr));
}
void assign(IRGenFunction &IGF, Explosion &e, Address address,
bool isOutlined) const override {
// Store the function pointer.
Address firstAddr = projectFirstElement(IGF, address);
asDerived().emitAssignFirstElement(IGF, e.claimNext(), firstAddr);
Address secondAddr = projectSecondElement(IGF, address);
asDerived().emitAssignSecondElement(IGF, e.claimNext(), secondAddr);
}
void initialize(IRGenFunction &IGF, Explosion &e, Address address,
bool isOutlined) const override {
Address firstAddr = projectFirstElement(IGF, address);
IGF.Builder.CreateStore(e.claimNext(), firstAddr);
Address secondAddr = projectSecondElement(IGF, address);
IGF.Builder.CreateStore(e.claimNext(), secondAddr);
}
void copy(IRGenFunction &IGF, Explosion &src,
Explosion &dest, Atomicity atomicity) const override {
auto first = src.claimNext();
asDerived().emitRetainFirstElement(IGF, first, atomicity);
dest.add(first);
auto second = src.claimNext();
asDerived().emitRetainSecondElement(IGF, second, atomicity);
dest.add(second);
}
void consume(IRGenFunction &IGF, Explosion &src,
Atomicity atomicity) const override {
auto first = src.claimNext();
asDerived().emitReleaseFirstElement(IGF, first, atomicity);
auto second = src.claimNext();
asDerived().emitReleaseSecondElement(IGF, second, atomicity);
}
void fixLifetime(IRGenFunction &IGF, Explosion &src) const override {
auto first = src.claimNext();
if (!asDerived().isFirstElementTrivial())
IGF.emitFixLifetime(first);
auto second = src.claimNext();
if (!asDerived().isSecondElementTrivial())
IGF.emitFixLifetime(second);
}
void destroy(IRGenFunction &IGF, Address addr, SILType T,
bool isOutlined) const override {
if (!asDerived().isFirstElementTrivial()) {
auto first = IGF.Builder.CreateLoad(projectFirstElement(IGF, addr));
asDerived().emitReleaseFirstElement(IGF, first);
}
if (!asDerived().isSecondElementTrivial()) {
auto first = IGF.Builder.CreateLoad(projectSecondElement(IGF, addr));
asDerived().emitReleaseSecondElement(IGF, first);
}
}
void packIntoEnumPayload(IRGenFunction &IGF,
EnumPayload &payload,
Explosion &src,
unsigned offset) const override {
payload.insertValue(IGF, src.claimNext(), offset);
payload.insertValue(IGF, src.claimNext(),
offset + asDerived().getSecondElementOffset(IGF.IGM).getValueInBits());
}
void unpackFromEnumPayload(IRGenFunction &IGF,
const EnumPayload &payload,
Explosion &dest,
unsigned offset) const override {
auto storageTy = getStorageType();
dest.add(payload.extractValue(IGF, storageTy->getElementType(0), offset));
dest.add(payload.extractValue(IGF, storageTy->getElementType(1),
offset + asDerived().getSecondElementOffset(IGF.IGM).getValueInBits()));
}
};
}
}
#endif