Skip to content
Closed
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
5 changes: 5 additions & 0 deletions llvm/include/llvm/Cheerp/PointerAnalyzer.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@

#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/DenseSet.h"
#include "llvm/IR/Instructions.h"
#include "llvm/IR/Value.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/Constants.h"
Expand Down Expand Up @@ -281,13 +282,17 @@ class PointerAnalyzer
POINTER_KIND getPointerKindForStoredType( llvm::Type * pointerType ) const;
POINTER_KIND getPointerKindForMemberPointer( const TypeAndIndex& baseAndIndex ) const;
POINTER_KIND getPointerKindForMember( const TypeAndIndex& baseAndIndex ) const;
POINTER_KIND getPointerKindForLoad(const llvm::LoadInst* v) const;
POINTER_KIND getPointerKindForStore(const llvm::StoreInst* v) const;
POINTER_KIND getPointerKindForArgumentTypeAndIndex( const TypeAndIndex& argTypeAndIndex ) const;
POINTER_KIND getPointerKindForArgument( const llvm::Argument* A ) const;
POINTER_KIND getPointerKindForJSExportedType (llvm::Type* pointerType) const;
const PointerKindWrapper& getFinalPointerKindWrapper(const llvm::Value* v ) const;
static TypeAndIndex getBaseStructAndIndexFromGEP( const llvm::Value* v );
const llvm::ConstantInt* getConstantOffsetForPointer( const llvm::Value* ) const;
const llvm::ConstantInt* getConstantOffsetForMember( const TypeAndIndex& baseAndIndex ) const;
const llvm::ConstantInt* getConstantOffsetForLoad(const llvm::LoadInst* v) const;
const llvm::ConstantInt* getConstantOffsetForStore(const llvm::StoreInst* v) const;

