| @@ -0,0 +1,109 @@ | |||
| //===-- NaCl.h - NaCl Transformations ---------------------------*- C++ -*-===// | |||
| // | |||
| // The LLVM Compiler Infrastructure | |||
| // | |||
| // This file is distributed under the University of Illinois Open Source | |||
| // License. See LICENSE.TXT for details. | |||
| // | |||
| //===----------------------------------------------------------------------===// | |||
|
|
|||
| #ifndef LLVM_TRANSFORMS_NACL_H | |||
| #define LLVM_TRANSFORMS_NACL_H | |||
|
|
|||
| #include "llvm/CodeGen/Passes.h" | |||
| #include "llvm/IR/Instructions.h" | |||
| #include "llvm/IR/LLVMContext.h" | |||
|
|
|||
| namespace llvm { | |||
|
|
|||
| class BasicBlockPass; | |||
| class Function; | |||
| class FunctionPass; | |||
| class FunctionType; | |||
| class Instruction; | |||
| class ModulePass; | |||
| class Triple; | |||
| class Use; | |||
| class Value; | |||
|
|
|||
| BasicBlockPass *createConstantInsertExtractElementIndexPass(); | |||
| BasicBlockPass *createExpandGetElementPtrPass(); | |||
| BasicBlockPass *createExpandShuffleVectorPass(); | |||
| BasicBlockPass *createFixVectorLoadStoreAlignmentPass(); | |||
| BasicBlockPass *createPromoteI1OpsPass(); | |||
| BasicBlockPass *createSimplifyAllocasPass(); | |||
| FunctionPass *createBackendCanonicalizePass(); | |||
| FunctionPass *createExpandConstantExprPass(); | |||
| FunctionPass *createExpandLargeIntegersPass(); | |||
| FunctionPass *createExpandStructRegsPass(); | |||
| FunctionPass *createInsertDivideCheckPass(); | |||
| FunctionPass *createNormalizeAlignmentPass(); | |||
| FunctionPass *createRemoveAsmMemoryPass(); | |||
| FunctionPass *createResolvePNaClIntrinsicsPass(); | |||
| ModulePass *createAddPNaClExternalDeclsPass(); | |||
| ModulePass *createCanonicalizeMemIntrinsicsPass(); | |||
| ModulePass *createCleanupUsedGlobalsMetadataPass(); | |||
| ModulePass *createExpandArithWithOverflowPass(); | |||
| ModulePass *createExpandByValPass(); | |||
| ModulePass *createExpandCtorsPass(); | |||
| ModulePass *createExpandIndirectBrPass(); | |||
| ModulePass *createExpandSmallArgumentsPass(); | |||
| ModulePass *createExpandTlsConstantExprPass(); | |||
| ModulePass *createExpandTlsPass(); | |||
| ModulePass *createExpandVarArgsPass(); | |||
| ModulePass *createFlattenGlobalsPass(); | |||
| ModulePass *createGlobalCleanupPass(); | |||
| ModulePass *createGlobalizeConstantVectorsPass(); | |||
| ModulePass *createInternalizeUsedGlobalsPass(); | |||
| ModulePass *createPNaClSjLjEHPass(); | |||
| ModulePass *createPromoteIntegersPass(); | |||
| ModulePass *createReplacePtrsWithIntsPass(); | |||
| ModulePass *createResolveAliasesPass(); | |||
| ModulePass *createRewriteAtomicsPass(); | |||
| ModulePass *createRewriteLLVMIntrinsicsPass(); | |||
| ModulePass *createRewritePNaClLibraryCallsPass(); | |||
| ModulePass *createSimplifyStructRegSignaturesPass(); | |||
| ModulePass *createStripAttributesPass(); | |||
| ModulePass *createStripMetadataPass(); | |||
| ModulePass *createStripModuleFlagsPass(); | |||
| ModulePass *createStripDanglingDISubprogramsPass(); | |||
|
|
|||
| // Emscripten passes: | |||
| FunctionPass *createExpandInsertExtractElementPass(); | |||
| ModulePass *createExpandI64Pass(); | |||
| ModulePass *createLowerEmAsyncifyPass(); | |||
| ModulePass *createLowerEmExceptionsPass(); | |||
| ModulePass *createLowerEmSetjmpPass(); | |||
| ModulePass *createNoExitRuntimePass(); | |||
| // Emscripten passes end. | |||
|
|
|||
| //void PNaClABISimplifyAddPreOptPasses(Triple *T, PassManagerBase &PM); | |||
| //void PNaClABISimplifyAddPostOptPasses(Triple *T, PassManagerBase &PM); | |||
|
|
|||
| Instruction *PhiSafeInsertPt(Use *U); | |||
| void PhiSafeReplaceUses(Use *U, Value *NewVal); | |||
|
|
|||
| // Copy debug information from Original to New, and return New. | |||
| template <typename T> T *CopyDebug(T *New, Instruction *Original) { | |||
| New->setDebugLoc(Original->getDebugLoc()); | |||
| return New; | |||
| } | |||
|
|
|||
| template <class InstType> | |||
| static void CopyLoadOrStoreAttrs(InstType *Dest, InstType *Src) { | |||
| Dest->setVolatile(Src->isVolatile()); | |||
| Dest->setAlignment(Src->getAlignment()); | |||
| Dest->setOrdering(Src->getOrdering()); | |||
| Dest->setSynchScope(Src->getSynchScope()); | |||
| } | |||
|
|
|||
| // In order to change a function's type, the function must be | |||
| // recreated. RecreateFunction() recreates Func with type NewType. | |||
| // It copies or moves across everything except the argument values, | |||
| // which the caller must update because the argument types might be | |||
| // different. | |||
| Function *RecreateFunction(Function *Func, FunctionType *NewType); | |||
|
|
|||
| } | |||
|
|
|||
| #endif | |||
| @@ -0,0 +1,76 @@ | |||
| //=== llvm/IR/NaClAtomicIntrinsics.cpp - NaCl Atomic Intrinsics -*- C++ -*-===// | |||
| // | |||
| // The LLVM Compiler Infrastructure | |||
| // | |||
| // This file is distributed under the University of Illinois Open Source | |||
| // License. See LICENSE.TXT for details. | |||
| // | |||
| //===----------------------------------------------------------------------===// | |||
| // | |||
| // This file describes atomic intrinsic functions that are specific to NaCl. | |||
| // | |||
| //===----------------------------------------------------------------------===// | |||
|
|
|||
| #include "llvm/IR/DerivedTypes.h" | |||
| #include "llvm/IR/NaClAtomicIntrinsics.h" | |||
| #include "llvm/IR/Type.h" | |||
|
|
|||
| namespace llvm { | |||
|
|
|||
| namespace NaCl { | |||
|
|
|||
| AtomicIntrinsics::AtomicIntrinsics(LLVMContext &C) { | |||
| Type *IT[NumAtomicIntrinsicOverloadTypes] = { Type::getInt8Ty(C), | |||
| Type::getInt16Ty(C), | |||
| Type::getInt32Ty(C), | |||
| Type::getInt64Ty(C) }; | |||
| size_t CurIntrin = 0; | |||
|
|
|||
| // Initialize each of the atomic intrinsics and their overloads. They | |||
| // have up to 5 parameters, the following macro will take care of | |||
| // overloading. | |||
| #define INIT(P0, P1, P2, P3, P4, INTRIN) \ | |||
| do { \ | |||
| for (size_t CurType = 0; CurType != NumAtomicIntrinsicOverloadTypes; \ | |||
| ++CurType) { \ | |||
| size_t Param = 0; \ | |||
| I[CurIntrin][CurType].OverloadedType = IT[CurType]; \ | |||
| I[CurIntrin][CurType].ID = Intrinsic::nacl_atomic_##INTRIN; \ | |||
| I[CurIntrin][CurType].Overloaded = \ | |||
| P0 == Int || P0 == Ptr || P1 == Int || P1 == Ptr || P2 == Int || \ | |||
| P2 == Ptr || P3 == Int || P3 == Ptr || P4 == Int || P4 == Ptr; \ | |||
| I[CurIntrin][CurType].NumParams = \ | |||
| (P0 != NoP) + (P1 != NoP) + (P2 != NoP) + (P3 != NoP) + (P4 != NoP); \ | |||
| I[CurIntrin][CurType].ParamType[Param++] = P0; \ | |||
| I[CurIntrin][CurType].ParamType[Param++] = P1; \ | |||
| I[CurIntrin][CurType].ParamType[Param++] = P2; \ | |||
| I[CurIntrin][CurType].ParamType[Param++] = P3; \ | |||
| I[CurIntrin][CurType].ParamType[Param++] = P4; \ | |||
| } \ | |||
| ++CurIntrin; \ | |||
| } while (0) | |||
|
|
|||
| INIT(Ptr, Mem, NoP, NoP, NoP, load); | |||
| INIT(Ptr, Int, Mem, NoP, NoP, store); | |||
| INIT(RMW, Ptr, Int, Mem, NoP, rmw); | |||
| INIT(Ptr, Int, Int, Mem, Mem, cmpxchg); | |||
| INIT(Mem, NoP, NoP, NoP, NoP, fence); | |||
| INIT(NoP, NoP, NoP, NoP, NoP, fence_all); | |||
| } | |||
|
|
|||
| AtomicIntrinsics::View AtomicIntrinsics::allIntrinsicsAndOverloads() const { | |||
| return View(&I[0][0], NumAtomicIntrinsics * NumAtomicIntrinsicOverloadTypes); | |||
| } | |||
|
|
|||
| const AtomicIntrinsics::AtomicIntrinsic * | |||
| AtomicIntrinsics::find(Intrinsic::ID ID, Type *OverloadedType) const { | |||
| View R = allIntrinsicsAndOverloads(); | |||
| for (const AtomicIntrinsic *AI = R.begin(), *E = R.end(); AI != E; ++AI) | |||
| if (AI->ID == ID && AI->OverloadedType == OverloadedType) | |||
| return AI; | |||
| return 0; | |||
| } | |||
|
|
|||
| } // End NaCl namespace | |||
|
|
|||
| } // End llvm namespace | |||
| @@ -0,0 +1,182 @@ | |||
| //===-- AllocaManager.h ---------------------------------------------------===// | |||
| // | |||
| // The LLVM Compiler Infrastructure | |||
| // | |||
| // This file is distributed under the University of Illinois Open Source | |||
| // License. See LICENSE.TXT for details. | |||
| // | |||
| //===----------------------------------------------------------------------===// | |||
| // | |||
| // This pass declares the AllocaManager class. | |||
| // | |||
| //===----------------------------------------------------------------------===// | |||
|
|
|||
| #ifndef JSBACKEND_ALLOCAMANAGER_H | |||
| #define JSBACKEND_ALLOCAMANAGER_H | |||
|
|
|||
| #include "llvm/ADT/BitVector.h" | |||
| #include "llvm/ADT/DenseMap.h" | |||
| #include "llvm/ADT/SmallVector.h" | |||
| #include "llvm/ADT/SetVector.h" | |||
|
|
|||
| namespace llvm { | |||
|
|
|||
| class AllocaInst; | |||
| class BasicBlock; | |||
| class CallInst; | |||
| class DataLayout; | |||
| class Function; | |||
| class Value; | |||
|
|
|||
| /// Compute frame layout for allocas. | |||
| class AllocaManager { | |||
| const DataLayout *DL; | |||
| const Function *LifetimeStart; | |||
| const Function *LifetimeEnd; | |||
| const Function *F; | |||
|
|
|||
| // Per-block lifetime information. | |||
| struct BlockLifetimeInfo { | |||
| BitVector Start; | |||
| BitVector End; | |||
| BitVector LiveIn; | |||
| BitVector LiveOut; | |||
| }; | |||
| typedef DenseMap<const BasicBlock *, BlockLifetimeInfo> LivenessMap; | |||
| LivenessMap BlockLiveness; | |||
|
|
|||
| // Worklist for inter-block liveness analysis. | |||
| typedef SmallSetVector<const BasicBlock *, 8> InterBlockWorklistVec; | |||
| InterBlockWorklistVec InterBlockTopDownWorklist; | |||
| InterBlockWorklistVec InterBlockBottomUpWorklist; | |||
|
|
|||
| // Map allocas to their index in AllocasByIndex. | |||
| typedef DenseMap<const AllocaInst *, size_t> AllocaMap; | |||
| AllocaMap Allocas; | |||
|
|
|||
| // Information about an alloca. Note that the size and alignment may vary | |||
| // from what's in the actual AllocaInst when an alloca is also representing | |||
| // another with perhaps greater size and/or alignment needs. | |||
| // | |||
| // When an alloca is represented by another, its AllocaInfo is marked as | |||
| // "forwarded", at which point it no longer holds a size and alignment, but | |||
| // the index of the representative AllocaInfo. | |||
| class AllocaInfo { | |||
| const AllocaInst *Inst; | |||
| uint64_t Size; | |||
| unsigned Alignment; | |||
| unsigned Index; | |||
|
|
|||
| public: | |||
| AllocaInfo(const AllocaInst *I, uint64_t S, unsigned A, unsigned X) | |||
| : Inst(I), Size(S), Alignment(A), Index(X) { | |||
| assert(I != NULL); | |||
| assert(A != 0); | |||
| assert(!isForwarded()); | |||
| } | |||
|
|
|||
| bool isForwarded() const { return Alignment == 0; } | |||
|
|
|||
| size_t getForwardedID() const { | |||
| assert(isForwarded()); | |||
| return static_cast<size_t>(Size); | |||
| } | |||
|
|
|||
| void forward(size_t i) { | |||
| assert(!isForwarded()); | |||
| Alignment = 0; | |||
| Size = i; | |||
| assert(isForwarded()); | |||
| assert(getForwardedID() == i); | |||
| } | |||
|
|
|||
| const AllocaInst *getInst() const { return Inst; } | |||
|
|
|||
| uint64_t getSize() const { assert(!isForwarded()); return Size; } | |||
| unsigned getAlignment() const { assert(!isForwarded()); return Alignment; } | |||
| unsigned getIndex() const { return Index; } | |||
|
|
|||
| void mergeSize(uint64_t S) { | |||
| assert(!isForwarded()); | |||
| Size = std::max(Size, S); | |||
| assert(!isForwarded()); | |||
| } | |||
| void mergeAlignment(unsigned A) { | |||
| assert(A != 0); | |||
| assert(!isForwarded()); | |||
| Alignment = std::max(Alignment, A); | |||
| assert(!isForwarded()); | |||
| } | |||
| }; | |||
| typedef SmallVector<AllocaInfo, 32> AllocaVec; | |||
| AllocaVec AllocasByIndex; | |||
|
|
|||
| // For each alloca, which allocas can it safely represent? Allocas are | |||
| // identified by AllocasByIndex index. | |||
| // TODO: Vector-of-vectors isn't the fastest data structure possible here. | |||
| typedef SmallVector<BitVector, 32> AllocaCompatibilityVec; | |||
| AllocaCompatibilityVec AllocaCompatibility; | |||
|
|
|||
| // This is for allocas that will eventually be sorted. | |||
| SmallVector<AllocaInfo, 32> SortedAllocas; | |||
|
|
|||
| // Static allocation results. | |||
| struct StaticAllocation { | |||
| const AllocaInst *Representative; | |||
| uint64_t Offset; | |||
| StaticAllocation() {} | |||
| StaticAllocation(const AllocaInst *A, uint64_t O) | |||
| : Representative(A), Offset(O) {} | |||
| }; | |||
| typedef DenseMap<const AllocaInst *, StaticAllocation> StaticAllocaMap; | |||
| StaticAllocaMap StaticAllocas; | |||
| uint64_t FrameSize; | |||
|
|
|||
| uint64_t getSize(const AllocaInst *AI); | |||
| unsigned getAlignment(const AllocaInst *AI); | |||
| AllocaInfo getInfo(const AllocaInst *AI, unsigned Index); | |||
| const Value *getPointerFromIntrinsic(const CallInst *CI); | |||
| const AllocaInst *isFavorableAlloca(const Value *V); | |||
| static int AllocaSort(const AllocaInfo *l, const AllocaInfo *r); | |||
|
|
|||
| void collectMarkedAllocas(); | |||
| void collectBlocks(); | |||
| void computeInterBlockLiveness(); | |||
| void computeIntraBlockLiveness(); | |||
| void computeRepresentatives(); | |||
| void computeFrameOffsets(); | |||
|
|
|||
| unsigned MaxAlignment; | |||
|
|
|||
| public: | |||
| AllocaManager(); | |||
|
|
|||
| /// Analyze the given function and prepare for getRepresentative queries. | |||
| void analyze(const Function &Func, const DataLayout &Layout, | |||
| bool PerformColoring); | |||
|
|
|||
| /// Reset all stored state. | |||
| void clear(); | |||
|
|
|||
| /// Return the representative alloca for the given alloca. When allocas are | |||
| /// merged, one is chosen as the representative to stand for the rest. | |||
| /// References to the alloca should take the form of references to the | |||
| /// representative. | |||
| const AllocaInst *getRepresentative(const AllocaInst *AI) const; | |||
|
|
|||
| /// Set *offset to the frame offset for the given alloca. Return true if the | |||
| /// given alloca is representative, meaning that it needs an explicit | |||
| /// definition in the function entry. Return false if some other alloca | |||
| /// represents this one. | |||
| bool getFrameOffset(const AllocaInst *AI, uint64_t *offset) const; | |||
|
|
|||
| /// Return the total frame size for all static allocas and associated padding. | |||
| uint64_t getFrameSize() const { return FrameSize; } | |||
|
|
|||
| /// Return the largest alignment seen. | |||
| unsigned getMaxAlignment() const { return MaxAlignment; } | |||
| }; | |||
|
|
|||
| } // namespace llvm | |||
|
|
|||
| #endif | |||
| @@ -0,0 +1,16 @@ | |||
| add_llvm_target(JSBackendCodeGen | |||
| AllocaManager.cpp | |||
| ExpandBigSwitches.cpp | |||
| JSBackend.cpp | |||
| JSTargetMachine.cpp | |||
| JSTargetTransformInfo.cpp | |||
| Relooper.cpp | |||
| RemoveLLVMAssume.cpp | |||
| SimplifyAllocas.cpp | |||
| ) | |||
|
|
|||
| add_dependencies(LLVMJSBackendCodeGen intrinsics_gen) | |||
|
|
|||
| add_subdirectory(TargetInfo) | |||
| add_subdirectory(MCTargetDesc) | |||
| add_subdirectory(NaCl) | |||
| @@ -0,0 +1,157 @@ | |||
| //===-- ExpandBigSwitches.cpp - Alloca optimization ---------------*- C++ -*-===// | |||
| // | |||
| // The LLVM Compiler Infrastructure | |||
| // | |||
| // This file is distributed under the University of Illinois Open Source | |||
| // License. See LICENSE.TXT for details. | |||
| // | |||
| //===-----------------------------------------------------------------------===// | |||
| // | |||
| // Very large switches can be a problem for JS engines. We split them up here. | |||
| // | |||
| //===-----------------------------------------------------------------------===// | |||
|
|
|||
| #include "OptPasses.h" | |||
|
|
|||
| #include "llvm/IR/Instruction.h" | |||
| #include "llvm/IR/Instructions.h" | |||
| #include "llvm/IR/Function.h" | |||
| #include "llvm/IR/Constants.h" | |||
| #include "llvm/Support/raw_ostream.h" | |||
|
|
|||
| #include <vector> | |||
| #include <algorithm> | |||
|
|
|||
| namespace llvm { | |||
|
|
|||
| struct ExpandBigSwitches : public FunctionPass { | |||
| static char ID; // Pass identification, replacement for typeid | |||
| ExpandBigSwitches() : FunctionPass(ID) {} | |||
| // XXX initialize..(*PassRegistry::getPassRegistry()); } | |||
|
|
|||
| bool runOnFunction(Function &Func) override; | |||
|
|
|||
| StringRef getPassName() const override { return "ExpandBigSwitches"; } | |||
| }; | |||
|
|
|||
| char ExpandBigSwitches::ID = 0; | |||
|
|
|||
| // Check if we need to split a switch. If so, return the median, on which we will do so | |||
| static bool ConsiderSplit(const SwitchInst *SI, int64_t& Median) { | |||
| int64_t Minn = INT64_MAX, Maxx = INT64_MIN; | |||
| std::vector<int64_t> Values; | |||
| for (SwitchInst::ConstCaseIt i = SI->case_begin(), e = SI->case_end(); i != e; ++i) { | |||
| int64_t Curr = i.getCaseValue()->getSExtValue(); | |||
| if (Curr < Minn) Minn = Curr; | |||
| if (Curr > Maxx) Maxx = Curr; | |||
| Values.push_back(Curr); | |||
| } | |||
| int64_t Range = Maxx - Minn; | |||
| int Num = SI->getNumCases(); | |||
| if (Num < 1024 && Range <= 10*1024 && (Range/Num) <= 1024) return false; | |||
| // this is either too big, or too rangey | |||
| std::sort(Values.begin(), Values.end()); | |||
| Median = Values[Values.size()/2]; | |||
| return true; | |||
| } | |||
|
|
|||
| static void DoSplit(SwitchInst *SI, int64_t Median) { | |||
| // switch (x) { ..very many.. } | |||
| // | |||
| // ==> | |||
| // | |||
| // if (x < median) { | |||
| // switch (x) { ..first half.. } | |||
| // } else { | |||
| // switch (x) { ..second half.. } | |||
| // } | |||
|
|
|||
| BasicBlock *SwitchBB = SI->getParent(); | |||
| Function *F = SwitchBB->getParent(); | |||
| Value *Condition = SI->getOperand(0); | |||
| BasicBlock *DD = SI->getDefaultDest(); | |||
| unsigned NumItems = SI->getNumCases(); | |||
| Type *T = Condition->getType(); | |||
|
|
|||
| Instruction *Check = new ICmpInst(SI, ICmpInst::ICMP_SLT, Condition, ConstantInt::get(T, Median), "switch-split"); | |||
| BasicBlock *LowBB = BasicBlock::Create(SI->getContext(), "switchsplit_low", F); | |||
| BasicBlock *HighBB = BasicBlock::Create(SI->getContext(), "switchsplit_high", F); | |||
| BranchInst *Br = BranchInst::Create(LowBB, HighBB, Check, SwitchBB); | |||
|
|
|||
| SwitchInst *LowSI = SwitchInst::Create(Condition, DD, NumItems/2, LowBB); | |||
| SwitchInst *HighSI = SwitchInst::Create(Condition, DD, NumItems/2, HighBB); | |||
|
|
|||
| for (SwitchInst::CaseIt i = SI->case_begin(), e = SI->case_end(); i != e; ++i) { | |||
| BasicBlock *BB = i.getCaseSuccessor(); | |||
| auto Value = i.getCaseValue(); | |||
| SwitchInst *NewSI = Value->getSExtValue() < Median ? LowSI : HighSI; | |||
| NewSI->addCase(Value, BB); | |||
| // update phis | |||
| BasicBlock *NewBB = NewSI->getParent(); | |||
| for (BasicBlock::iterator I = BB->begin(); I != BB->end(); ++I) { | |||
| PHINode *Phi = dyn_cast<PHINode>(I); | |||
| if (!Phi) break; | |||
| int Index = Phi->getBasicBlockIndex(SwitchBB); | |||
| if (Index < 0) continue; | |||
| Phi->addIncoming(Phi->getIncomingValue(Index), NewBB); | |||
| Phi->removeIncomingValue(Index); | |||
| } | |||
| } | |||
|
|
|||
| // fix default dest | |||
| for (BasicBlock::iterator I = DD->begin(); I != DD->end(); ++I) { | |||
| PHINode *Phi = dyn_cast<PHINode>(I); | |||
| if (!Phi) break; | |||
| int Index = Phi->getBasicBlockIndex(SwitchBB); | |||
| if (Index < 0) continue; | |||
| Phi->addIncoming(Phi->getIncomingValue(Index), LowBB); | |||
| Phi->addIncoming(Phi->getIncomingValue(Index), HighBB); | |||
| Phi->removeIncomingValue(Index); | |||
| } | |||
|
|
|||
| // finish up | |||
| SI->eraseFromParent(); | |||
| assert(SwitchBB->getTerminator() == Br); | |||
| assert(LowSI->getNumCases() + HighSI->getNumCases() == NumItems); | |||
| assert(LowSI->getNumCases() < HighSI->getNumCases() + 2); | |||
| assert(HighSI->getNumCases() < LowSI->getNumCases() + 2); | |||
| } | |||
|
|
|||
| bool ExpandBigSwitches::runOnFunction(Function &Func) { | |||
| bool Changed = false; | |||
|
|
|||
| struct SplitInfo { | |||
| SwitchInst *SI; | |||
| int64_t Median; | |||
| }; | |||
|
|
|||
| while (1) { // repetively split in 2 | |||
| std::vector<SplitInfo> ToSplit; | |||
| // find switches we need to split | |||
| for (Function::iterator B = Func.begin(), E = Func.end(); B != E; ++B) { | |||
| Instruction *I = B->getTerminator(); | |||
| SwitchInst *SI = dyn_cast<SwitchInst>(I); | |||
| if (!SI) continue; | |||
| SplitInfo Curr; | |||
| if (!ConsiderSplit(SI, Curr.Median)) continue; | |||
| Curr.SI = SI; | |||
| Changed = true; | |||
| ToSplit.push_back(Curr); | |||
| } | |||
| if (ToSplit.size() == 0) break; | |||
| // split them | |||
| for (auto& Curr : ToSplit) { | |||
| DoSplit(Curr.SI, Curr.Median); | |||
| } | |||
| } | |||
|
|
|||
| return Changed; | |||
| } | |||
|
|
|||
| // | |||
|
|
|||
| extern FunctionPass *createEmscriptenExpandBigSwitchesPass() { | |||
| return new ExpandBigSwitches(); | |||
| } | |||
|
|
|||
| } // End llvm namespace | |||
| @@ -0,0 +1,29 @@ | |||
| //===-- JS.h - Top-level interface for JS representation ------*- C++ -*-===// | |||
| // | |||
| // The LLVM Compiler Infrastructure | |||
| // | |||
| // This file is distributed under the University of Illinois Open Source | |||
| // License. See LICENSE.TXT for details. | |||
| // | |||
| //===----------------------------------------------------------------------===// | |||
| // | |||
| // This file contains the entry points for global functions defined in the JS | |||
| // target library, as used by the LLVM JIT. | |||
| // | |||
| //===----------------------------------------------------------------------===// | |||
|
|
|||
| #ifndef TARGET_JS_H | |||
| #define TARGET_JS_H | |||
|
|
|||
| namespace llvm { | |||
|
|
|||
| class ImmutablePass; | |||
| class JSTargetMachine; | |||
|
|
|||
| /// createJSISelDag - This pass converts a legalized DAG into a | |||
| /// \brief Creates an JS-specific Target Transformation Info pass. | |||
| ImmutablePass *createJSTargetTransformInfoPass(const JSTargetMachine *TM); | |||
|
|
|||
| } // End llvm namespace | |||
|
|
|||
| #endif | |||
| @@ -0,0 +1,48 @@ | |||
| //===-- JSTargetMachine.cpp - Define TargetMachine for the JS -------------===// | |||
| // | |||
| // The LLVM Compiler Infrastructure | |||
| // | |||
| // This file is distributed under the University of Illinois Open Source | |||
| // License. See LICENSE.TXT for details. | |||
| // | |||
| //===----------------------------------------------------------------------===// | |||
| // | |||
| // This file defines the JS specific subclass of TargetMachine. | |||
| // | |||
| //===----------------------------------------------------------------------===// | |||
|
|
|||
| #include "JSTargetMachine.h" | |||
| #include "JSTargetTransformInfo.h" | |||
| #include "llvm/Analysis/TargetTransformInfo.h" | |||
| #include "llvm/Support/TargetRegistry.h" | |||
| using namespace llvm; | |||
|
|
|||
| extern const llvm::SubtargetFeatureKV JSSubTypeKV[] = { | |||
| { "asmjs", "Select the asmjs processor", { }, { } } | |||
| }; | |||
|
|
|||
| static const llvm::SubtargetInfoKV JSProcSchedModels[] = { | |||
| { "asmjs", &MCSchedModel::GetDefaultSchedModel() } | |||
| }; | |||
|
|
|||
| JSSubtarget::JSSubtarget(const TargetMachine& TM, const Triple &TT) : | |||
| TargetSubtargetInfo(TT, "asmjs", "asmjs", None, makeArrayRef(JSSubTypeKV, 1), JSProcSchedModels, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr), | |||
| TL(TM) | |||
| {} | |||
|
|
|||
|
|
|||
| JSTargetMachine::JSTargetMachine(const Target &T, const Triple &TT, | |||
| StringRef CPU, StringRef FS, const TargetOptions &Options, | |||
| Optional<Reloc::Model>& RM, CodeModel::Model CM, | |||
| CodeGenOpt::Level OL) | |||
| : LLVMTargetMachine(T, "e-p:32:32-i64:64-v128:32:128-n32-S128", TT, | |||
| CPU, FS, Options, Reloc::Static, CM, OL), | |||
| ST(*this, TT) { | |||
| } | |||
|
|
|||
| TargetIRAnalysis JSTargetMachine::getTargetIRAnalysis() { | |||
| return TargetIRAnalysis([this](const Function &F) { | |||
| return TargetTransformInfo(JSTTIImpl(this, F)); | |||
| }); | |||
| } | |||
|
|
|||
| @@ -0,0 +1,72 @@ | |||
| //===-- JSTargetMachine.h - TargetMachine for the JS Backend ----*- C++ -*-===// | |||
| // | |||
| // The LLVM Compiler Infrastructure | |||
| // | |||
| // This file is distributed under the University of Illinois Open Source | |||
| // License. See LICENSE.TXT for details. | |||
| // | |||
| //===---------------------------------------------------------------------===// | |||
| // | |||
| // This file declares the TargetMachine that is used by the JS/asm.js/ | |||
| // emscripten backend. | |||
| // | |||
| //===---------------------------------------------------------------------===// | |||
|
|
|||
| #ifndef JSTARGETMACHINE_H | |||
| #define JSTARGETMACHINE_H | |||
|
|
|||
| #include "JS.h" | |||
| #include "llvm/Target/TargetMachine.h" | |||
| #include "llvm/Target/TargetSubtargetInfo.h" | |||
| #include "llvm/Target/TargetLowering.h" | |||
|
|
|||
| namespace llvm { | |||
|
|
|||
| class formatted_raw_ostream; | |||
|
|
|||
| class JSTargetLowering : public TargetLowering { | |||
| public: | |||
| explicit JSTargetLowering(const TargetMachine& TM) : TargetLowering(TM) {} | |||
| }; | |||
|
|
|||
| class JSSubtarget : public TargetSubtargetInfo { | |||
| JSTargetLowering TL; | |||
|
|
|||
| public: | |||
| JSSubtarget(const TargetMachine& TM, const Triple &TT); | |||
|
|
|||
| const TargetLowering *getTargetLowering() const override { | |||
| return &TL; | |||
| } | |||
| }; | |||
|
|
|||
| class JSTargetMachine : public LLVMTargetMachine { | |||
| const JSSubtarget ST; | |||
|
|
|||
| public: | |||
| JSTargetMachine(const Target &T, const Triple &TT, | |||
| StringRef CPU, StringRef FS, const TargetOptions &Options, | |||
| Optional<Reloc::Model>& RM, CodeModel::Model CM, | |||
| CodeGenOpt::Level OL); | |||
|
|
|||
| bool addPassesToEmitFile( | |||
| PassManagerBase &PM, raw_pwrite_stream &Out, CodeGenFileType FileType, | |||
| bool DisableVerify = true, AnalysisID StartBefore = nullptr, | |||
| AnalysisID StartAfter = nullptr, AnalysisID StopBefore = nullptr, | |||
| AnalysisID StopAfter = nullptr, | |||
| MachineFunctionInitializer *MFInitializer = nullptr) override; | |||
|
|
|||
| TargetIRAnalysis getTargetIRAnalysis() override; | |||
|
|
|||
| const TargetSubtargetInfo *getJSSubtargetImpl() const { | |||
| return &ST; | |||
| } | |||
|
|
|||
| const JSSubtarget *getSubtargetImpl(const Function &F) const override { | |||
| return &ST; | |||
| } | |||
| }; | |||
|
|
|||
| } // End llvm namespace | |||
|
|
|||
| #endif | |||
| @@ -0,0 +1,121 @@ | |||
| // | |||
| // The LLVM Compiler Infrastructure | |||
| // | |||
| // This file is distributed under the University of Illinois Open Source | |||
| // License. See LICENSE.TXT for details. | |||
| // | |||
| //===----------------------------------------------------------------------===// | |||
| // | |||
| // \file | |||
| // This file implements a TargetTransformInfo analysis pass specific to the | |||
| // JS target machine. It uses the target's detailed information to provide | |||
| // more precise answers to certain TTI queries, while letting the target | |||
| // independent and default TTI implementations handle the rest. | |||
| // | |||
| //===----------------------------------------------------------------------===// | |||
|
|
|||
| #include "JSTargetTransformInfo.h" | |||
| #include "llvm/Analysis/LoopInfo.h" | |||
| #include "llvm/Analysis/TargetTransformInfo.h" | |||
| #include "llvm/Analysis/ValueTracking.h" | |||
| #include "llvm/CodeGen/BasicTTIImpl.h" | |||
| #include "llvm/IR/Module.h" | |||
| #include "llvm/Support/Debug.h" | |||
| #include "llvm/Support/raw_ostream.h" | |||
| #include "llvm/Target/CostTable.h" | |||
| #include "llvm/Target/TargetLowering.h" | |||
| using namespace llvm; | |||
|
|
|||
| #define DEBUG_TYPE "JStti" | |||
|
|
|||
| void JSTTIImpl::getUnrollingPreferences(Loop *L, | |||
| TTI::UnrollingPreferences &UP) { | |||
| // We generally don't want a lot of unrolling. | |||
| UP.Partial = false; | |||
| UP.Runtime = false; | |||
| } | |||
|
|
|||
| unsigned JSTTIImpl::getNumberOfRegisters(bool Vector) { | |||
| if (Vector) return 16; // like NEON, x86_64, etc. | |||
|
|
|||
| return 8; // like x86, thumb, etc. | |||
| } | |||
|
|
|||
| unsigned JSTTIImpl::getRegisterBitWidth(bool Vector) { | |||
| if (Vector) { | |||
| return 128; | |||
| } | |||
|
|
|||
| return 32; | |||
| } | |||
|
|
|||
| static const unsigned Nope = 65536; | |||
|
|
|||
| // Certain types are fine, but some vector types must be avoided at all Costs. | |||
| static bool isOkType(Type *Ty) { | |||
| if (VectorType *VTy = dyn_cast<VectorType>(Ty)) { | |||
| if (VTy->getNumElements() != 4 || !(VTy->getElementType()->isIntegerTy(1) || | |||
| VTy->getElementType()->isIntegerTy(32) || | |||
| VTy->getElementType()->isFloatTy())) { | |||
| return false; | |||
| } | |||
| } | |||
| return true; | |||
| } | |||
|
|
|||
| unsigned JSTTIImpl::getArithmeticInstrCost( | |||
| unsigned Opcode, Type *Ty, TTI::OperandValueKind Opd1Info, | |||
| TTI::OperandValueKind Opd2Info, TTI::OperandValueProperties Opd1PropInfo, | |||
| TTI::OperandValueProperties Opd2PropInfo, | |||
| ArrayRef<const Value*> Args) { | |||
|
|
|||
| unsigned Cost = BasicTTIImplBase<JSTTIImpl>::getArithmeticInstrCost(Opcode, Ty, Opd1Info, | |||
| Opd2Info, Opd1PropInfo, | |||
| Opd2PropInfo, Args); | |||
|
|
|||
| if (!isOkType(Ty)) | |||
| return Nope; | |||
|
|
|||
| if (VectorType *VTy = dyn_cast<VectorType>(Ty)) { | |||
| switch (Opcode) { | |||
| case Instruction::LShr: | |||
| case Instruction::AShr: | |||
| case Instruction::Shl: | |||
| // SIMD.js' shifts are currently only ByScalar. | |||
| if (Opd2Info != TTI::OK_UniformValue && Opd2Info != TTI::OK_UniformConstantValue) | |||
| Cost = Cost * VTy->getNumElements() + 100; | |||
| break; | |||
| } | |||
| } | |||
| return Cost; | |||
| } | |||
|
|
|||
| unsigned JSTTIImpl::getVectorInstrCost(unsigned Opcode, Type *Val, unsigned Index) { | |||
| if (!isOkType(Val)) | |||
| return Nope; | |||
|
|
|||
| unsigned Cost = BasicTTIImplBase::getVectorInstrCost(Opcode, Val, Index); | |||
|
|
|||
| // SIMD.js' insert/extract currently only take constant indices. | |||
| if (Index == -1u) | |||
| return Cost + 100; | |||
|
|
|||
| return Cost; | |||
| } | |||
|
|
|||
|
|
|||
| unsigned JSTTIImpl::getMemoryOpCost(unsigned Opcode, Type *Src, unsigned Alignment, | |||
| unsigned AddressSpace) { | |||
| if (!isOkType(Src)) | |||
| return Nope; | |||
|
|
|||
| return BasicTTIImplBase::getMemoryOpCost(Opcode, Src, Alignment, AddressSpace); | |||
| } | |||
|
|
|||
| unsigned JSTTIImpl::getCastInstrCost(unsigned Opcode, Type *Dst, Type *Src) { | |||
| if (!isOkType(Src) || !isOkType(Dst)) | |||
| return Nope; | |||
|
|
|||
| return BasicTTIImplBase::getCastInstrCost(Opcode, Dst, Src); | |||
| } | |||
|
|
|||
| @@ -0,0 +1,97 @@ | |||
| //===-- JSTargetTransformInfo.h - JS specific TTI -------*- C++ -*-===// | |||
| // | |||
| // The LLVM Compiler Infrastructure | |||
| // | |||
| // This file is distributed under the University of Illinois Open Source | |||
| // License. See LICENSE.TXT for details. | |||
| // | |||
| //===----------------------------------------------------------------------===// | |||
| /// \file | |||
| /// This file a TargetTransformInfo::Concept conforming object specific to the | |||
| /// JS target machine. It uses the target's detailed information to | |||
| /// provide more precise answers to certain TTI queries, while letting the | |||
| /// target independent and default TTI implementations handle the rest. | |||
| /// | |||
| //===----------------------------------------------------------------------===// | |||
|
|
|||
| #ifndef LLVM_LIB_TARGET_JS_JSTARGETTRANSFORMINFO_H | |||
| #define LLVM_LIB_TARGET_JS_JSTARGETTRANSFORMINFO_H | |||
|
|
|||
| #include "JSTargetMachine.h" | |||
| #include "llvm/Analysis/TargetTransformInfo.h" | |||
| #include "llvm/CodeGen/BasicTTIImpl.h" | |||
| #include "llvm/Target/TargetLowering.h" | |||
|
|
|||
| namespace llvm { | |||
|
|
|||
| class JSTTIImpl : public BasicTTIImplBase<JSTTIImpl> { | |||
| typedef BasicTTIImplBase<JSTTIImpl> BaseT; | |||
| typedef TargetTransformInfo TTI; | |||
| friend BaseT; | |||
|
|
|||
| const TargetSubtargetInfo *ST; | |||
| const TargetLoweringBase *TLI; | |||
|
|
|||
| const TargetSubtargetInfo *getST() const { return ST; } | |||
| const TargetLoweringBase *getTLI() const { return TLI; } | |||
|
|
|||
| public: | |||
| explicit JSTTIImpl(const JSTargetMachine *TM, const Function &F) | |||
| : BaseT(TM, F.getParent()->getDataLayout()), ST(TM->getSubtargetImpl(F)), | |||
| TLI(ST->getTargetLowering()) {} | |||
|
|
|||
| // Provide value semantics. MSVC requires that we spell all of these out. | |||
| JSTTIImpl(const JSTTIImpl &Arg) | |||
| : BaseT(static_cast<const BaseT &>(Arg)), ST(Arg.ST), TLI(Arg.TLI) {} | |||
| JSTTIImpl(JSTTIImpl &&Arg) | |||
| : BaseT(std::move(static_cast<BaseT &>(Arg))), ST(std::move(Arg.ST)), | |||
| TLI(std::move(Arg.TLI)) {} | |||
| /* | |||
| JSTTIImpl &operator=(const JSTTIImpl &RHS) { | |||
| BaseT::operator=(static_cast<const BaseT &>(RHS)); | |||
| ST = RHS.ST; | |||
| TLI = RHS.TLI; | |||
| return *this; | |||
| } | |||
| JSTTIImpl &operator=(JSTTIImpl &&RHS) { | |||
| BaseT::operator=(std::move(static_cast<BaseT &>(RHS))); | |||
| ST = std::move(RHS.ST); | |||
| TLI = std::move(RHS.TLI); | |||
| return *this; | |||
| } | |||
| */ | |||
|
|
|||
| bool hasBranchDivergence() { return true; } | |||
|
|
|||
| void getUnrollingPreferences(Loop *L, TTI::UnrollingPreferences &UP); | |||
|
|
|||
| TTI::PopcntSupportKind getPopcntSupport( | |||
| unsigned TyWidth) { | |||
| assert(isPowerOf2_32(TyWidth) && "Ty width must be power of 2"); | |||
| // Hopefully we'll get popcnt in ES7, but for now, we just have software. | |||
| return TargetTransformInfo::PSK_Software; | |||
| } | |||
|
|
|||
| unsigned getNumberOfRegisters(bool Vector); | |||
|
|
|||
| unsigned getRegisterBitWidth(bool Vector); | |||
|
|
|||
| unsigned getArithmeticInstrCost( | |||
| unsigned Opcode, Type *Ty, | |||
| TTI::OperandValueKind Opd1Info = TTI::OK_AnyValue, | |||
| TTI::OperandValueKind Opd2Info = TTI::OK_AnyValue, | |||
| TTI::OperandValueProperties Opd1PropInfo = TTI::OP_None, | |||
| TTI::OperandValueProperties Opd2PropInfo = TTI::OP_None, | |||
| ArrayRef<const Value*> Args = {}); | |||
|
|
|||
| unsigned getVectorInstrCost(unsigned Opcode, Type *Val, unsigned Index); | |||
|
|
|||
| unsigned getMemoryOpCost(unsigned Opcode, Type *Src, unsigned Alignment, | |||
| unsigned AddressSpace); | |||
|
|
|||
| unsigned getCastInstrCost(unsigned Opcode, Type *Dst, Type *Src); | |||
| }; | |||
|
|
|||
| } // end namespace llvm | |||
|
|
|||
| #endif | |||
| @@ -0,0 +1,31 @@ | |||
| ;===- ./lib/Target/JSBackend/LLVMBuild.txt --------------------*- Conf -*--===; | |||
| ; | |||
| ; The LLVM Compiler Infrastructure | |||
| ; | |||
| ; This file is distributed under the University of Illinois Open Source | |||
| ; License. See LICENSE.TXT for details. | |||
| ; | |||
| ;===------------------------------------------------------------------------===; | |||
| ; | |||
| ; This is an LLVMBuild description file for the components in this subdirectory. | |||
| ; | |||
| ; For more information on the LLVMBuild system, please see: | |||
| ; | |||
| ; http://llvm.org/docs/LLVMBuild.html | |||
| ; | |||
| ;===------------------------------------------------------------------------===; | |||
|
|
|||
| [common] | |||
| subdirectories = MCTargetDesc NaCl TargetInfo | |||
|
|
|||
| [component_0] | |||
| type = TargetGroup | |||
| name = JSBackend | |||
| parent = Target | |||
|
|
|||
| [component_1] | |||
| type = Library | |||
| name = JSBackendCodeGen | |||
| parent = JSBackend | |||
| required_libraries = Analysis CodeGen Core IPO JSBackendInfo JSBackendDesc MC PNaClTransforms Scalar Support SelectionDAG Target TransformUtils | |||
| add_to_library_groups = JSBackend | |||
| @@ -0,0 +1,6 @@ | |||
| add_llvm_library(LLVMJSBackendDesc | |||
| JSBackendMCTargetDesc.cpp | |||
| ) | |||
|
|
|||
| # Hack: we need to include 'main' target directory to grab private headers | |||
| include_directories(${CMAKE_CURRENT_SOURCE_DIR}/.. ${CMAKE_CURRENT_BINARY_DIR}/..) | |||
| @@ -0,0 +1,22 @@ | |||
| //===-- JSBackendMCTargetDesc.cpp - JS Backend Target Descriptions --------===// | |||
| // | |||
| // The LLVM Compiler Infrastructure | |||
| // | |||
| // This file is distributed under the University of Illinois Open Source | |||
| // License. See LICENSE.TXT for details. | |||
| // | |||
| //===----------------------------------------------------------------------===// | |||
| // | |||
| // This file provides asm.js specific target descriptions. | |||
| // | |||
| //===----------------------------------------------------------------------===// | |||
|
|
|||
| #include "JSBackendMCTargetDesc.h" | |||
| #include "llvm/Support/TargetRegistry.h" | |||
| using namespace llvm; | |||
|
|
|||
| // Force static initialization. | |||
| extern "C" void LLVMInitializeJSBackendTargetMC() { | |||
| // nothing to register | |||
| } | |||
|
|
|||
| @@ -0,0 +1,25 @@ | |||
| //===- JSBackendMCTargetDesc.h - JS Backend Target Descriptions -*- C++ -*-===// | |||
| // | |||
| // The LLVM Compiler Infrastructure | |||
| // | |||
| // This file is distributed under the University of Illinois Open Source | |||
| // License. See LICENSE.TXT for details. | |||
| // | |||
| //===----------------------------------------------------------------------===// | |||
| // | |||
| // This file provides asm.js specific target descriptions. | |||
| // | |||
| //===----------------------------------------------------------------------===// | |||
|
|
|||
| #ifndef JSBACKENDMCTARGETDESC_H | |||
| #define JSBACKENDMCTARGETDESC_H | |||
|
|
|||
| #include "llvm/Support/TargetRegistry.h" | |||
|
|
|||
| namespace llvm { | |||
|
|
|||
| extern Target TheJSBackendTarget; | |||
|
|
|||
| } // End llvm namespace | |||
|
|
|||
| #endif | |||
| @@ -0,0 +1,24 @@ | |||
| ;===- ./lib/Target/JSBackend/MCTargetDesc/LLVMBuild.txt --------*- Conf -*--===; | |||
| ; | |||
| ; The LLVM Compiler Infrastructure | |||
| ; | |||
| ; This file is distributed under the University of Illinois Open Source | |||
| ; License. See LICENSE.TXT for details. | |||
| ; | |||
| ;===------------------------------------------------------------------------===; | |||
| ; | |||
| ; This is an LLVMBuild description file for the components in this subdirectory. | |||
| ; | |||
| ; For more information on the LLVMBuild system, please see: | |||
| ; | |||
| ; http://llvm.org/docs/LLVMBuild.html | |||
| ; | |||
| ;===------------------------------------------------------------------------===; | |||
|
|
|||
| [component_0] | |||
| type = Library | |||
| name = JSBackendDesc | |||
| parent = JSBackend | |||
| required_libraries = MC Support JSBackendInfo | |||
| add_to_library_groups = JSBackend | |||
|
|
|||
| @@ -0,0 +1,85 @@ | |||
| //===- AddPNaClExternalDecls.cpp - Add decls for PNaCl external functions -===// | |||
| // | |||
| // The LLVM Compiler Infrastructure | |||
| // | |||
| // This file is distributed under the University of Illinois Open Source | |||
| // License. See LICENSE.TXT for details. | |||
| // | |||
| //===----------------------------------------------------------------------===// | |||
| // | |||
| // This pass adds function declarations for external functions used by PNaCl. | |||
| // These externals are implemented in native libraries and calls to them are | |||
| // created as part of the translation process. | |||
| // | |||
| // Running this pass is a precondition for running ResolvePNaClIntrinsics. They | |||
| // are separate because one is a ModulePass and the other is a FunctionPass. | |||
| // | |||
| //===----------------------------------------------------------------------===// | |||
|
|
|||
| #include "llvm/IR/DerivedTypes.h" | |||
| #include "llvm/IR/Intrinsics.h" | |||
| #include "llvm/IR/Module.h" | |||
| #include "llvm/IR/NaClAtomicIntrinsics.h" | |||
| #include "llvm/IR/Type.h" | |||
| #include "llvm/Pass.h" | |||
| #include "llvm/Transforms/NaCl.h" | |||
|
|
|||
| using namespace llvm; | |||
|
|
|||
| namespace { | |||
| // This is a module pass because it adds declarations to the module. | |||
| class AddPNaClExternalDecls : public ModulePass { | |||
| public: | |||
| static char ID; | |||
| AddPNaClExternalDecls() : ModulePass(ID) { | |||
| initializeAddPNaClExternalDeclsPass(*PassRegistry::getPassRegistry()); | |||
| } | |||
|
|
|||
| virtual bool runOnModule(Module &M); | |||
| }; | |||
| } | |||
|
|
|||
| bool AddPNaClExternalDecls::runOnModule(Module &M) { | |||
| // Add declarations for a pre-defined set of external functions to the module. | |||
| // The function names must match the functions implemented in native code (in | |||
| // pnacl/support). The function types must match the types of the LLVM | |||
| // intrinsics. | |||
| // We expect these declarations not to exist in the module before this pass | |||
| // runs, but don't assert it; it will be handled by the ABI verifier. | |||
| LLVMContext &C = M.getContext(); | |||
| M.getOrInsertFunction("setjmp", | |||
| // return type | |||
| Type::getInt32Ty(C), | |||
| // arguments | |||
| Type::getInt8Ty(C)->getPointerTo(), | |||
| NULL); | |||
| M.getOrInsertFunction("longjmp", | |||
| // return type | |||
| Type::getVoidTy(C), | |||
| // arguments | |||
| Type::getInt8Ty(C)->getPointerTo(), | |||
| Type::getInt32Ty(C), | |||
| NULL); | |||
|
|
|||
| // Add Intrinsic declarations needed by ResolvePNaClIntrinsics up front. | |||
| Intrinsic::getDeclaration(&M, Intrinsic::nacl_setjmp); | |||
| Intrinsic::getDeclaration(&M, Intrinsic::nacl_longjmp); | |||
| NaCl::AtomicIntrinsics AI(C); | |||
| NaCl::AtomicIntrinsics::View V = AI.allIntrinsicsAndOverloads(); | |||
| for (NaCl::AtomicIntrinsics::View::iterator I = V.begin(), E = V.end(); | |||
| I != E; ++I) { | |||
| I->getDeclaration(&M); | |||
| } | |||
| Intrinsic::getDeclaration(&M, Intrinsic::nacl_atomic_is_lock_free); | |||
|
|
|||
| return true; | |||
| } | |||
|
|
|||
| char AddPNaClExternalDecls::ID = 0; | |||
| INITIALIZE_PASS(AddPNaClExternalDecls, "add-pnacl-external-decls", | |||
| "Add declarations of external functions used by PNaCl", | |||
| false, false) | |||
|
|
|||
| ModulePass *llvm::createAddPNaClExternalDeclsPass() { | |||
| return new AddPNaClExternalDecls(); | |||
| } | |||
| @@ -0,0 +1,360 @@ | |||
| //===- BackendCanonicalize.cpp --------------------------------------------===// | |||
| // | |||
| // The LLVM Compiler Infrastructure | |||
| // | |||
| // This file is distributed under the University of Illinois Open Source | |||
| // License. See LICENSE.TXT for details. | |||
| // | |||
| //===----------------------------------------------------------------------===// | |||
| // | |||
| // Clean up some toolchain-side PNaCl ABI simplification passes. These passes | |||
| // allow PNaCl to have a simple and stable ABI, but they sometimes lead to | |||
| // harder-to-optimize code. This is desirable because LLVM's definition of | |||
| // "canonical" evolves over time, meaning that PNaCl's simple ABI can stay | |||
| // simple yet still take full advantage of LLVM's backend by having this pass | |||
| // massage the code into something that the backend prefers handling. | |||
| // | |||
| // It currently: | |||
| // - Re-generates shufflevector (not part of the PNaCl ABI) from insertelement / | |||
| // extractelement combinations. This is done by duplicating some of | |||
| // instcombine's implementation, and ignoring optimizations that should | |||
| // already have taken place. | |||
| // - Re-materializes constant loads, especially of vectors. This requires doing | |||
| // constant folding through bitcasts. | |||
| // | |||
| // The pass also performs limited DCE on instructions it knows to be dead, | |||
| // instead of performing a full global DCE. | |||
| // | |||
| //===----------------------------------------------------------------------===// | |||
|
|
|||
| #include "llvm/Analysis/ConstantFolding.h" | |||
| #include "llvm/IR/BasicBlock.h" | |||
| #include "llvm/IR/DataLayout.h" | |||
| #include "llvm/IR/IRBuilder.h" | |||
| #include "llvm/IR/Instruction.h" | |||
| #include "llvm/IR/Instructions.h" | |||
| #include "llvm/IR/Operator.h" | |||
| #include "llvm/IR/InstVisitor.h" | |||
| #include "llvm/Pass.h" | |||
| #include "llvm/Analysis/TargetLibraryInfo.h" | |||
| #include "llvm/Transforms/NaCl.h" | |||
| #include "llvm/Transforms/Utils/Local.h" | |||
|
|
|||
| using namespace llvm; | |||
|
|
|||
| // ============================================================================= | |||
| // TODO(jfb) The following functions are as-is from instcombine. Make them | |||
| // reusable instead. | |||
|
|
|||
| /// CollectSingleShuffleElements - If V is a shuffle of values that ONLY returns | |||
| /// elements from either LHS or RHS, return the shuffle mask and true. | |||
| /// Otherwise, return false. | |||
| static bool CollectSingleShuffleElements(Value *V, Value *LHS, Value *RHS, | |||
| SmallVectorImpl<Constant*> &Mask) { | |||
| assert(LHS->getType() == RHS->getType() && | |||
| "Invalid CollectSingleShuffleElements"); | |||
| unsigned NumElts = V->getType()->getVectorNumElements(); | |||
|
|
|||
| if (isa<UndefValue>(V)) { | |||
| Mask.assign(NumElts, UndefValue::get(Type::getInt32Ty(V->getContext()))); | |||
| return true; | |||
| } | |||
|
|
|||
| if (V == LHS) { | |||
| for (unsigned i = 0; i != NumElts; ++i) | |||
| Mask.push_back(ConstantInt::get(Type::getInt32Ty(V->getContext()), i)); | |||
| return true; | |||
| } | |||
|
|
|||
| if (V == RHS) { | |||
| for (unsigned i = 0; i != NumElts; ++i) | |||
| Mask.push_back(ConstantInt::get(Type::getInt32Ty(V->getContext()), | |||
| i+NumElts)); | |||
| return true; | |||
| } | |||
|
|
|||
| if (InsertElementInst *IEI = dyn_cast<InsertElementInst>(V)) { | |||
| // If this is an insert of an extract from some other vector, include it. | |||
| Value *VecOp = IEI->getOperand(0); | |||
| Value *ScalarOp = IEI->getOperand(1); | |||
| Value *IdxOp = IEI->getOperand(2); | |||
|
|
|||
| if (!isa<ConstantInt>(IdxOp)) | |||
| return false; | |||
| unsigned InsertedIdx = cast<ConstantInt>(IdxOp)->getZExtValue(); | |||
|
|
|||
| if (isa<UndefValue>(ScalarOp)) { // inserting undef into vector. | |||
| // We can handle this if the vector we are inserting into is | |||
| // transitively ok. | |||
| if (CollectSingleShuffleElements(VecOp, LHS, RHS, Mask)) { | |||
| // If so, update the mask to reflect the inserted undef. | |||
| Mask[InsertedIdx] = UndefValue::get(Type::getInt32Ty(V->getContext())); | |||
| return true; | |||
| } | |||
| } else if (ExtractElementInst *EI = dyn_cast<ExtractElementInst>(ScalarOp)){ | |||
| if (isa<ConstantInt>(EI->getOperand(1))) { | |||
| unsigned ExtractedIdx = | |||
| cast<ConstantInt>(EI->getOperand(1))->getZExtValue(); | |||
| unsigned NumLHSElts = LHS->getType()->getVectorNumElements(); | |||
|
|
|||
| // This must be extracting from either LHS or RHS. | |||
| if (EI->getOperand(0) == LHS || EI->getOperand(0) == RHS) { | |||
| // We can handle this if the vector we are inserting into is | |||
| // transitively ok. | |||
| if (CollectSingleShuffleElements(VecOp, LHS, RHS, Mask)) { | |||
| // If so, update the mask to reflect the inserted value. | |||
| if (EI->getOperand(0) == LHS) { | |||
| Mask[InsertedIdx % NumElts] = | |||
| ConstantInt::get(Type::getInt32Ty(V->getContext()), | |||
| ExtractedIdx); | |||
| } else { | |||
| assert(EI->getOperand(0) == RHS); | |||
| Mask[InsertedIdx % NumElts] = | |||
| ConstantInt::get(Type::getInt32Ty(V->getContext()), | |||
| ExtractedIdx + NumLHSElts); | |||
| } | |||
| return true; | |||
| } | |||
| } | |||
| } | |||
| } | |||
| } | |||
|
|
|||
| return false; | |||
| } | |||
|
|
|||
| /// We are building a shuffle to create V, which is a sequence of insertelement, | |||
| /// extractelement pairs. If PermittedRHS is set, then we must either use it or | |||
| /// not rely on the second vector source. Return a std::pair containing the | |||
| /// left and right vectors of the proposed shuffle (or 0), and set the Mask | |||
| /// parameter as required. | |||
| /// | |||
| /// Note: we intentionally don't try to fold earlier shuffles since they have | |||
| /// often been chosen carefully to be efficiently implementable on the target. | |||
| typedef std::pair<Value *, Value *> ShuffleOps; | |||
|
|
|||
| static ShuffleOps CollectShuffleElements(Value *V, | |||
| SmallVectorImpl<Constant *> &Mask, | |||
| Value *PermittedRHS) { | |||
| assert(V->getType()->isVectorTy() && "Invalid shuffle!"); | |||
| unsigned NumElts = cast<VectorType>(V->getType())->getNumElements(); | |||
|
|
|||
| if (isa<UndefValue>(V)) { | |||
| Mask.assign(NumElts, UndefValue::get(Type::getInt32Ty(V->getContext()))); | |||
| return std::make_pair( | |||
| PermittedRHS ? UndefValue::get(PermittedRHS->getType()) : V, nullptr); | |||
| } | |||
|
|
|||
| if (isa<ConstantAggregateZero>(V)) { | |||
| Mask.assign(NumElts, ConstantInt::get(Type::getInt32Ty(V->getContext()),0)); | |||
| return std::make_pair(V, nullptr); | |||
| } | |||
|
|
|||
| if (InsertElementInst *IEI = dyn_cast<InsertElementInst>(V)) { | |||
| // If this is an insert of an extract from some other vector, include it. | |||
| Value *VecOp = IEI->getOperand(0); | |||
| Value *ScalarOp = IEI->getOperand(1); | |||
| Value *IdxOp = IEI->getOperand(2); | |||
|
|
|||
| if (ExtractElementInst *EI = dyn_cast<ExtractElementInst>(ScalarOp)) { | |||
| if (isa<ConstantInt>(EI->getOperand(1)) && isa<ConstantInt>(IdxOp)) { | |||
| unsigned ExtractedIdx = | |||
| cast<ConstantInt>(EI->getOperand(1))->getZExtValue(); | |||
| unsigned InsertedIdx = cast<ConstantInt>(IdxOp)->getZExtValue(); | |||
|
|
|||
| // Either the extracted from or inserted into vector must be RHSVec, | |||
| // otherwise we'd end up with a shuffle of three inputs. | |||
| if (EI->getOperand(0) == PermittedRHS || PermittedRHS == nullptr) { | |||
| Value *RHS = EI->getOperand(0); | |||
| ShuffleOps LR = CollectShuffleElements(VecOp, Mask, RHS); | |||
| assert(LR.second == nullptr || LR.second == RHS); | |||
|
|
|||
| if (LR.first->getType() != RHS->getType()) { | |||
| // We tried our best, but we can't find anything compatible with RHS | |||
| // further up the chain. Return a trivial shuffle. | |||
| for (unsigned i = 0; i < NumElts; ++i) | |||
| Mask[i] = ConstantInt::get(Type::getInt32Ty(V->getContext()), i); | |||
| return std::make_pair(V, nullptr); | |||
| } | |||
|
|
|||
| unsigned NumLHSElts = RHS->getType()->getVectorNumElements(); | |||
| Mask[InsertedIdx % NumElts] = | |||
| ConstantInt::get(Type::getInt32Ty(V->getContext()), | |||
| NumLHSElts+ExtractedIdx); | |||
| return std::make_pair(LR.first, RHS); | |||
| } | |||
|
|
|||
| if (VecOp == PermittedRHS) { | |||
| // We've gone as far as we can: anything on the other side of the | |||
| // extractelement will already have been converted into a shuffle. | |||
| unsigned NumLHSElts = | |||
| EI->getOperand(0)->getType()->getVectorNumElements(); | |||
| for (unsigned i = 0; i != NumElts; ++i) | |||
| Mask.push_back(ConstantInt::get( | |||
| Type::getInt32Ty(V->getContext()), | |||
| i == InsertedIdx ? ExtractedIdx : NumLHSElts + i)); | |||
| return std::make_pair(EI->getOperand(0), PermittedRHS); | |||
| } | |||
|
|
|||
| // If this insertelement is a chain that comes from exactly these two | |||
| // vectors, return the vector and the effective shuffle. | |||
| if (EI->getOperand(0)->getType() == PermittedRHS->getType() && | |||
| CollectSingleShuffleElements(IEI, EI->getOperand(0), PermittedRHS, | |||
| Mask)) | |||
| return std::make_pair(EI->getOperand(0), PermittedRHS); | |||
| } | |||
| } | |||
| } | |||
|
|
|||
| // Otherwise, can't do anything fancy. Return an identity vector. | |||
| for (unsigned i = 0; i != NumElts; ++i) | |||
| Mask.push_back(ConstantInt::get(Type::getInt32Ty(V->getContext()), i)); | |||
| return std::make_pair(V, nullptr); | |||
| } | |||
|
|
|||
| // ============================================================================= | |||
|
|
|||
|
|
|||
| namespace { | |||
|
|
|||
| class BackendCanonicalize : public FunctionPass, | |||
| public InstVisitor<BackendCanonicalize, bool> { | |||
| public: | |||
| static char ID; // Pass identification, replacement for typeid | |||
| BackendCanonicalize() : FunctionPass(ID), DL(0), TLI(0) { | |||
| initializeBackendCanonicalizePass(*PassRegistry::getPassRegistry()); | |||
| } | |||
| virtual void getAnalysisUsage(AnalysisUsage &AU) const { | |||
| AU.addRequired<TargetLibraryInfoWrapperPass>(); | |||
| FunctionPass::getAnalysisUsage(AU); | |||
| } | |||
|
|
|||
| virtual bool runOnFunction(Function &F); | |||
|
|
|||
| // InstVisitor implementation. Unhandled instructions stay as-is. | |||
| bool visitInstruction(Instruction &I) { return false; } | |||
| bool visitInsertElementInst(InsertElementInst &IE); | |||
| bool visitBitCastInst(BitCastInst &C); | |||
| bool visitLoadInst(LoadInst &L); | |||
|
|
|||
| private: | |||
| const DataLayout *DL; | |||
| const TargetLibraryInfo *TLI; | |||
|
|
|||
| // List of instructions that are now obsolete, and should be DCE'd. | |||
| typedef SmallVector<Instruction *, 512> KillList; | |||
| KillList Kill; | |||
|
|
|||
| /// Helper that constant folds an instruction. | |||
| bool visitConstantFoldableInstruction(Instruction *I); | |||
|
|
|||
| /// Empty the kill list, making sure that all other dead instructions | |||
| /// up the chain (but in the current basic block) also get killed. | |||
| static void emptyKillList(KillList &Kill); | |||
| }; | |||
|
|
|||
| } // anonymous namespace | |||
|
|
|||
| char BackendCanonicalize::ID = 0; | |||
| INITIALIZE_PASS(BackendCanonicalize, "backend-canonicalize", | |||
| "Canonicalize PNaCl bitcode for LLVM backends", false, false) | |||
|
|
|||
| bool BackendCanonicalize::runOnFunction(Function &F) { | |||
| bool Modified = false; | |||
| DL = &F.getParent()->getDataLayout(); | |||
| TLI = &getAnalysis<TargetLibraryInfoWrapperPass>().getTLI(); | |||
|
|
|||
| for (Function::iterator FI = F.begin(), FE = F.end(); FI != FE; ++FI) | |||
| for (BasicBlock::iterator BI = FI->begin(), BE = FI->end(); BI != BE; ++BI) | |||
| Modified |= visit(&*BI); | |||
| emptyKillList(Kill); | |||
| return Modified; | |||
| } | |||
|
|
|||
| // This function is *almost* as-is from instcombine, avoiding silly | |||
| // cases that should already have been optimized. | |||
| bool BackendCanonicalize::visitInsertElementInst(InsertElementInst &IE) { | |||
| Value *ScalarOp = IE.getOperand(1); | |||
| Value *IdxOp = IE.getOperand(2); | |||
|
|
|||
| // If the inserted element was extracted from some other vector, and if the | |||
| // indexes are constant, try to turn this into a shufflevector operation. | |||
| if (ExtractElementInst *EI = dyn_cast<ExtractElementInst>(ScalarOp)) { | |||
| if (isa<ConstantInt>(EI->getOperand(1)) && isa<ConstantInt>(IdxOp)) { | |||
| unsigned NumInsertVectorElts = IE.getType()->getNumElements(); | |||
| unsigned NumExtractVectorElts = | |||
| EI->getOperand(0)->getType()->getVectorNumElements(); | |||
| unsigned ExtractedIdx = | |||
| cast<ConstantInt>(EI->getOperand(1))->getZExtValue(); | |||
| unsigned InsertedIdx = cast<ConstantInt>(IdxOp)->getZExtValue(); | |||
|
|
|||
| if (ExtractedIdx >= NumExtractVectorElts) // Out of range extract. | |||
| return false; | |||
|
|
|||
| if (InsertedIdx >= NumInsertVectorElts) // Out of range insert. | |||
| return false; | |||
|
|
|||
| // If this insertelement isn't used by some other insertelement, turn it | |||
| // (and any insertelements it points to), into one big shuffle. | |||
| if (!IE.hasOneUse() || !isa<InsertElementInst>(IE.user_back())) { | |||
| typedef SmallVector<Constant *, 16> MaskT; | |||
| MaskT Mask; | |||
| Value *LHS, *RHS; | |||
| std::tie(LHS, RHS) = CollectShuffleElements(&IE, Mask, nullptr); | |||
| if (!RHS) | |||
| RHS = UndefValue::get(LHS->getType()); | |||
| // We now have a shuffle of LHS, RHS, Mask. | |||
|
|
|||
| if (isa<UndefValue>(LHS) && !isa<UndefValue>(RHS)) { | |||
| // Canonicalize shufflevector to always have undef on the RHS, | |||
| // and adjust the mask. | |||
| std::swap(LHS, RHS); | |||
| for (MaskT::iterator I = Mask.begin(), E = Mask.end(); I != E; ++I) { | |||
| unsigned Idx = cast<ConstantInt>(*I)->getZExtValue(); | |||
| unsigned NewIdx = Idx >= NumInsertVectorElts | |||
| ? Idx - NumInsertVectorElts | |||
| : Idx + NumInsertVectorElts; | |||
| *I = ConstantInt::get(Type::getInt32Ty(RHS->getContext()), NewIdx); | |||
| } | |||
| } | |||
|
|
|||
| IRBuilder<> IRB(&IE); | |||
| IE.replaceAllUsesWith( | |||
| IRB.CreateShuffleVector(LHS, RHS, ConstantVector::get(Mask))); | |||
| // The chain of now-dead insertelement / extractelement | |||
| // instructions can be deleted. | |||
| Kill.push_back(&IE); | |||
|
|
|||
| return true; | |||
| } | |||
| } | |||
| } | |||
|
|
|||
| return false; | |||
| } | |||
|
|
|||
| bool BackendCanonicalize::visitBitCastInst(BitCastInst &B) { | |||
| return visitConstantFoldableInstruction(&B); | |||
| } | |||
|
|
|||
| bool BackendCanonicalize::visitLoadInst(LoadInst &L) { | |||
| return visitConstantFoldableInstruction(&L); | |||
| } | |||
|
|
|||
| bool BackendCanonicalize::visitConstantFoldableInstruction(Instruction *I) { | |||
| if (Constant *Folded = ConstantFoldInstruction(I, *DL, TLI)) { | |||
| I->replaceAllUsesWith(Folded); | |||
| Kill.push_back(I); | |||
| return true; | |||
| } | |||
| return false; | |||
| } | |||
|
|
|||
| void BackendCanonicalize::emptyKillList(KillList &Kill) { | |||
| while (!Kill.empty()) | |||
| RecursivelyDeleteTriviallyDeadInstructions(Kill.pop_back_val()); | |||
| } | |||
|
|
|||
| FunctionPass *llvm::createBackendCanonicalizePass() { | |||
| return new BackendCanonicalize(); | |||
| } | |||
| @@ -0,0 +1,55 @@ | |||
| include_directories( ${CMAKE_CURRENT_BINARY_DIR}/.. ${CMAKE_CURRENT_SOURCE_DIR}/.. ) | |||
|
|
|||
| add_llvm_library(LLVMPNaClTransforms | |||
| AddPNaClExternalDecls.cpp | |||
| BackendCanonicalize.cpp | |||
| CanonicalizeMemIntrinsics.cpp | |||
| CleanupUsedGlobalsMetadata.cpp | |||
| ConstantInsertExtractElementIndex.cpp | |||
| ExceptionInfoWriter.cpp | |||
| ExpandArithWithOverflow.cpp | |||
| ExpandByVal.cpp | |||
| ExpandConstantExpr.cpp | |||
| ExpandCtors.cpp | |||
| ExpandGetElementPtr.cpp | |||
| ExpandIndirectBr.cpp | |||
| ExpandLargeIntegers.cpp | |||
| ExpandShuffleVector.cpp | |||
| ExpandSmallArguments.cpp | |||
| ExpandStructRegs.cpp | |||
| ExpandTls.cpp | |||
| ExpandTlsConstantExpr.cpp | |||
| ExpandUtils.cpp | |||
| ExpandVarArgs.cpp | |||
| FixVectorLoadStoreAlignment.cpp | |||
| FlattenGlobals.cpp | |||
| SimplifiedFuncTypeMap.cpp | |||
| GlobalCleanup.cpp | |||
| GlobalizeConstantVectors.cpp | |||
| InsertDivideCheck.cpp | |||
| InternalizeUsedGlobals.cpp | |||
| NormalizeAlignment.cpp | |||
| PNaClSjLjEH.cpp | |||
| PromoteI1Ops.cpp | |||
| PromoteIntegers.cpp | |||
| RemoveAsmMemory.cpp | |||
| ReplacePtrsWithInts.cpp | |||
| ResolvePNaClIntrinsics.cpp | |||
| RewriteAtomics.cpp | |||
| RewriteLLVMIntrinsics.cpp | |||
| RewritePNaClLibraryCalls.cpp | |||
| SimplifyAllocas.cpp | |||
| SimplifyStructRegSignatures.cpp | |||
| StripAttributes.cpp | |||
| StripMetadata.cpp | |||
| # Emscripten files: | |||
| ExpandI64.cpp | |||
| ExpandInsertExtractElement.cpp | |||
| LowerEmAsyncify.cpp | |||
| LowerEmExceptionsPass.cpp | |||
| LowerEmSetjmp.cpp | |||
| NoExitRuntime.cpp | |||
| # Emscripten files end. | |||
| ) | |||
|
|
|||
| add_dependencies(LLVMPNaClTransforms intrinsics_gen) | |||
| @@ -0,0 +1,100 @@ | |||
| //===- CanonicalizeMemIntrinsics.cpp - Make memcpy's "len" arg consistent--===// | |||
| // | |||
| // The LLVM Compiler Infrastructure | |||
| // | |||
| // This file is distributed under the University of Illinois Open Source | |||
| // License. See LICENSE.TXT for details. | |||
| // | |||
| //===----------------------------------------------------------------------===// | |||
| // | |||
| // This pass canonicalizes uses of the llvm.memset, llvm.memcpy and | |||
| // llvm.memmove intrinsics so that the variants with 64-bit "len" | |||
| // arguments aren't used, and the 32-bit variants are used instead. | |||
| // | |||
| // This means the PNaCl translator won't need to handle two versions | |||
| // of each of these intrinsics, and it won't need to do any implicit | |||
| // truncations from 64-bit to 32-bit. | |||
| // | |||
| //===----------------------------------------------------------------------===// | |||
|
|
|||
| #include "llvm/IR/Function.h" | |||
| #include "llvm/IR/IRBuilder.h" | |||
| #include "llvm/IR/Instructions.h" | |||
| #include "llvm/IR/Intrinsics.h" | |||
| #include "llvm/IR/Module.h" | |||
| #include "llvm/Pass.h" | |||
| #include "llvm/Transforms/NaCl.h" | |||
|
|
|||
| using namespace llvm; | |||
|
|
|||
| namespace { | |||
| // This is a ModulePass because that makes it easier to find all | |||
| // uses of intrinsics efficiently. | |||
| class CanonicalizeMemIntrinsics : public ModulePass { | |||
| public: | |||
| static char ID; // Pass identification, replacement for typeid | |||
| CanonicalizeMemIntrinsics() : ModulePass(ID) { | |||
| initializeCanonicalizeMemIntrinsicsPass(*PassRegistry::getPassRegistry()); | |||
| } | |||
|
|
|||
| virtual bool runOnModule(Module &M); | |||
| }; | |||
| } | |||
|
|
|||
| char CanonicalizeMemIntrinsics::ID = 0; | |||
| INITIALIZE_PASS(CanonicalizeMemIntrinsics, "canonicalize-mem-intrinsics", | |||
| "Make memcpy() et al's \"len\" argument consistent", | |||
| false, false) | |||
|
|
|||
| static bool expandIntrinsic(Module *M, Intrinsic::ID ID) { | |||
| SmallVector<Type *, 3> Types; | |||
| Types.push_back(Type::getInt8PtrTy(M->getContext())); | |||
| if (ID != Intrinsic::memset) | |||
| Types.push_back(Type::getInt8PtrTy(M->getContext())); | |||
| unsigned LengthTypePos = Types.size(); | |||
| Types.push_back(Type::getInt64Ty(M->getContext())); | |||
|
|
|||
| std::string OldName = Intrinsic::getName(ID, Types); | |||
| Function *OldIntrinsic = M->getFunction(OldName); | |||
| if (!OldIntrinsic) | |||
| return false; | |||
|
|
|||
| Types[LengthTypePos] = Type::getInt32Ty(M->getContext()); | |||
| Function *NewIntrinsic = Intrinsic::getDeclaration(M, ID, Types); | |||
|
|
|||
| SmallVector<CallInst *, 64> Calls; | |||
| for (User *U : OldIntrinsic->users()) { | |||
| if (CallInst *Call = dyn_cast<CallInst>(U)) | |||
| Calls.push_back(Call); | |||
| else | |||
| report_fatal_error("CanonicalizeMemIntrinsics: Taking the address of an " | |||
| "intrinsic is not allowed: " + | |||
| OldName); | |||
| } | |||
|
|
|||
| for (CallInst *Call : Calls) { | |||
| // This temporarily leaves Call non-well-typed. | |||
| Call->setCalledFunction(NewIntrinsic); | |||
| // Truncate the "len" argument. No overflow check. | |||
| IRBuilder<> Builder(Call); | |||
| Value *Length = Builder.CreateTrunc(Call->getArgOperand(2), | |||
| Type::getInt32Ty(M->getContext()), | |||
| "mem_len_truncate"); | |||
| Call->setArgOperand(2, Length); | |||
| } | |||
|
|
|||
| OldIntrinsic->eraseFromParent(); | |||
| return true; | |||
| } | |||
|
|
|||
| bool CanonicalizeMemIntrinsics::runOnModule(Module &M) { | |||
| bool Changed = false; | |||
| Changed |= expandIntrinsic(&M, Intrinsic::memset); | |||
| Changed |= expandIntrinsic(&M, Intrinsic::memcpy); | |||
| Changed |= expandIntrinsic(&M, Intrinsic::memmove); | |||
| return Changed; | |||
| } | |||
|
|
|||
| ModulePass *llvm::createCanonicalizeMemIntrinsicsPass() { | |||
| return new CanonicalizeMemIntrinsics(); | |||
| } | |||
| @@ -0,0 +1,48 @@ | |||
| //===- CleanupUsedGlobalsMetadata.cpp - Cleanup llvm.used -----------------===// | |||
| // | |||
| // The LLVM Compiler Infrastructure | |||
| // | |||
| // This file is distributed under the University of Illinois Open Source | |||
| // License. See LICENSE.TXT for details. | |||
| // | |||
| // ===---------------------------------------------------------------------===// | |||
| // | |||
| // Remove llvm.used metadata. | |||
| // | |||
| //===----------------------------------------------------------------------===// | |||
|
|
|||
| #include "llvm/IR/Module.h" | |||
| #include "llvm/Pass.h" | |||
| #include "llvm/Transforms/NaCl.h" | |||
|
|
|||
| using namespace llvm; | |||
|
|
|||
| namespace { | |||
| class CleanupUsedGlobalsMetadata : public ModulePass { | |||
| public: | |||
| static char ID; | |||
| CleanupUsedGlobalsMetadata() : ModulePass(ID) { | |||
| initializeCleanupUsedGlobalsMetadataPass(*PassRegistry::getPassRegistry()); | |||
| } | |||
| bool runOnModule(Module &M) override; | |||
| }; | |||
| } | |||
|
|
|||
| char CleanupUsedGlobalsMetadata::ID = 0; | |||
| INITIALIZE_PASS(CleanupUsedGlobalsMetadata, "cleanup-used-globals-metadata", | |||
| "Removes llvm.used metadata.", false, false) | |||
|
|
|||
| bool CleanupUsedGlobalsMetadata::runOnModule(Module &M) { | |||
| bool Modified = false; | |||
|
|
|||
| if (auto *GV = M.getNamedGlobal("llvm.used")) { | |||
| GV->eraseFromParent(); | |||
| Modified = true; | |||
| } | |||
|
|
|||
| return Modified; | |||
| } | |||
|
|
|||
| ModulePass *llvm::createCleanupUsedGlobalsMetadataPass() { | |||
| return new CleanupUsedGlobalsMetadata(); | |||
| } | |||
| @@ -0,0 +1,180 @@ | |||
| //===- ConstantInsertExtractElementIndex.cpp - Insert/Extract element -----===// | |||
| // | |||
| // The LLVM Compiler Infrastructure | |||
| // | |||
| // This file is distributed under the University of Illinois Open Source | |||
| // License. See LICENSE.TXT for details. | |||
| // | |||
| //===----------------------------------------------------------------------===// | |||
| // | |||
| // Transform all InsertElement and ExtractElement with non-constant or | |||
| // out-of-bounds indices into either in-bounds constant accesses or | |||
| // stack accesses. This moves all undefined behavior to the stack, | |||
| // making InsertElement and ExtractElement well-defined. | |||
| // | |||
| //===----------------------------------------------------------------------===// | |||
|
|
|||
| #include "llvm/IR/DataLayout.h" | |||
| #include "llvm/IR/IRBuilder.h" | |||
| #include "llvm/IR/Instruction.h" | |||
| #include "llvm/IR/Instructions.h" | |||
| #include "llvm/IR/Module.h" | |||
| #include "llvm/Pass.h" | |||
| #include "llvm/Transforms/NaCl.h" | |||
|
|
|||
| #include <algorithm> | |||
|
|
|||
| using namespace llvm; | |||
|
|
|||
| namespace { | |||
| class ConstantInsertExtractElementIndex : public BasicBlockPass { | |||
| public: | |||
| static char ID; // Pass identification, replacement for typeid | |||
| ConstantInsertExtractElementIndex() : BasicBlockPass(ID), M(0), DL(0) { | |||
| initializeConstantInsertExtractElementIndexPass( | |||
| *PassRegistry::getPassRegistry()); | |||
| } | |||
| using BasicBlockPass::doInitialization; | |||
| bool doInitialization(Module &Mod) override { | |||
| M = &Mod; | |||
| return false; // Unchanged. | |||
| } | |||
| bool runOnBasicBlock(BasicBlock &BB) override; | |||
|
|
|||
| private: | |||
| typedef SmallVector<Instruction *, 8> Instructions; | |||
| const Module *M; | |||
| const DataLayout *DL; | |||
|
|
|||
| void findNonConstantInsertExtractElements( | |||
| const BasicBlock &BB, Instructions &OutOfRangeConstantIndices, | |||
| Instructions &NonConstantVectorIndices) const; | |||
| void fixOutOfRangeConstantIndices(BasicBlock &BB, | |||
| const Instructions &Instrs) const; | |||
| void fixNonConstantVectorIndices(BasicBlock &BB, | |||
| const Instructions &Instrs) const; | |||
| }; | |||
|
|
|||
| /// Number of elements in a vector instruction. | |||
| unsigned vectorNumElements(const Instruction *I) { | |||
| return cast<VectorType>(I->getOperand(0)->getType())->getNumElements(); | |||
| } | |||
|
|
|||
| /// Get the index of an InsertElement or ExtractElement instruction, or null. | |||
| Value *getInsertExtractElementIdx(const Instruction *I) { | |||
| switch (I->getOpcode()) { | |||
| default: return NULL; | |||
| case Instruction::InsertElement: return I->getOperand(2); | |||
| case Instruction::ExtractElement: return I->getOperand(1); | |||
| } | |||
| } | |||
|
|
|||
| /// Set the index of an InsertElement or ExtractElement instruction. | |||
| void setInsertExtractElementIdx(Instruction *I, Value *NewIdx) { | |||
| switch (I->getOpcode()) { | |||
| default: | |||
| llvm_unreachable( | |||
| "expected instruction to be InsertElement or ExtractElement"); | |||
| case Instruction::InsertElement: I->setOperand(2, NewIdx); break; | |||
| case Instruction::ExtractElement: I->setOperand(1, NewIdx); break; | |||
| } | |||
| } | |||
| } // anonymous namespace | |||
|
|
|||
| char ConstantInsertExtractElementIndex::ID = 0; | |||
| INITIALIZE_PASS( | |||
| ConstantInsertExtractElementIndex, "constant-insert-extract-element-index", | |||
| "Force insert and extract vector element to always be in bounds", false, | |||
| false) | |||
|
|
|||
| void ConstantInsertExtractElementIndex::findNonConstantInsertExtractElements( | |||
| const BasicBlock &BB, Instructions &OutOfRangeConstantIndices, | |||
| Instructions &NonConstantVectorIndices) const { | |||
| for (BasicBlock::const_iterator BBI = BB.begin(), BBE = BB.end(); BBI != BBE; | |||
| ++BBI) { | |||
| const Instruction *I = &*BBI; | |||
| if (Value *Idx = getInsertExtractElementIdx(I)) { | |||
| if (ConstantInt *CI = dyn_cast<ConstantInt>(Idx)) { | |||
| if (!CI->getValue().ult(vectorNumElements(I))) | |||
| OutOfRangeConstantIndices.push_back(const_cast<Instruction *>(I)); | |||
| } else | |||
| NonConstantVectorIndices.push_back(const_cast<Instruction *>(I)); | |||
| } | |||
| } | |||
| } | |||
|
|
|||
| void ConstantInsertExtractElementIndex::fixOutOfRangeConstantIndices( | |||
| BasicBlock &BB, const Instructions &Instrs) const { | |||
| for (Instructions::const_iterator IB = Instrs.begin(), IE = Instrs.end(); | |||
| IB != IE; ++IB) { | |||
| Instruction *I = *IB; | |||
| const APInt &Idx = | |||
| cast<ConstantInt>(getInsertExtractElementIdx(I))->getValue(); | |||
| APInt NumElements = APInt(Idx.getBitWidth(), vectorNumElements(I)); | |||
| APInt NewIdx = Idx.urem(NumElements); | |||
| setInsertExtractElementIdx(I, ConstantInt::get(M->getContext(), NewIdx)); | |||
| } | |||
| } | |||
|
|
|||
| void ConstantInsertExtractElementIndex::fixNonConstantVectorIndices( | |||
| BasicBlock &BB, const Instructions &Instrs) const { | |||
| for (Instructions::const_iterator IB = Instrs.begin(), IE = Instrs.end(); | |||
| IB != IE; ++IB) { | |||
| Instruction *I = *IB; | |||
| Value *Vec = I->getOperand(0); | |||
| Value *Idx = getInsertExtractElementIdx(I); | |||
| VectorType *VecTy = cast<VectorType>(Vec->getType()); | |||
| Type *ElemTy = VecTy->getElementType(); | |||
| unsigned ElemAlign = DL->getPrefTypeAlignment(ElemTy); | |||
| unsigned VecAlign = std::max(ElemAlign, DL->getPrefTypeAlignment(VecTy)); | |||
|
|
|||
| IRBuilder<> IRB(I); | |||
| AllocaInst *Alloca = IRB.CreateAlloca( | |||
| ElemTy, ConstantInt::get(Type::getInt32Ty(M->getContext()), | |||
| vectorNumElements(I))); | |||
| Alloca->setAlignment(VecAlign); | |||
| Value *AllocaAsVec = IRB.CreateBitCast(Alloca, VecTy->getPointerTo()); | |||
| IRB.CreateAlignedStore(Vec, AllocaAsVec, Alloca->getAlignment()); | |||
| Value *GEP = IRB.CreateGEP(Alloca, Idx); | |||
|
|
|||
| Value *Res; | |||
| switch (I->getOpcode()) { | |||
| default: | |||
| llvm_unreachable("expected InsertElement or ExtractElement"); | |||
| case Instruction::InsertElement: | |||
| IRB.CreateAlignedStore(I->getOperand(1), GEP, ElemAlign); | |||
| Res = IRB.CreateAlignedLoad(AllocaAsVec, Alloca->getAlignment()); | |||
| break; | |||
| case Instruction::ExtractElement: | |||
| Res = IRB.CreateAlignedLoad(GEP, ElemAlign); | |||
| break; | |||
| } | |||
|
|
|||
| I->replaceAllUsesWith(Res); | |||
| I->eraseFromParent(); | |||
| } | |||
| } | |||
|
|
|||
| bool ConstantInsertExtractElementIndex::runOnBasicBlock(BasicBlock &BB) { | |||
| bool Changed = false; | |||
| if (!DL) | |||
| DL = &BB.getParent()->getParent()->getDataLayout(); | |||
| Instructions OutOfRangeConstantIndices; | |||
| Instructions NonConstantVectorIndices; | |||
|
|
|||
| findNonConstantInsertExtractElements(BB, OutOfRangeConstantIndices, | |||
| NonConstantVectorIndices); | |||
| if (!OutOfRangeConstantIndices.empty()) { | |||
| Changed = true; | |||
| fixOutOfRangeConstantIndices(BB, OutOfRangeConstantIndices); | |||
| } | |||
| if (!NonConstantVectorIndices.empty()) { | |||
| Changed = true; | |||
| fixNonConstantVectorIndices(BB, NonConstantVectorIndices); | |||
| } | |||
| return Changed; | |||
| } | |||
|
|
|||
| BasicBlockPass *llvm::createConstantInsertExtractElementIndexPass() { | |||
| return new ConstantInsertExtractElementIndex(); | |||
| } | |||
| @@ -0,0 +1,291 @@ | |||
| //===- ExceptionInfoWriter.cpp - Generate C++ exception info for PNaCl-----===// | |||
| // | |||
| // The LLVM Compiler Infrastructure | |||
| // | |||
| // This file is distributed under the University of Illinois Open Source | |||
| // License. See LICENSE.TXT for details. | |||
| // | |||
| //===----------------------------------------------------------------------===// | |||
| // | |||
| // The ExceptionInfoWriter class converts the clauses of a | |||
| // "landingpad" instruction into data tables stored in global | |||
| // variables. These tables are interpreted by PNaCl's C++ runtime | |||
| // library (either libsupc++ or libcxxabi), which is linked into a | |||
| // pexe. | |||
| // | |||
| // This is similar to the lowering that the LLVM backend does to | |||
| // convert landingpad clauses into ".gcc_except_table" sections. The | |||
| // difference is that ExceptionInfoWriter is an IR-to-IR | |||
| // transformation that runs on the PNaCl user toolchain side. The | |||
| // format it produces is not part of PNaCl's stable ABI; the PNaCl | |||
| // translator and LLVM backend do not know about this format. | |||
| // | |||
| // Encoding: | |||
| // | |||
| // A landingpad instruction contains a list of clauses. | |||
| // ExceptionInfoWriter encodes each clause as a 32-bit "clause ID". A | |||
| // clause is one of the following forms: | |||
| // | |||
| // 1) "catch i8* @ExcType" | |||
| // * This clause means that the landingpad should be entered if | |||
| // the C++ exception being thrown has type @ExcType (or a | |||
| // subtype of @ExcType). @ExcType is a pointer to the | |||
| // std::type_info object (an RTTI object) for the C++ exception | |||
| // type. | |||
| // * Clang generates this for a "catch" block in the C++ source. | |||
| // * @ExcType is NULL for "catch (...)" (catch-all) blocks. | |||
| // * This is encoded as the "type ID" for @ExcType, defined below, | |||
| // which is a positive integer. | |||
| // | |||
| // 2) "filter [i8* @ExcType1, ..., i8* @ExcTypeN]" | |||
| // * This clause means that the landingpad should be entered if | |||
| // the C++ exception being thrown *doesn't* match any of the | |||
| // types in the list (which are again specified as | |||
| // std::type_info pointers). | |||
| // * Clang uses this to implement C++ exception specifications, e.g. | |||
| // void foo() throw(ExcType1, ..., ExcTypeN) { ... } | |||
| // * This is encoded as the filter ID, X, where X < 0, and | |||
| // &__pnacl_eh_filter_table[-X-1] points to a 0-terminated | |||
| // array of integer "type IDs". | |||
| // | |||
| // 3) "cleanup" | |||
| // * This means that the landingpad should always be entered. | |||
| // * Clang uses this for calling objects' destructors. | |||
| // * This is encoded as 0. | |||
| // * The runtime may treat "cleanup" differently from "catch i8* | |||
| // null" (a catch-all). In C++, if an unhandled exception | |||
| // occurs, the language runtime may abort execution without | |||
| // running any destructors. The runtime may implement this by | |||
| // searching for a matching non-"cleanup" clause, and aborting | |||
| // if it does not find one, before entering any landingpad | |||
| // blocks. | |||
| // | |||
| // The "type ID" for a type @ExcType is a 1-based index into the array | |||
| // __pnacl_eh_type_table[]. That is, the type ID is a value X such | |||
| // that __pnacl_eh_type_table[X-1] == @ExcType, and X >= 1. | |||
| // | |||
| // ExceptionInfoWriter generates the following data structures: | |||
| // | |||
| // struct action_table_entry { | |||
| // int32_t clause_id; | |||
| // uint32_t next_clause_list_id; | |||
| // }; | |||
| // | |||
| // // Represents singly linked lists of clauses. | |||
| // extern const struct action_table_entry __pnacl_eh_action_table[]; | |||
| // | |||
| // // Allows std::type_infos to be represented using small integer IDs. | |||
| // extern std::type_info *const __pnacl_eh_type_table[]; | |||
| // | |||
| // // Used to represent type arrays for "filter" clauses. | |||
| // extern const uint32_t __pnacl_eh_filter_table[]; | |||
| // | |||
| // A "clause list ID" is either: | |||
| // * 0, representing the empty list; or | |||
| // * an index into __pnacl_eh_action_table[] with 1 added, which | |||
| // specifies a node in the clause list. | |||
| // | |||
| // Example: | |||
| // | |||
| // std::type_info *const __pnacl_eh_type_table[] = { | |||
| // // defines type ID 1 == ExcA and clause ID 1 == "catch ExcA" | |||
| // &typeinfo(ExcA), | |||
| // // defines type ID 2 == ExcB and clause ID 2 == "catch ExcB" | |||
| // &typeinfo(ExcB), | |||
| // // defines type ID 3 == ExcC and clause ID 3 == "catch ExcC" | |||
| // &typeinfo(ExcC), | |||
| // }; | |||
| // | |||
| // const uint32_t __pnacl_eh_filter_table[] = { | |||
| // 1, // refers to ExcA; defines clause ID -1 as "filter [ExcA, ExcB]" | |||
| // 2, // refers to ExcB; defines clause ID -2 as "filter [ExcB]" | |||
| // 0, // list terminator; defines clause ID -3 as "filter []" | |||
| // 3, // refers to ExcC; defines clause ID -4 as "filter [ExcC]" | |||
| // 0, // list terminator; defines clause ID -5 as "filter []" | |||
| // }; | |||
| // | |||
| // const struct action_table_entry __pnacl_eh_action_table[] = { | |||
| // // defines clause list ID 1: | |||
| // { | |||
| // -4, // "filter [ExcC]" | |||
| // 0, // end of list (no more actions) | |||
| // }, | |||
| // // defines clause list ID 2: | |||
| // { | |||
| // -1, // "filter [ExcA, ExcB]" | |||
| // 1, // else go to clause list ID 1 | |||
| // }, | |||
| // // defines clause list ID 3: | |||
| // { | |||
| // 2, // "catch ExcB" | |||
| // 2, // else go to clause list ID 2 | |||
| // }, | |||
| // // defines clause list ID 4: | |||
| // { | |||
| // 1, // "catch ExcA" | |||
| // 3, // else go to clause list ID 3 | |||
| // }, | |||
| // }; | |||
| // | |||
| // So if a landingpad contains the clause list: | |||
| // [catch ExcA, | |||
| // catch ExcB, | |||
| // filter [ExcA, ExcB], | |||
| // filter [ExcC]] | |||
| // then this can be represented as clause list ID 4 using the tables above. | |||
| // | |||
| // The C++ runtime library checks the clauses in order to decide | |||
| // whether to enter the landingpad. If a clause matches, the | |||
| // landingpad BasicBlock is passed the clause ID. The landingpad code | |||
| // can use the clause ID to decide which C++ catch() block (if any) to | |||
| // execute. | |||
| // | |||
| // The purpose of these exception tables is to keep code sizes | |||
| // relatively small. The landingpad code only needs to check a small | |||
| // integer clause ID, rather than having to call a function to check | |||
| // whether the C++ exception matches a type. | |||
| // | |||
| // ExceptionInfoWriter's encoding corresponds loosely to the format of | |||
| // GCC's .gcc_except_table sections. One difference is that | |||
| // ExceptionInfoWriter writes fixed-width 32-bit integers, whereas | |||
| // .gcc_except_table uses variable-length LEB128 encodings. We could | |||
| // switch to LEB128 to save space in the future. | |||
| // | |||
| //===----------------------------------------------------------------------===// | |||
|
|
|||
| #include "ExceptionInfoWriter.h" | |||
| #include "llvm/IR/Constants.h" | |||
| #include "llvm/Support/raw_ostream.h" | |||
|
|
|||
| using namespace llvm; | |||
|
|
|||
| ExceptionInfoWriter::ExceptionInfoWriter(LLVMContext *Context): | |||
| Context(Context) { | |||
| Type *I32 = Type::getInt32Ty(*Context); | |||
| Type *Fields[] = { I32, I32 }; | |||
| ActionTableEntryTy = StructType::create(Fields, "action_table_entry"); | |||
| } | |||
|
|
|||
| unsigned ExceptionInfoWriter::getIDForExceptionType(Value *ExcTy) { | |||
| Constant *ExcTyConst = dyn_cast<Constant>(ExcTy); | |||
| if (!ExcTyConst) | |||
| report_fatal_error("Exception type not a constant"); | |||
|
|
|||
| // Reuse existing ID if one has already been assigned. | |||
| TypeTableIDMapType::iterator Iter = TypeTableIDMap.find(ExcTyConst); | |||
| if (Iter != TypeTableIDMap.end()) | |||
| return Iter->second; | |||
|
|
|||
| unsigned Index = TypeTableData.size() + 1; | |||
| TypeTableIDMap[ExcTyConst] = Index; | |||
| TypeTableData.push_back(ExcTyConst); | |||
| return Index; | |||
| } | |||
|
|
|||
| unsigned ExceptionInfoWriter::getIDForClauseListNode( | |||
| unsigned ClauseID, unsigned NextClauseListID) { | |||
| // Reuse existing ID if one has already been assigned. | |||
| ActionTableEntry Key(ClauseID, NextClauseListID); | |||
| ActionTableIDMapType::iterator Iter = ActionTableIDMap.find(Key); | |||
| if (Iter != ActionTableIDMap.end()) | |||
| return Iter->second; | |||
|
|
|||
| Type *I32 = Type::getInt32Ty(*Context); | |||
| Constant *Fields[] = { ConstantInt::get(I32, ClauseID), | |||
| ConstantInt::get(I32, NextClauseListID) }; | |||
| Constant *Entry = ConstantStruct::get(ActionTableEntryTy, Fields); | |||
|
|
|||
| // Add 1 so that the empty list can be represented as 0. | |||
| unsigned ClauseListID = ActionTableData.size() + 1; | |||
| ActionTableIDMap[Key] = ClauseListID; | |||
| ActionTableData.push_back(Entry); | |||
| return ClauseListID; | |||
| } | |||
|
|
|||
| unsigned ExceptionInfoWriter::getIDForFilterClause(Value *Filter) { | |||
| unsigned FilterClauseID = -(FilterTableData.size() + 1); | |||
| Type *I32 = Type::getInt32Ty(*Context); | |||
| ArrayType *ArrayTy = dyn_cast<ArrayType>(Filter->getType()); | |||
| if (!ArrayTy) | |||
| report_fatal_error("Landingpad filter clause is not of array type"); | |||
| unsigned FilterLength = ArrayTy->getNumElements(); | |||
| // Don't try the dyn_cast if the FilterLength is zero, because Array | |||
| // could be a zeroinitializer. | |||
| if (FilterLength > 0) { | |||
| ConstantArray *Array = dyn_cast<ConstantArray>(Filter); | |||
| if (!Array) | |||
| report_fatal_error("Landingpad filter clause is not a ConstantArray"); | |||
| for (unsigned I = 0; I < FilterLength; ++I) { | |||
| unsigned TypeID = getIDForExceptionType(Array->getOperand(I)); | |||
| assert(TypeID > 0); | |||
| FilterTableData.push_back(ConstantInt::get(I32, TypeID)); | |||
| } | |||
| } | |||
| // Add array terminator. | |||
| FilterTableData.push_back(ConstantInt::get(I32, 0)); | |||
| return FilterClauseID; | |||
| } | |||
|
|
|||
| unsigned ExceptionInfoWriter::getIDForLandingPadClauseList(LandingPadInst *LP) { | |||
| unsigned NextClauseListID = 0; // ID for empty list. | |||
|
|
|||
| if (LP->isCleanup()) { | |||
| // Add cleanup clause at the end of the list. | |||
| NextClauseListID = getIDForClauseListNode(0, NextClauseListID); | |||
| } | |||
|
|
|||
| for (int I = (int) LP->getNumClauses() - 1; I >= 0; --I) { | |||
| unsigned ClauseID; | |||
| if (LP->isCatch(I)) { | |||
| ClauseID = getIDForExceptionType(LP->getClause(I)); | |||
| } else if (LP->isFilter(I)) { | |||
| ClauseID = getIDForFilterClause(LP->getClause(I)); | |||
| } else { | |||
| report_fatal_error("Unknown kind of landingpad clause"); | |||
| } | |||
| assert(ClauseID > 0); | |||
| NextClauseListID = getIDForClauseListNode(ClauseID, NextClauseListID); | |||
| } | |||
|
|
|||
| return NextClauseListID; | |||
| } | |||
|
|
|||
| static void defineArray(Module *M, const char *Name, | |||
| const SmallVectorImpl<Constant *> &Elements, | |||
| Type *ElementType) { | |||
| ArrayType *ArrayTy = ArrayType::get(ElementType, Elements.size()); | |||
| Constant *ArrayData = ConstantArray::get(ArrayTy, Elements); | |||
| GlobalVariable *OldGlobal = M->getGlobalVariable(Name); | |||
| if (OldGlobal) { | |||
| if (OldGlobal->hasInitializer()) { | |||
| report_fatal_error(std::string("Variable ") + Name + | |||
| " already has an initializer"); | |||
| } | |||
| Constant *NewGlobal = new GlobalVariable( | |||
| *M, ArrayTy, /* isConstant= */ true, | |||
| GlobalValue::InternalLinkage, ArrayData); | |||
| NewGlobal->takeName(OldGlobal); | |||
| OldGlobal->replaceAllUsesWith(ConstantExpr::getBitCast( | |||
| NewGlobal, OldGlobal->getType())); | |||
| OldGlobal->eraseFromParent(); | |||
| } else { | |||
| if (Elements.size() > 0) { | |||
| // This warning could happen for a program that does not link | |||
| // against the C++ runtime libraries. Such a program might | |||
| // contain "invoke" instructions but never throw any C++ | |||
| // exceptions. | |||
| errs() << "Warning: Variable " << Name << " not referenced\n"; | |||
| } | |||
| } | |||
| } | |||
|
|
|||
| void ExceptionInfoWriter::defineGlobalVariables(Module *M) { | |||
| defineArray(M, "__pnacl_eh_type_table", TypeTableData, | |||
| Type::getInt8PtrTy(M->getContext())); | |||
|
|
|||
| defineArray(M, "__pnacl_eh_action_table", ActionTableData, | |||
| ActionTableEntryTy); | |||
|
|
|||
| defineArray(M, "__pnacl_eh_filter_table", FilterTableData, | |||
| Type::getInt32Ty(M->getContext())); | |||
| } | |||
| @@ -0,0 +1,71 @@ | |||
| //===-- ExceptionInfoWriter.h - Generate C++ exception info------*- C++ -*-===// | |||
| // | |||
| // The LLVM Compiler Infrastructure | |||
| // | |||
| // This file is distributed under the University of Illinois Open Source | |||
| // License. See LICENSE.TXT for details. | |||
| // | |||
| //===----------------------------------------------------------------------===// | |||
|
|
|||
| #ifndef TRANSFORMS_NACL_EXCEPTIONINFOWRITER_H | |||
| #define TRANSFORMS_NACL_EXCEPTIONINFOWRITER_H | |||
|
|
|||
| #include "llvm/ADT/DenseMap.h" | |||
| #include "llvm/IR/Instructions.h" | |||
| #include "llvm/IR/Module.h" | |||
|
|
|||
| namespace llvm { | |||
|
|
|||
| // The ExceptionInfoWriter class converts the clauses of a | |||
| // "landingpad" instruction into data tables stored in global | |||
| // variables, which are interpreted by PNaCl's C++ runtime library. | |||
| // See ExceptionInfoWriter.cpp for a full description. | |||
| class ExceptionInfoWriter { | |||
| LLVMContext *Context; | |||
| StructType *ActionTableEntryTy; | |||
|
|
|||
| // Data for populating __pnacl_eh_type_table[], which is an array of | |||
| // std::type_info* pointers. Each of these pointers represents a | |||
| // C++ exception type. | |||
| SmallVector<Constant *, 10> TypeTableData; | |||
| // Mapping from std::type_info* pointer to type ID (index in | |||
| // TypeTableData). | |||
| typedef DenseMap<Constant *, unsigned> TypeTableIDMapType; | |||
| TypeTableIDMapType TypeTableIDMap; | |||
|
|
|||
| // Data for populating __pnacl_eh_action_table[], which is an array | |||
| // of pairs. | |||
| SmallVector<Constant *, 10> ActionTableData; | |||
| // Pair of (clause_id, clause_list_id). | |||
| typedef std::pair<unsigned, unsigned> ActionTableEntry; | |||
| // Mapping from (clause_id, clause_list_id) to clause_id (index in | |||
| // ActionTableData). | |||
| typedef DenseMap<ActionTableEntry, unsigned> ActionTableIDMapType; | |||
| ActionTableIDMapType ActionTableIDMap; | |||
|
|
|||
| // Data for populating __pnacl_eh_filter_table[], which is an array | |||
| // of integers. | |||
| SmallVector<Constant *, 10> FilterTableData; | |||
|
|
|||
| // Get the interned ID for an action. | |||
| unsigned getIDForClauseListNode(unsigned ClauseID, unsigned NextClauseListID); | |||
|
|
|||
| // Get the clause ID for a "filter" clause. | |||
| unsigned getIDForFilterClause(Value *Filter); | |||
|
|
|||
| public: | |||
| explicit ExceptionInfoWriter(LLVMContext *Context); | |||
|
|
|||
| // Get the interned type ID (a small integer) for a C++ exception type. | |||
| unsigned getIDForExceptionType(Value *Ty); | |||
|
|
|||
| // Get the clause list ID for a landingpad's clause list. | |||
| unsigned getIDForLandingPadClauseList(LandingPadInst *LP); | |||
|
|
|||
| // Add the exception info tables to the module. | |||
| void defineGlobalVariables(Module *M); | |||
| }; | |||
|
|
|||
| } | |||
|
|
|||
| #endif | |||
| @@ -0,0 +1,234 @@ | |||
| //===- ExpandArithWithOverflow.cpp - Expand out uses of *.with.overflow----===// | |||
| // | |||
| // The LLVM Compiler Infrastructure | |||
| // | |||
| // This file is distributed under the University of Illinois Open Source | |||
| // License. See LICENSE.TXT for details. | |||
| // | |||
| //===----------------------------------------------------------------------===// | |||
| // | |||
| // The llvm.*.with.overflow.*() intrinsics are awkward for PNaCl support because | |||
| // they return structs, and we want to omit struct types from IR in PNaCl's | |||
| // stable ABI. | |||
| // | |||
| // However, llvm.{umul,uadd}.with.overflow.*() are used by Clang to implement an | |||
| // overflow check for C++'s new[] operator, and {sadd,ssub} are used by | |||
| // ubsan. This pass expands out these uses so that PNaCl does not have to | |||
| // support *.with.overflow as part of PNaCl's stable ABI. | |||
| // | |||
| //===----------------------------------------------------------------------===// | |||
|
|
|||
| #include "llvm/ADT/APInt.h" | |||
| #include "llvm/IR/Constants.h" | |||
| #include "llvm/IR/Function.h" | |||
| #include "llvm/IR/IRBuilder.h" | |||
| #include "llvm/IR/Instructions.h" | |||
| #include "llvm/IR/Intrinsics.h" | |||
| #include "llvm/IR/Module.h" | |||
| #include "llvm/Pass.h" | |||
| #include "llvm/Support/Debug.h" | |||
| #include "llvm/Support/raw_ostream.h" | |||
| #include "llvm/Transforms/NaCl.h" | |||
|
|
|||
| #define DEBUG_TYPE "expand-arith-with-overflow" | |||
|
|
|||
| using namespace llvm; | |||
|
|
|||
| namespace { | |||
| class ExpandArithWithOverflow : public ModulePass { | |||
| public: | |||
| static char ID; | |||
| ExpandArithWithOverflow() : ModulePass(ID) { | |||
| initializeExpandArithWithOverflowPass(*PassRegistry::getPassRegistry()); | |||
| } | |||
| virtual bool runOnModule(Module &M); | |||
| }; | |||
| } | |||
|
|
|||
| char ExpandArithWithOverflow::ID = 0; | |||
| INITIALIZE_PASS(ExpandArithWithOverflow, "expand-arith-with-overflow", | |||
| "Expand out some uses of *.with.overflow intrinsics", false, | |||
| false) | |||
|
|
|||
| enum class ExpandArith { Add, Sub, Mul }; | |||
| static const ExpandArith ExpandArithOps[] = {ExpandArith::Add, ExpandArith::Sub, | |||
| ExpandArith::Mul}; | |||
|
|
|||
| static Intrinsic::ID getID(ExpandArith Op, bool Signed) { | |||
| static const Intrinsic::ID IDs[][2] = { | |||
| // Unsigned Signed | |||
| /* Add */ {Intrinsic::uadd_with_overflow, Intrinsic::sadd_with_overflow}, | |||
| /* Sub */ {Intrinsic::usub_with_overflow, Intrinsic::ssub_with_overflow}, | |||
| /* Mul */ {Intrinsic::umul_with_overflow, Intrinsic::smul_with_overflow}, | |||
| }; | |||
| return IDs[(size_t)Op][Signed]; | |||
| } | |||
|
|
|||
| static Instruction::BinaryOps getOpcode(ExpandArith Op) { | |||
| static const Instruction::BinaryOps Opcodes[] = { | |||
| Instruction::Add, Instruction::Sub, Instruction::Mul, | |||
| }; | |||
| return Opcodes[(size_t)Op]; | |||
| } | |||
|
|
|||
| static Value *CreateInsertValue(IRBuilder<> *IRB, Value *StructVal, | |||
| unsigned Index, Value *Field, | |||
| Instruction *BasedOn) { | |||
| SmallVector<unsigned, 1> EVIndexes(1, Index); | |||
| return IRB->CreateInsertValue(StructVal, Field, EVIndexes, | |||
| BasedOn->getName() + ".insert"); | |||
| } | |||
|
|
|||
| static bool Expand(Module *M, unsigned Bits, ExpandArith Op, bool Signed) { | |||
| IntegerType *IntTy = IntegerType::get(M->getContext(), Bits); | |||
| SmallVector<Type *, 1> Types(1, IntTy); | |||
| Function *Intrinsic = | |||
| M->getFunction(Intrinsic::getName(getID(Op, Signed), Types)); | |||
| if (!Intrinsic) | |||
| return false; | |||
|
|
|||
| SmallVector<CallInst *, 64> Calls; | |||
| for (User *U : Intrinsic->users()) | |||
| if (CallInst *Call = dyn_cast<CallInst>(U)) { | |||
| Calls.push_back(Call); | |||
| } else { | |||
| errs() << "User: " << *U << "\n"; | |||
| report_fatal_error("ExpandArithWithOverflow: Taking the address of a " | |||
| "*.with.overflow intrinsic is not allowed"); | |||
| } | |||
|
|
|||
| for (CallInst *Call : Calls) { | |||
| DEBUG(dbgs() << "Expanding " << *Call << "\n"); | |||
|
|
|||
| StringRef Name = Call->getName(); | |||
| Value *LHS; | |||
| Value *RHS; | |||
| Value *NonConstOperand; | |||
| ConstantInt *ConstOperand; | |||
| bool hasConstOperand; | |||
|
|
|||
| if (ConstantInt *C = dyn_cast<ConstantInt>(Call->getArgOperand(0))) { | |||
| LHS = ConstOperand = C; | |||
| RHS = NonConstOperand = Call->getArgOperand(1); | |||
| hasConstOperand = true; | |||
| } else if (ConstantInt *C = dyn_cast<ConstantInt>(Call->getArgOperand(1))) { | |||
| LHS = NonConstOperand = Call->getArgOperand(0); | |||
| RHS = ConstOperand = C; | |||
| hasConstOperand = true; | |||
| } else { | |||
| LHS = Call->getArgOperand(0); | |||
| RHS = Call->getArgOperand(1); | |||
| hasConstOperand = false; | |||
| } | |||
|
|
|||
| IRBuilder<> IRB(Call); | |||
| Value *ArithResult = | |||
| IRB.CreateBinOp(getOpcode(Op), LHS, RHS, Name + ".arith"); | |||
| Value *OverflowResult; | |||
|
|
|||
| if (ExpandArith::Mul == Op && hasConstOperand && | |||
| ConstOperand->getValue() == 0) { | |||
| // Mul by zero never overflows but can divide by zero. | |||
| OverflowResult = ConstantInt::getFalse(M->getContext()); | |||
| } else if (hasConstOperand && !Signed && ExpandArith::Sub != Op) { | |||
| // Unsigned add & mul with a constant operand can be optimized. | |||
| uint64_t ArgMax = | |||
| (ExpandArith::Mul == Op | |||
| ? APInt::getMaxValue(Bits).udiv(ConstOperand->getValue()) | |||
| : APInt::getMaxValue(Bits) - ConstOperand->getValue()) | |||
| .getLimitedValue(); | |||
| OverflowResult = | |||
| IRB.CreateICmp(CmpInst::ICMP_UGT, NonConstOperand, | |||
| ConstantInt::get(IntTy, ArgMax), Name + ".overflow"); | |||
| } else if (ExpandArith::Mul == Op) { | |||
| // Dividing the result by one of the operands should yield the other | |||
| // operand if there was no overflow. Note that this division can't | |||
| // overflow (signed division of INT_MIN / -1 overflows but can't occur | |||
| // here), but it could divide by 0 in which case we instead divide by 1 | |||
| // (this case didn't overflow). | |||
| // | |||
| // FIXME: This approach isn't optimal because it's better to perform a | |||
| // wider multiplication and mask off the result, or perform arithmetic on | |||
| // the component pieces. | |||
| auto DivOp = Signed ? Instruction::SDiv : Instruction::UDiv; | |||
| auto DenomIsZero = | |||
| IRB.CreateICmp(CmpInst::ICMP_EQ, RHS, | |||
| ConstantInt::get(RHS->getType(), 0), Name + ".iszero"); | |||
| auto Denom = | |||
| IRB.CreateSelect(DenomIsZero, ConstantInt::get(RHS->getType(), 1), | |||
| RHS, Name + ".denom"); | |||
| auto Div = IRB.CreateBinOp(DivOp, ArithResult, Denom, Name + ".div"); | |||
| OverflowResult = IRB.CreateSelect( | |||
| DenomIsZero, ConstantInt::getFalse(M->getContext()), | |||
| IRB.CreateICmp(CmpInst::ICMP_NE, Div, LHS, Name + ".same"), | |||
| Name + ".overflow"); | |||
| } else { | |||
| if (!Signed) { | |||
| switch (Op) { | |||
| case ExpandArith::Add: | |||
| // Overflow occurs if unsigned x+y < x (or y). We only need to compare | |||
| // with one of them because this is unsigned arithmetic: on overflow | |||
| // the result is smaller than both inputs, and when there's no | |||
| // overflow the result is greater than both inputs. | |||
| OverflowResult = IRB.CreateICmp(CmpInst::ICMP_ULT, ArithResult, LHS, | |||
| Name + ".overflow"); | |||
| break; | |||
| case ExpandArith::Sub: | |||
| // Overflow occurs if x < y. | |||
| OverflowResult = | |||
| IRB.CreateICmp(CmpInst::ICMP_ULT, LHS, RHS, Name + ".overflow"); | |||
| break; | |||
| case ExpandArith::Mul: // This is handled above. | |||
| llvm_unreachable("Unsigned variable saturating multiplication"); | |||
| } | |||
| } else { | |||
| // In the signed case, we care if the sum is >127 or <-128. When looked | |||
| // at as an unsigned number, that is precisely when the sum is >= 128. | |||
| Value *PositiveTemp = IRB.CreateBinOp( | |||
| Instruction::Add, LHS, | |||
| ConstantInt::get(IntTy, APInt::getSignedMinValue(Bits) + | |||
| (ExpandArith::Sub == Op ? 1 : 0)), | |||
| Name + ".postemp"); | |||
| Value *NegativeTemp = IRB.CreateBinOp( | |||
| Instruction::Add, LHS, | |||
| ConstantInt::get(IntTy, APInt::getSignedMaxValue(Bits) + | |||
| (ExpandArith::Sub == Op ? 1 : 0)), | |||
| Name + ".negtemp"); | |||
| Value *PositiveCheck = IRB.CreateICmp(CmpInst::ICMP_SLT, ArithResult, | |||
| PositiveTemp, Name + ".poscheck"); | |||
| Value *NegativeCheck = IRB.CreateICmp(CmpInst::ICMP_SGT, ArithResult, | |||
| NegativeTemp, Name + ".negcheck"); | |||
| Value *IsPositive = | |||
| IRB.CreateICmp(CmpInst::ICMP_SGE, LHS, ConstantInt::get(IntTy, 0), | |||
| Name + ".ispos"); | |||
| OverflowResult = IRB.CreateSelect(IsPositive, PositiveCheck, | |||
| NegativeCheck, Name + ".select"); | |||
| } | |||
| } | |||
|
|
|||
| // Construct the struct result. | |||
| Value *NewStruct = UndefValue::get(Call->getType()); | |||
| NewStruct = CreateInsertValue(&IRB, NewStruct, 0, ArithResult, Call); | |||
| NewStruct = CreateInsertValue(&IRB, NewStruct, 1, OverflowResult, Call); | |||
| Call->replaceAllUsesWith(NewStruct); | |||
| Call->eraseFromParent(); | |||
| } | |||
|
|
|||
| Intrinsic->eraseFromParent(); | |||
| return true; | |||
| } | |||
|
|
|||
| static const unsigned MaxBits = 64; | |||
|
|
|||
| bool ExpandArithWithOverflow::runOnModule(Module &M) { | |||
| bool Modified = false; | |||
| for (ExpandArith Op : ExpandArithOps) | |||
| for (int Signed = false; Signed <= true; ++Signed) | |||
| for (unsigned Bits = 8; Bits <= MaxBits; Bits <<= 1) | |||
| Modified |= Expand(&M, Bits, Op, Signed); | |||
| return Modified; | |||
| } | |||
|
|
|||
| ModulePass *llvm::createExpandArithWithOverflowPass() { | |||
| return new ExpandArithWithOverflow(); | |||
| } | |||