blob: 16479cb0031f305f4d9d2acfd46e6bbaa0acb716 [file] [log] [blame]
//===-- SimplifiedFuncTypeMap.cpp - Consistent type remapping----*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "SimplifiedFuncTypeMap.h"
using namespace llvm;
Type *SimplifiedFuncTypeMap::getSimpleType(LLVMContext &Ctx, Type *Ty) {
auto Found = MappedTypes.find(Ty);
if (Found != MappedTypes.end()) {
return Found->second;
}
StructMap Tentatives;
auto Ret = getSimpleAggregateTypeInternal(Ctx, Ty, Tentatives);
assert(Tentatives.size() == 0);
if (!Ty->isStructTy()) {
// Structs are memoized in getSimpleAggregateTypeInternal.
MappedTypes[Ty] = Ret;
}
return Ret;
}
// Transforms any type that could transitively reference a function pointer
// into a simplified type.
// We enter this function trying to determine the mapping of a type. Because
// of how structs are handled (not interned by llvm - see further comments
// below) we may be working with temporary types - types (pointers, for example)
// transitively referencing "tentative" structs. For that reason, we do not
// memoize anything here, except for structs. The latter is so that we avoid
// unnecessary repeated creation of types (pointers, function types, etc),
// as we try to map a given type.
SimplifiedFuncTypeMap::MappingResult
SimplifiedFuncTypeMap::getSimpleAggregateTypeInternal(LLVMContext &Ctx,
Type *Ty,
StructMap &Tentatives) {
// Leverage the map for types we encounter on the way.
auto Found = MappedTypes.find(Ty);
if (Found != MappedTypes.end()) {
return {Found->second, Found->second != Ty};
}
if (auto *OldFnTy = dyn_cast<FunctionType>(Ty)) {
return getSimpleFuncType(Ctx, Tentatives, OldFnTy);
}
if (auto PtrTy = dyn_cast<PointerType>(Ty)) {
auto *ElemTy = PtrTy->getPointerElementType();
auto NewTy = getSimpleAggregateTypeInternal(Ctx, ElemTy, Tentatives);
return {NewTy->getPointerTo(PtrTy->getAddressSpace()), NewTy.isChanged()};
}
if (auto ArrTy = dyn_cast<ArrayType>(Ty)) {
auto NewTy = getSimpleAggregateTypeInternal(
Ctx, ArrTy->getArrayElementType(), Tentatives);
return {ArrayType::get(NewTy, ArrTy->getArrayNumElements()),
NewTy.isChanged()};
}
if (auto VecTy = dyn_cast<VectorType>(Ty)) {
auto NewTy = getSimpleAggregateTypeInternal(
Ctx, VecTy->getVectorElementType(), Tentatives);
return {VectorType::get(NewTy, VecTy->getVectorNumElements()),
NewTy.isChanged()};
}
// LLVM doesn't intern identified structs (the ones with a name). This,
// together with the fact that such structs can be recursive,
// complicates things a bit. We want to make sure that we only change
// "unsimplified" structs (those that somehow reference funcs that
// are not simple).
// We don't want to change "simplified" structs, otherwise converting
// instruction types will become trickier.
if (auto StructTy = dyn_cast<StructType>(Ty)) {
ParamTypeVector ElemTypes;
if (!StructTy->isLiteral()) {
// Literals - struct without a name - cannot be recursive, so we
// don't need to form tentatives.
auto Found = Tentatives.find(StructTy);
// Having a tentative means we are in a recursion trying to map this
// particular struct, so arriving back to it is not a change.
// We will determine if this struct is actually
// changed by checking its other fields.
if (Found != Tentatives.end()) {
return {Found->second, false};
}
// We have never seen this struct, so we start a tentative.
std::string NewName = StructTy->getStructName();
NewName += ".simplified";
StructType *Tentative = StructType::create(Ctx, NewName);
Tentatives[StructTy] = Tentative;
bool Changed = isChangedStruct(Ctx, StructTy, ElemTypes, Tentatives);
Tentatives.erase(StructTy);
// We can now decide the mapping of the struct. We will register it
// early with MappedTypes, to avoid leaking tentatives unnecessarily.
// We are leaking the created struct here, but there is no way to
// correctly delete it.
if (!Changed) {
return {MappedTypes[StructTy] = StructTy, false};
} else {
Tentative->setBody(ElemTypes, StructTy->isPacked());
return {MappedTypes[StructTy] = Tentative, true};
}
} else {
bool Changed = isChangedStruct(Ctx, StructTy, ElemTypes, Tentatives);
if (!Changed) {
return {StructTy, false};
} else {
return {MappedTypes[StructTy] =
StructType::get(Ctx, ElemTypes, StructTy->isPacked()),
Changed};
}
}
}
// Anything else stays the same.
return {Ty, false};
}
bool SimplifiedFuncTypeMap::isChangedStruct(LLVMContext &Ctx,
StructType *StructTy,
ParamTypeVector &ElemTypes,
StructMap &Tentatives) {
bool Changed = false;
unsigned StructElemCount = StructTy->getStructNumElements();
for (unsigned I = 0; I < StructElemCount; I++) {
auto *ElemTy = StructTy->getStructElementType(I);
auto NewElem = getSimpleAggregateTypeInternal(Ctx, ElemTy, Tentatives);
ElemTypes.push_back(NewElem);
Changed |= NewElem.isChanged();
}
return Changed;
}