/**
* Functions to manually invalidate the cache
Expand Down
1 change: 1 addition & 0 deletions llvm/include/llvm/Cheerp/Writer.h
Original file line number Diff line number Diff line change
Expand Up @@ -493,6 +493,7 @@ class CheerpWriter final : public CheerpBaseWriter
COMPILE_INSTRUCTION_FEEDBACK compileNotInlineableInstruction(const llvm::Instruction& I, PARENT_PRIORITY parentPrio);
COMPILE_INSTRUCTION_FEEDBACK compileInlineableInstruction(const llvm::Instruction& I, PARENT_PRIORITY parentPrio);
COMPILE_INSTRUCTION_FEEDBACK compileCallInstruction(const llvm::CallBase& I, PARENT_PRIORITY parentPrio);
void compileElem(const llvm::Value* ptrOp, llvm::Type* Ty, llvm::StructType* STy, POINTER_KIND valKind, POINTER_KIND ptrKind, POINTER_KIND memKind, bool isOffset, uint32_t structElemIdx);
void compileLoadElem(const llvm::LoadInst& li, llvm::Type* Ty, llvm::StructType* STy, POINTER_KIND ptrKind, POINTER_KIND loadKind, bool isOffset, Registerize::REGISTER_KIND regKind, uint32_t structElemIdx, bool asmjs, PARENT_PRIORITY parentPrio);
void compileLoad(const llvm::LoadInst& li, PARENT_PRIORITY parentPrio);
void compileStoreElem(const llvm::StoreInst& si, llvm::Type* Ty, llvm::StructType* STy, POINTER_KIND ptrKind, POINTER_KIND storedKind, bool isOffset, Registerize::REGISTER_KIND regKind, uint32_t structElemIdx, uint32_t elemIdx, bool asmjs);
Expand Down
20 changes: 20 additions & 0 deletions llvm/lib/CheerpUtils/PointerAnalyzer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1723,6 +1723,16 @@ POINTER_KIND PointerAnalyzer::getPointerKindForMember(const TypeAndIndex& baseAn
return getPointerKindForMemberImpl(baseAndIndex, PACache);
}

POINTER_KIND PointerAnalyzer::getPointerKindForLoad(const llvm::LoadInst* v) const
{
return getPointerKind(v);
}

POINTER_KIND PointerAnalyzer::getPointerKindForStore(const llvm::StoreInst* v) const
{
return getPointerKind(v);
Comment thread
DutChen18 marked this conversation as resolved.
}

TypeAndIndex PointerAnalyzer::getBaseStructAndIndexFromGEP(const Value* p)
{
if(!isGEP(p))
Expand Down Expand Up @@ -1826,6 +1836,16 @@ const llvm::ConstantInt* PointerAnalyzer::getConstantOffsetForMember( const Type
return ret.getPointerOffset();
}

const llvm::ConstantInt* PointerAnalyzer::getConstantOffsetForLoad(const llvm::LoadInst* v) const
{
return getConstantOffsetForPointer(v);
}

const llvm::ConstantInt* PointerAnalyzer::getConstantOffsetForStore(const llvm::StoreInst* v) const
{
return getConstantOffsetForPointer(v);
}

void PointerAnalyzer::invalidate(const Value * v)
{
assert(status == MODIFIABLE);
Expand Down
4 changes: 4 additions & 0 deletions llvm/lib/CheerpUtils/Utility.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1478,6 +1478,10 @@ bool InstElemIterator::isTwoElems(const llvm::Instruction* I, llvm::Type* Ty, in
{
if(!Ty->isStructTy())
{
// avoid calling getPointerKind for store instruction
if (const StoreInst* SI = dyn_cast<StoreInst>(I))
return Ty->isPointerTy() && PA.getPointerKindForStore(SI) == SPLIT_REGULAR && !PA.getConstantOffsetForStore(SI);

return Ty->isPointerTy() && PA.getPointerKind(I) == SPLIT_REGULAR && !PA.getConstantOffsetForPointer(I);
}
auto* STy = llvm::cast<llvm::StructType>(Ty);
Expand Down
112 changes: 51 additions & 61 deletions llvm/lib/CheerpWriter/CheerpWriter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4531,29 +4531,9 @@ CheerpWriter::COMPILE_INSTRUCTION_FEEDBACK CheerpWriter::compileInlineableInstru

void CheerpWriter::compileLoad(const LoadInst& li, PARENT_PRIORITY parentPrio)
{
auto* Ty = li.getType();
const Value* ptrOp = li.getPointerOperand();
bool asmjs = currentFun->getSection()==StringRef("asmjs");
POINTER_KIND ptrKind = PA.getPointerKind(ptrOp);
bool needsCheckBounds = false;
if (checkBounds)
{
if(ptrKind == REGULAR || ptrKind == SPLIT_REGULAR)
{
needsCheckBounds = true;
stream<<"(";
compileCheckBounds(ptrOp);
stream<<",";
}
else if(ptrKind == COMPLETE_OBJECT && isGEP(ptrOp))
{
needsCheckBounds = true;
bool needsOffset = !li.use_empty() && Ty->isPointerTy() && PA.getPointerKindAssert(&li) == SPLIT_REGULAR && !PA.getConstantOffsetForPointer(&li);
stream<<"(";
compileCheckMemberExists(ptrOp, needsOffset);
stream<<",";
}
}
for(const auto& ie: getInstElems(&li, PA))
{
if(ie.totalIdx != 0)
Expand All @@ -4577,15 +4557,10 @@ void CheerpWriter::compileLoad(const LoadInst& li, PARENT_PRIORITY parentPrio)
}
else if(Ty->isPointerTy())
{
elemPtrKind = PA.getPointerKind(&li);
elemPtrKind = PA.getPointerKindForLoad(&li);
}
bool isOffset = ie.ptrIdx == 1;
compileLoadElem(li, Ty, STy, ptrKind, elemPtrKind, isOffset, elemRegKind, ie.structIdx, asmjs, parentPrio);
if(needsCheckBounds)
{
needsCheckBounds = false;
stream << ')';
}
}
}

Expand Down Expand Up @@ -4726,13 +4701,18 @@ void CheerpWriter::compileLoadElem(const LoadInst& li, Type* Ty, StructType* STy
}
else
{
compileCompleteObject(ptrOp);
if(STy)
POINTER_KIND valKind = li.getType()->isPointerTy() ? PA.getPointerKind(&li) : COMPLETE_OBJECT;

if (valKind == COMPLETE_OBJECT && (loadKind == REGULAR || loadKind == SPLIT_REGULAR))
{
compileAccessToElement(STy, {ConstantInt::get(IntegerType::get(Ty->getContext(), 32), structElemIdx)}, true);
assert(!isOffset);
compileElem(ptrOp, Ty, STy, COMPLETE_OBJECT, ptrKind, loadKind, false, structElemIdx);
stream << "[";
compileElem(ptrOp, Ty, STy, COMPLETE_OBJECT, ptrKind, loadKind, true, structElemIdx);
stream << "]";
}
if(isOffset)
stream << 'o';
else
compileElem(ptrOp, Ty, STy, valKind, ptrKind, loadKind, isOffset, structElemIdx);
}
if(regKind==Registerize::INTEGER && needsIntCoercion(parentPrio))
{
Expand All @@ -4755,20 +4735,6 @@ void CheerpWriter::compileStore(const StoreInst& si)
assert(ptrKind != CONSTANT);

auto* Ty = valOp->getType();
if (checkBounds)
{
if(ptrKind == REGULAR || ptrKind == SPLIT_REGULAR)
{
compileCheckBounds(ptrOp);
stream<<",";
}
else if(ptrKind == COMPLETE_OBJECT && isGEP(ptrOp))
{
bool needsOffset = Ty->isPointerTy() && PA.getPointerKindAssert(&si) == SPLIT_REGULAR && !PA.getConstantOffsetForPointer(&si);
compileCheckMemberExists(ptrOp, needsOffset);
stream<<",";
}
}
StructType* STy = dyn_cast<StructType>(Ty);
for(const auto& ie: getInstElems(&si, PA))
{
Expand All @@ -4789,7 +4755,7 @@ void CheerpWriter::compileStore(const StoreInst& si)
}
else if(Ty->isPointerTy())
{
elemPtrKind = PA.getPointerKind(&si);
elemPtrKind = PA.getPointerKindForStore(&si);
}
bool isOffset = ie.ptrIdx == 1;
compileStoreElem(si, Ty, STy, ptrKind, elemPtrKind, isOffset, elemRegKind, ie.totalIdx, ie.structIdx, asmjs);
Expand Down Expand Up @@ -4876,13 +4842,7 @@ void CheerpWriter::compileStoreElem(const StoreInst& si, Type* Ty, StructType* S
}
else
{
compileCompleteObject(ptrOp);
if(STy)
{
compileAccessToElement(STy, {ConstantInt::get(IntegerType::get(Ty->getContext(), 32), structElemIdx)}, true);
}
if(isOffset)
stream << 'o';
compileElem(ptrOp, Ty, STy, storedKind, ptrKind, storedKind, isOffset, structElemIdx);
}

stream << '=';
Expand All @@ -4895,7 +4855,7 @@ void CheerpWriter::compileStoreElem(const StoreInst& si, Type* Ty, StructType* S
if(Ty->isPointerTy())
{
assert(storedKind != CONSTANT);
bool hasConstantOffset = PA.getConstantOffsetForPointer(&si);
bool hasConstantOffset = PA.getConstantOffsetForStore(&si);
if(storedKind==SPLIT_REGULAR || ((storedKind == REGULAR || storedKind == BYTE_LAYOUT) && hasConstantOffset))
{
if(isOffset)
Expand Down Expand Up @@ -4932,6 +4892,27 @@ void CheerpWriter::compileStoreElem(const StoreInst& si, Type* Ty, StructType* S
}
}

void CheerpWriter::compileElem(const Value* ptrOp, llvm::Type* Ty, llvm::StructType* STy, POINTER_KIND valKind, POINTER_KIND ptrKind, POINTER_KIND memKind, bool isOffset, uint32_t structElemIdx)
{
if(checkBounds && (ptrKind == REGULAR || ptrKind == SPLIT_REGULAR))
compileCheckBounds(ptrOp);
else if(checkBounds && ptrKind == COMPLETE_OBJECT && isGEP(ptrOp))
compileCheckMemberExists(ptrOp, isOffset && memKind != REGULAR);
else
compileCompleteObject(ptrOp);

if(STy)
compileAccessToElement(STy, {ConstantInt::get(IntegerType::get(Ty->getContext(), 32), structElemIdx)}, true);

if(valKind != REGULAR && memKind != COMPLETE_OBJECT)
{
if(isOffset)
stream << (memKind == REGULAR ? ".o" : "o");
else
stream << (memKind == REGULAR ? ".d" : "");
}
}

void CheerpWriter::compileAtomicRMW(const AtomicRMWInst& ai, PARENT_PRIORITY parentPrio)
{
if (parentPrio > BIT_OR)
Expand Down Expand Up @@ -6252,7 +6233,7 @@ void CheerpWriter::compileBuiltins(bool asmjs)

void CheerpWriter::compileCheckBoundsHelper()
{
stream << "function checkBounds(arr,offs){if(offs>=arr.length || offs<0) throw new Error('OutOfBounds');}" << NewLine;
stream << "function checkBounds(arr,offs){if(offs>=arr.length || offs<0) throw new Error('OutOfBounds');return arr;}" << NewLine;
}

void CheerpWriter::compileCheckBounds(const Value* p)
Expand All @@ -6261,12 +6242,14 @@ void CheerpWriter::compileCheckBounds(const Value* p)
compilePointerBase(p);
stream<<",";
compilePointerOffset(p,LOWEST);
stream<<")";
stream<<")[";
compilePointerOffset(p,LOWEST);
stream<<"]";
}

void CheerpWriter::compileCheckMemberExistsHelper()
{
stream << "function checkMemberExists(obj, member){if(!(member in obj)) throw new Error('MemberDoesNotExist');}" << NewLine;
stream << "function checkMemberExists(obj, member){if(!(member in obj)) throw new Error('MemberDoesNotExist');return obj;}" << NewLine;
}

void CheerpWriter::compileCheckMemberExists(const Value* p, bool needsOffset)
Expand All @@ -6293,17 +6276,24 @@ void CheerpWriter::compileCheckMemberExists(const Value* p, bool needsOffset)
{
const APInt& index = cast<Constant>(lastOperand)->getUniqueInteger();
uint64_t idxVal = index.getLimitedValue();
char prefixChar = types.getPrefixCharForMember(PA, containerStructType, idxVal);

stream << "'";
stream << types.getPrefixCharForMember(PA, containerStructType, idxVal) << idxVal;
stream << prefixChar << idxVal;
if (needsOffset)
stream << "o";
stream << "'";
stream << "').";
stream << prefixChar << idxVal;
if(types.useWrapperArrayForMember(PA, containerStructType, idxVal))
stream << "[0]";
}
else if (dyn_cast<ArrayType>(basePointedType))
{
compileOperand(lastOperand, LOWEST);

stream << ")";
stream << ")[";
compileOperand(lastOperand, LOWEST);
stream << "]";
}
}

void CheerpWriter::compileCheckBoundsAsmJSHelper()
Expand Down
Loading