blob: 522f59adff602f3f5b1ed340d7f2452de6847869 [file] [log] [blame]
//===--- ConstantInitBuilder.cpp - Global initializer builder -------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// This file defines out-of-line routines for building initializers for
// global variables, in particular the kind of globals that are implicitly
// introduced by various language ABIs.
//
//===----------------------------------------------------------------------===//
#include "ConstantInitBuilder.h"
#include "CIRGenModule.h"
using namespace clang;
using namespace cir;
ConstantInitBuilderBase::ConstantInitBuilderBase(CIRGenModule &CGM)
: CGM(CGM), builder(CGM.getBuilder()) {}
mlir::Type ConstantInitFuture::getType() const {
assert(Data && "dereferencing null future");
if (Data.is<mlir::Attribute>()) {
auto attr = mlir::dyn_cast<mlir::TypedAttr>(Data.get<mlir::Attribute>());
assert(attr && "expected typed attribute");
return attr.getType();
} else {
llvm_unreachable("Only sypport typed attributes here");
}
}
void ConstantInitFuture::abandon() {
assert(Data && "abandoning null future");
if (auto builder = mlir::dyn_cast<ConstantInitBuilderBase *>(Data)) {
builder->abandon(0);
}
Data = nullptr;
}
void ConstantInitFuture::installInGlobal(mlir::cir::GlobalOp GV) {
assert(Data && "installing null future");
if (Data.is<mlir::Attribute>()) {
CIRGenModule::setInitializer(GV, Data.get<mlir::Attribute>());
} else {
llvm_unreachable("NYI");
// auto &builder = *Data.get<ConstantInitBuilderBase *>();
// assert(builder.Buffer.size() == 1);
// builder.setGlobalInitializer(GV, builder.Buffer[0]);
// builder.Buffer.clear();
// Data = nullptr;
}
}
ConstantInitFuture
ConstantInitBuilderBase::createFuture(mlir::Attribute initializer) {
assert(Buffer.empty() && "buffer not current empty");
Buffer.push_back(initializer);
return ConstantInitFuture(this);
}
// Only used in this file.
inline ConstantInitFuture::ConstantInitFuture(ConstantInitBuilderBase *builder)
: Data(builder) {
assert(!builder->Frozen);
assert(builder->Buffer.size() == 1);
assert(builder->Buffer[0] != nullptr);
}
mlir::cir::GlobalOp ConstantInitBuilderBase::createGlobal(
mlir::Attribute initializer, const llvm::Twine &name, CharUnits alignment,
bool constant, mlir::cir::GlobalLinkageKind linkage,
unsigned addressSpace) {
llvm_unreachable("NYI");
// auto GV =
// new llvm::GlobalVariable(CGM.getModule(), initializer->getType(),
// constant, linkage, initializer, name,
// /*insert before*/ nullptr,
// llvm::GlobalValue::NotThreadLocal,
// addressSpace);
// GV->setAlignment(alignment.getAsAlign());
// resolveSelfReferences(GV);
// return GV;
}
void ConstantInitBuilderBase::setGlobalInitializer(
mlir::cir::GlobalOp GV, mlir::Attribute initializer) {
CIRGenModule::setInitializer(GV, initializer);
if (!SelfReferences.empty())
resolveSelfReferences(GV);
}
void ConstantInitBuilderBase::resolveSelfReferences(mlir::cir::GlobalOp GV) {
llvm_unreachable("NYI");
// for (auto &entry : SelfReferences) {
// mlir::Attribute resolvedReference =
// llvm::ConstantExpr::getInBoundsGetElementPtr(GV->getValueType(), GV,
// entry.Indices);
// auto dummy = entry.Dummy;
// dummy->replaceAllUsesWith(resolvedReference);
// dummy->eraseFromParent();
// }
// SelfReferences.clear();
}
void ConstantInitBuilderBase::abandon(size_t newEnd) {
llvm_unreachable("NYI");
// // Remove all the entries we've added.
// Buffer.erase(Buffer.begin() + newEnd, Buffer.end());
// // If we're abandoning all the way to the beginning, destroy
// // all the self-references, because we might not get another
// // opportunity.
// if (newEnd == 0) {
// for (auto &entry : SelfReferences) {
// auto dummy = entry.Dummy;
// dummy->replaceAllUsesWith(llvm::PoisonValue::get(dummy->getType()));
// dummy->eraseFromParent();
// }
// SelfReferences.clear();
// }
}
void ConstantAggregateBuilderBase::addSize(CharUnits size) {
add(Builder.CGM.getSize(size));
}
mlir::Attribute
ConstantAggregateBuilderBase::getRelativeOffset(mlir::cir::IntType offsetType,
mlir::Attribute target) {
return getRelativeOffsetToPosition(offsetType, target,
Builder.Buffer.size() - Begin);
}
mlir::Attribute ConstantAggregateBuilderBase::getRelativeOffsetToPosition(
mlir::cir::IntType offsetType, mlir::Attribute target, size_t position) {
llvm_unreachable("NYI");
// // Compute the address of the relative-address slot.
// auto base = getAddrOfPosition(offsetType, position);
// // Subtract.
// base = llvm::ConstantExpr::getPtrToInt(base, Builder.CGM.IntPtrTy);
// target = llvm::ConstantExpr::getPtrToInt(target, Builder.CGM.IntPtrTy);
// mlir::Attribute offset = llvm::ConstantExpr::getSub(target, base);
// // Truncate to the relative-address type if necessary.
// if (Builder.CGM.IntPtrTy != offsetType) {
// offset = llvm::ConstantExpr::getTrunc(offset, offsetType);
// }
// return offset;
}
mlir::Attribute
ConstantAggregateBuilderBase::getAddrOfPosition(mlir::Type type,
size_t position) {
llvm_unreachable("NYI");
// // Make a global variable. We will replace this with a GEP to this
// // position after installing the initializer.
// auto dummy = new llvm::GlobalVariable(Builder.CGM.getModule(), type, true,
// llvm::GlobalVariable::PrivateLinkage,
// nullptr, "");
// Builder.SelfReferences.emplace_back(dummy);
// auto &entry = Builder.SelfReferences.back();
// (void)getGEPIndicesTo(entry.Indices, position + Begin);
// return dummy;
}
mlir::Attribute
ConstantAggregateBuilderBase::getAddrOfCurrentPosition(mlir::Type type) {
llvm_unreachable("NYI");
// // Make a global variable. We will replace this with a GEP to this
// // position after installing the initializer.
// auto dummy = new llvm::GlobalVariable(Builder.CGM.getModule(), type, true,
// llvm::GlobalVariable::PrivateLinkage,
// nullptr, "");
// Builder.SelfReferences.emplace_back(dummy);
// auto &entry = Builder.SelfReferences.back();
// (void)getGEPIndicesToCurrentPosition(entry.Indices);
// return dummy;
}
void ConstantAggregateBuilderBase::getGEPIndicesTo(
llvm::SmallVectorImpl<mlir::Attribute> &indices, size_t position) const {
llvm_unreachable("NYI");
// // Recurse on the parent builder if present.
// if (Parent) {
// Parent->getGEPIndicesTo(indices, Begin);
// // Otherwise, add an index to drill into the first level of pointer.
// } else {
// assert(indices.empty());
// indices.push_back(llvm::ConstantInt::get(Builder.CGM.Int32Ty, 0));
// }
// assert(position >= Begin);
// // We have to use i32 here because struct GEPs demand i32 indices.
// // It's rather unlikely to matter in practice.
// indices.push_back(
// llvm::ConstantInt::get(Builder.CGM.Int32Ty, position - Begin));
}
ConstantAggregateBuilderBase::PlaceholderPosition
ConstantAggregateBuilderBase::addPlaceholderWithSize(mlir::Type type) {
llvm_unreachable("NYI");
// // Bring the offset up to the last field.
// CharUnits offset = getNextOffsetFromGlobal();
// // Create the placeholder.
// auto position = addPlaceholder();
// // Advance the offset past that field.
// auto &layout = Builder.CGM.getDataLayout();
// if (!Packed)
// offset =
// offset.alignTo(CharUnits::fromQuantity(layout.getABITypeAlign(type)));
// offset += CharUnits::fromQuantity(layout.getTypeStoreSize(type));
// CachedOffsetEnd = Builder.Buffer.size();
// CachedOffsetFromGlobal = offset;
// return position;
}
CharUnits
ConstantAggregateBuilderBase::getOffsetFromGlobalTo(size_t end) const {
size_t cacheEnd = CachedOffsetEnd;
assert(cacheEnd <= end);
// Fast path: if the cache is valid, just use it.
if (cacheEnd == end) {
return CachedOffsetFromGlobal;
}
// If the cached range ends before the index at which the current
// aggregate starts, recurse for the parent.
CharUnits offset;
if (cacheEnd < Begin) {
assert(cacheEnd == 0);
assert(Parent && "Begin != 0 for root builder");
cacheEnd = Begin;
offset = Parent->getOffsetFromGlobalTo(Begin);
} else {
offset = CachedOffsetFromGlobal;
}
// Perform simple layout on the elements in cacheEnd..<end.
if (cacheEnd != end) {
llvm_unreachable("NYI");
// auto &layout = Builder.CGM.getDataLayout();
// do {
// mlir::Attribute element = Builder.Buffer[cacheEnd];
// assert(element != nullptr &&
// "cannot compute offset when a placeholder is present");
// mlir::Type elementType = element->getType();
// if (!Packed)
// offset = offset.alignTo(
// CharUnits::fromQuantity(layout.getABITypeAlign(elementType)));
// offset +=
// CharUnits::fromQuantity(layout.getTypeStoreSize(elementType));
// } while (++cacheEnd != end);
}
// Cache and return.
CachedOffsetEnd = cacheEnd;
CachedOffsetFromGlobal = offset;
return offset;
}
// FIXME(cir): ideally we should use CIRGenBuilder for both static function
// bellow by threading ConstantAggregateBuilderBase through
// ConstantAggregateBuilderBase.
static mlir::cir::ConstArrayAttr getConstArray(mlir::Attribute attrs,
mlir::cir::ArrayType arrayTy) {
return mlir::cir::ConstArrayAttr::get(arrayTy, attrs);
}
mlir::Attribute ConstantAggregateBuilderBase::finishArray(mlir::Type eltTy) {
markFinished();
auto &buffer = getBuffer();
assert((Begin < buffer.size() || (Begin == buffer.size() && eltTy)) &&
"didn't add any array elements without element type");
auto elts = llvm::ArrayRef(buffer).slice(Begin);
if (!eltTy) {
llvm_unreachable("NYI");
// Uncomment this once we get a testcase.
// auto tAttr = elts[0].dyn_cast<mlir::TypedAttr>();
// assert(tAttr && "expected typed attribute");
// eltTy = tAttr.getType();
}
auto constant = getConstArray(
mlir::ArrayAttr::get(eltTy.getContext(), elts),
mlir::cir::ArrayType::get(eltTy.getContext(), eltTy, elts.size()));
buffer.erase(buffer.begin() + Begin, buffer.end());
return constant;
}
mlir::Attribute
ConstantAggregateBuilderBase::finishStruct(mlir::MLIRContext *ctx,
mlir::cir::StructType ty) {
markFinished();
auto &buffer = getBuffer();
auto elts = llvm::ArrayRef(buffer).slice(Begin);
if (ty == nullptr && elts.empty()) {
llvm_unreachable("NYI");
}
mlir::Attribute constant;
if (ty) {
llvm_unreachable("NYI");
// assert(ty->isPacked() == Packed);
// constant = llvm::ConstantStruct::get(ty, elts);
} else {
const auto members = mlir::ArrayAttr::get(ctx, elts);
constant = Builder.CGM.getBuilder().getAnonConstStruct(members, Packed);
}
buffer.erase(buffer.begin() + Begin, buffer.end());
return constant;
}