Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -53,13 +53,13 @@ option (SEA_DSA_STATIC_EXE "Static executable." OFF)

## llvm
if (TOP_LEVEL)
find_package (LLVM 14.0 CONFIG)
find_package (LLVM 15.0 CONFIG)
if (NOT LLVM_FOUND)
ExternalProject_Get_Property (llvm INSTALL_DIR)
set (LLVM_ROOT ${INSTALL_DIR})
set (LLVM_DIR ${LLVM_ROOT}/lib/cmake/llvm CACHE PATH
"Forced location of LLVM cmake config" FORCE)
message (WARNING "No llvm found. Install LLVM 14.")
message (WARNING "No llvm found. Install LLVM 15.")
return()
endif()

Expand Down
8 changes: 0 additions & 8 deletions include/seadsa/FieldType.hh
Original file line number Diff line number Diff line change
Expand Up @@ -89,14 +89,6 @@ public:
return FieldType(PtrTy);
}

FieldType elemOf() const {
assert(!isUnknown());
assert(isPointer());

auto *NewTy = m_ty->getPointerElementType();
return FieldType(NewTy);
}

void dump(llvm::raw_ostream &OS = llvm::errs()) const {
if (m_NOT_IMPLEMENTED) {
OS << "TODO<" << m_whereNotImpl << ">";
Expand Down
20 changes: 4 additions & 16 deletions lib/seadsa/Cloner.cc
Original file line number Diff line number Diff line change
Expand Up @@ -27,23 +27,11 @@ static bool isConstantNoPtr(const llvm::Value *v) {
if (v->hasName() && v->getName().startswith(".str."))
return true;

if (!v->getType()->isPointerTy())
return false;

auto *type = v->getType()->getPointerElementType();
if (type->isIntegerTy() || type->isFloatingPointTy())
return true;

// auto *compositeTy = llvm::dyn_cast<llvm::CompositeType>(type);
// Shaobo: LLVM 11 removes `CompositeType`, which was a union of ArrayType,
// StructType, and VectorType.
if (!type->isAggregateType() && !type->isVectorTy())
return false;
if (!v->getType()->isPointerTy()) return false;

return std::all_of(type->subtype_begin(), type->subtype_end(),
[](const llvm::Type *ty) {
return ty->isIntegerTy() || ty->isFloatingPointTy();
});
// TODO: Can infer pointer type by checking its uses. For now, not much
// can be done and precision will be lost to opaque pointers in LLVM 15.
return false;
}

Node &Cloner::clone(const Node &n, bool forceAddAlloca,
Expand Down
2 changes: 1 addition & 1 deletion lib/seadsa/DsaLibFuncInfo.cc
Original file line number Diff line number Diff line change
Expand Up @@ -356,7 +356,7 @@ void DsaLibFuncInfo::generateSpec(const llvm::Function &F,
builder.CreateRet(retVal);
} else if (!retVal && F.getReturnType()->getTypeID()) {
retVal = builder.CreateAlloca(F.getReturnType(), nullptr);
Value *loadedRet = builder.CreateLoad(retVal->getType()->getPointerElementType(), retVal);
Value *loadedRet = builder.CreateLoad(F.getReturnType(), retVal);
builder.CreateRet(loadedRet);
}
}
Expand Down
204 changes: 107 additions & 97 deletions lib/seadsa/DsaLocal.cc
Original file line number Diff line number Diff line change
Expand Up @@ -168,8 +168,9 @@ Function *getCalledFunction(CallBase &CB) {

namespace {
// forward declaration
std::pair<int64_t, uint64_t>
computeGepOffset(Type *ptrTy, ArrayRef<Value *> Indicies, const DataLayout &dl);
std::pair<int64_t, uint64_t> computeGepOffset(Type *srcElementTy,
ArrayRef<Value *> Indicies,
const DataLayout &dl);

/*****************************************************************************/
/* BlockBuilderBase */
Expand Down Expand Up @@ -316,32 +317,37 @@ class GlobalBuilder : public BlockBuilderBase {
if (isa<ConstantDataSequential>(Init)) { return; }

if (Init->getType()->isPointerTy() && !isa<ConstantPointerNull>(Init)) {
if (cast<PointerType>(Init->getType())
->getElementType()
->isFunctionTy()) {
seadsa::Node &n = m_graph.mkNode();
seadsa::Cell nc(n, 0);
seadsa::DsaAllocSite *site = m_graph.mkAllocSite(*Init);
assert(site);
n.addAllocSite(*site);

// connect c with nc
c.growSize(0, Init->getType());
c.addAccessedType(0, Init->getType());
c.addLink(seadsa::Field(0, seadsa::FieldType(Init->getType())), nc);
return;
}

if (m_graph.hasCell(*Init)) {
// @g1 = ...*
// @g2 = ...** @g1
seadsa::Cell &nc = m_graph.mkCell(*Init, seadsa::Cell());
// connect c with nc
c.growSize(0, Init->getType());
c.addAccessedType(0, Init->getType());
c.addLink(seadsa::Field(0, seadsa::FieldType(Init->getType())), nc);
return;
}
// FIXME: This creates a node for a global function pointer. Needed by
// vtable in C++
// Disabled for now since in LLVM 15 there is no way to determine if the pointer is a
// function. May be inferenced by checking if the pointer is ever loaded as a function.

// if (cast<PointerType>(Init->getType())
// ->getElementType()
// ->isFunctionTy()) {
// seadsa::Node &n = m_graph.mkNode();
// seadsa::Cell nc(n, 0);
// seadsa::DsaAllocSite *site = m_graph.mkAllocSite(*Init);
// assert(site);
// n.addAllocSite(*site);

// // connect c with nc
// c.growSize(0, Init->getType());
// c.addAccessedType(0, Init->getType());
// c.addLink(seadsa::Field(0, seadsa::FieldType(Init->getType())), nc);
// return;
// }

// if (m_graph.hasCell(*Init)) {
// // @g1 = ...*
// // @g2 = ...** @g1
// seadsa::Cell &nc = m_graph.mkCell(*Init, seadsa::Cell());
// // connect c with nc
// c.growSize(0, Init->getType());
// c.addAccessedType(0, Init->getType());
// c.addLink(seadsa::Field(0, seadsa::FieldType(Init->getType())), nc);
// return;
// }
}
}

Expand Down Expand Up @@ -458,8 +464,7 @@ class IntraBlockBuilder : public InstVisitor<IntraBlockBuilder>,
void visitIntToPtrInst(IntToPtrInst &I);
void visitPtrToIntInst(PtrToIntInst &I);
void visitBitCastInst(BitCastInst &I);
void visitCmpInst(CmpInst &I) { /* do nothing */
}
void visitCmpInst(CmpInst &I) { /* do nothing */ }
void visitInsertValueInst(InsertValueInst &I);
void visitExtractValueInst(ExtractValueInst &I);
void visitShuffleVectorInst(ShuffleVectorInst &I);
Expand All @@ -479,7 +484,6 @@ class IntraBlockBuilder : public InstVisitor<IntraBlockBuilder>,
void visitAllocWrapperCall(CallBase &I);
void visitAllocationFnCall(CallBase &I);


SeadsaFn getSeaDsaFn(const Function *fn) {
if (!fn) return SeadsaFn::UNKNOWN;

Expand Down Expand Up @@ -786,10 +790,6 @@ void IntraBlockBuilder::visitAtomicRMWInst(AtomicRMWInst &I) {
}
}

static bool isBytePtrTy(const Type *ty) {
return ty->isPointerTy() && ty->getPointerElementType()->isIntegerTy(8);
}

void IntraBlockBuilder::visitStoreInst(StoreInst &SI) {
using namespace seadsa;

Expand Down Expand Up @@ -837,14 +837,10 @@ void IntraBlockBuilder::visitStoreInst(StoreInst &SI) {
Cell dest(val.getNode(), val.getRawOffset());

// -- guess best type for the store. Use the type of the value being
// -- stored, unless it is i8*, in which case check if the store location
// -- has a better type
// -- stored
// Since LLVM 15, a loss of precision is incurred compared to past version for when omnichar pointers are being stored
Type *ty = ValOp->getType();
if (isBytePtrTy(ty)) {
Type *opTy = SI.getPointerOperand()->stripPointerCasts()->getType();
if (opTy->isPointerTy() && opTy->getPointerElementType()->isPointerTy())
ty = opTy->getPointerElementType();
}

base.addLink(Field(0, FieldType(ty)), dest);
}

Expand Down Expand Up @@ -877,21 +873,20 @@ template <typename T> T gcd(T a, T b) {
The first element of the pair is the fixed offset. The second is
a gcd of the variable offset.
*/
std::pair<int64_t, uint64_t> computeGepOffset(Type *ptrTy,
std::pair<int64_t, uint64_t> computeGepOffset(Type *srcElementTy,
ArrayRef<Value *> Indicies,
const DataLayout &dl) {
Type *Ty = ptrTy;
assert(Ty->isPointerTy());

Type *Ty = srcElementTy;

// numeric offset
int64_t noffset = 0;

// divisor
uint64_t divisor = 0;

Type *srcElemTy = cast<PointerType>(ptrTy)->getElementType();
generic_gep_type_iterator<Value *const *> TI =
gep_type_begin(srcElemTy, Indicies);
gep_type_begin(srcElementTy, Indicies);

for (unsigned CurIDX = 0, EndIDX = Indicies.size(); CurIDX != EndIDX;
++CurIDX, ++TI) {
Expand All @@ -900,9 +895,8 @@ std::pair<int64_t, uint64_t> computeGepOffset(Type *ptrTy,
noffset += dl.getStructLayout(STy)->getElementOffset(fieldNo);
Ty = STy->getElementType(fieldNo);
} else {
if (PointerType *ptrTy = dyn_cast<PointerType>(Ty))
Ty = ptrTy->getElementType();
else if (Ty->isArrayTy())
// We do nothing to pointer type now
if (Ty->isArrayTy())
Ty = Ty->getArrayElementType();
else if (auto vt = dyn_cast<VectorType>(Ty))
Ty = vt->getElementType();
Expand Down Expand Up @@ -939,13 +933,11 @@ uint64_t computeIndexedOffset(Type *ty, ArrayRef<unsigned> indecies,
offset += layout->getElementOffset(idx);
ty = sty->getElementType(idx);
} else {
if (PointerType *ptrTy = dyn_cast<PointerType>(ty))
ty = ptrTy->getElementType();
else if (ty->isArrayTy())
if (ty->isArrayTy())
ty = ty->getArrayElementType();
else if (auto vt = dyn_cast<VectorType>(ty))
ty = vt->getElementType();
assert(ty && "Type is neither PointerType nor SequentialType");
assert(ty && "Type being indexed is not a SequentialType");
offset += idx * dl.getTypeAllocSize(ty);
}
}
Expand Down Expand Up @@ -1006,7 +998,21 @@ void BlockBuilderBase::visitGep(const Value &gep, const Value &ptr,
return;
}

auto off = computeGepOffset(ptr.getType(), indicies, m_dl);
Type *srcElementType;

// We require a cast to GEPOperator first, since we can only acquire the
// source element type through GEPOperator.
if (auto *g = dyn_cast<GEPOperator>(&gep)) {
srcElementType = g->getSourceElementType();
} else {
errs() << "Attempted to cast following value into a GEP instruction: ";
gep.print(llvm::errs());
errs() << "\n";
assert(false && "Not a GEP instruction");
return;
}

auto off = computeGepOffset(srcElementType, indicies, m_dl);
if (off.first < 0) {
if (base.getOffset() + off.first >= 0) {
m_graph.mkCell(gep,
Expand Down Expand Up @@ -1463,7 +1469,6 @@ void IntraBlockBuilder::visitCallBase(CallBase &I) {
// a function that does not return a pointer is a noop
if (!I.getType()->isPointerTy()) return;


// -- something unexpected. Keep an assert so that we know that something
// -- unexpected happened.

Expand Down Expand Up @@ -1510,50 +1515,55 @@ bool hasNoPointerTy(const llvm::Type *t) {
}

bool transfersNoPointers(MemTransferInst &MI, const DataLayout &DL) {
Value *srcPtr = MI.getSource();
auto *srcTy = srcPtr->getType()->getPointerElementType();
// FIXME: LLVM 15, Kevin: Since we can no longer access pointee types, it is
// now
// impossible to determine whether the pointee's struct type contains
// pointers. This whole function is effectively hamstrung as it now only
// returns false.

ConstantInt *rawLength = dyn_cast<ConstantInt>(MI.getLength());
if (!rawLength) return false;
if (!rawLength)
return false; // Analysis is not possible if length is not constant

const uint64_t length = rawLength->getZExtValue();
LOG("dsa", errs() << "MemTransfer length:\t" << length << "\n");

// opaque structs may transfer pointers
if (!srcTy->isSized()) return false;

// TODO: Go up to the GEP chain to find nearest fitting type to transfer.
// This can occur when someone tries to transfer int the middle of a struct.
if (length * 8 > DL.getTypeSizeInBits(srcTy)) {
LOG("dsa-warn", errs() << "WARNING: MemTransfer past object size!\n"
<< "\tTransfer: ");
LOG("dsa", MI.print(errs()));
LOG("dsa-warn", errs() << "\n\tLength: " << length << "\n\tType size: "
<< (DL.getTypeSizeInBits(srcTy) / 8) << "\n");
return false;
}

static SmallDenseMap<std::pair<Type *, unsigned>, bool, 16>
knownNoPointersInStructs;

if (knownNoPointersInStructs.count({srcTy, length}) != 0)
return knownNoPointersInStructs[{srcTy, length}];

for (auto &subTy : seadsa::AggregateIterator::range(srcTy, &DL)) {
if (subTy.Offset >= length) break;

if (subTy.Ty->isPointerTy()) {
LOG("dsa", errs() << "Found ptr member "; subTy.Ty->print(errs());
errs() << "\n\tin "; srcTy->print(errs());
errs() << "\n\tMemTransfer transfers pointers!\n");

knownNoPointersInStructs[{srcTy, length}] = false;
return false;
}
}

knownNoPointersInStructs[{srcTy, length}] = true;
return true;
// // opaque structs may transfer pointers
// if (!srcTy->isSized()) return false;

// // TODO: Go up to the GEP chain to find nearest fitting type to transfer.
// // This can occur when someone tries to transfer int the middle of a struct.
// if (length * 8 > DL.getTypeSizeInBits(srcTy)) {
// LOG("dsa-warn", errs() << "WARNING: MemTransfer past object size!\n"
// << "\tTransfer: ");
// LOG("dsa", MI.print(errs()));
// LOG("dsa-warn", errs() << "\n\tLength: " << length << "\n\tType size: "
// << (DL.getTypeSizeInBits(srcTy) / 8) << "\n");
// return false;
// }

// static SmallDenseMap<std::pair<Type *, unsigned>, bool, 16>
// knownNoPointersInStructs;

// if (knownNoPointersInStructs.count({srcTy, length}) != 0)
// return knownNoPointersInStructs[{srcTy, length}];

// for (auto &subTy : seadsa::AggregateIterator::range(srcTy, &DL)) {
// if (subTy.Offset >= length) break;

// if (subTy.Ty->isPointerTy()) {
// LOG("dsa", errs() << "Found ptr member "; subTy.Ty->print(errs());
// errs() << "\n\tin "; srcTy->print(errs());
// errs() << "\n\tMemTransfer transfers pointers!\n");

// knownNoPointersInStructs[{srcTy, length}] = false;
// return false;
// }
// }

// knownNoPointersInStructs[{srcTy, length}] = true;
// return true;
return false;
}

void IntraBlockBuilder::visitMemTransferInst(MemTransferInst &I) {
Expand Down Expand Up @@ -1589,9 +1599,9 @@ void IntraBlockBuilder::visitMemTransferInst(MemTransferInst &I) {
seadsa::Cell destCell = m_graph.mkCell(*I.getDest(), seadsa::Cell());

if (TrustTypes &&
((sourceCell.getNode()->links().size() == 0 &&
hasNoPointerTy(I.getSource()->getType()->getPointerElementType())) ||
transfersNoPointers(I, m_dl))) {
// FIXME: LLVM 15, Kevin: The removal of the pointer type means we can no longer avoid unification upon a memory
// operation by looking at its type.
(transfersNoPointers(I, m_dl))) {
/* do nothing */
// no pointers are copied from source to dest, so there is no
// need to unify them
Expand Down
Loading