@@ -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
@@ -37,6 +37,7 @@ add_llvm_library(LLVMCore
Mangler.cpp
Metadata.cpp
Module.cpp
NaClAtomicIntrinsics.cpp
ModuleSummaryIndex.cpp
Operator.cpp
OptBisect.cpp
@@ -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
@@ -655,10 +655,10 @@ void Verifier::visitGlobalVariable(const GlobalVariable &GV) {
AssertDI(false, "!dbg attachment of global variable must be a DIGlobalVariableExpression");
}

if (!GV.hasInitializer()) {
//if (!GV.hasInitializer()) { // XXX EMSCRIPTEN - do not do extra verification below, 40x slower linking on some big projects
visitGlobalValue(GV);
return;
}
//}

// Walk any aggregate initializers looking for bitcasts between address spaces
visitConstantExprsRecursively(GV.getInitializer());
@@ -56,6 +56,7 @@ StringRef Triple::getArchTypeName(ArchType Kind) {
case nvptx64: return "nvptx64";
case le32: return "le32";
case le64: return "le64";
case asmjs: return "asmjs"; // @LOCALMOD Emscripten
case amdil: return "amdil";
case amdil64: return "amdil64";
case hsail: return "hsail";
@@ -124,6 +125,8 @@ StringRef Triple::getArchTypePrefix(ArchType Kind) {
case le32: return "le32";
case le64: return "le64";

case asmjs: return "asmjs"; // @LOCALMOD Emscripten

case amdil:
case amdil64: return "amdil";

@@ -187,6 +190,7 @@ StringRef Triple::getOSTypeName(OSType Kind) {
case Haiku: return "haiku";
case Minix: return "minix";
case RTEMS: return "rtems";
case Emscripten: return "emscripten"; // @LOCALMOD Emscripten
case NaCl: return "nacl";
case CNK: return "cnk";
case Bitrig: return "bitrig";
@@ -285,6 +289,7 @@ Triple::ArchType Triple::getArchTypeForLLVMName(StringRef Name) {
.Case("nvptx64", nvptx64)
.Case("le32", le32)
.Case("le64", le64)
.Case("asmjs", asmjs) // @LOCALMOD Emscripten
.Case("amdil", amdil)
.Case("amdil64", amdil64)
.Case("hsail", hsail)
@@ -399,6 +404,7 @@ static Triple::ArchType parseArch(StringRef ArchName) {
.Case("nvptx64", Triple::nvptx64)
.Case("le32", Triple::le32)
.Case("le64", Triple::le64)
.Case("asmjs", Triple::asmjs) // @LOCALMOD Emscripten
.Case("amdil", Triple::amdil)
.Case("amdil64", Triple::amdil64)
.Case("hsail", Triple::hsail)
@@ -466,6 +472,7 @@ static Triple::OSType parseOS(StringRef OSName) {
.StartsWith("haiku", Triple::Haiku)
.StartsWith("minix", Triple::Minix)
.StartsWith("rtems", Triple::RTEMS)
.StartsWith("emscripten", Triple::Emscripten) // @LOCALMOD Emscripten
.StartsWith("nacl", Triple::NaCl)
.StartsWith("cnk", Triple::CNK)
.StartsWith("bitrig", Triple::Bitrig)
@@ -604,6 +611,7 @@ static Triple::ObjectFormatType getDefaultFormat(const Triple &T) {
case Triple::amdil:
case Triple::amdil64:
case Triple::armeb:
case Triple::asmjs: // @LOCALMOD Emscripten
case Triple::avr:
case Triple::bpfeb:
case Triple::bpfel:
@@ -1150,6 +1158,7 @@ static unsigned getArchPointerBitWidth(llvm::Triple::ArchType Arch) {
case llvm::Triple::armeb:
case llvm::Triple::hexagon:
case llvm::Triple::le32:
case llvm::Triple::asmjs: // @LOCALMOD Emscripten
case llvm::Triple::mips:
case llvm::Triple::mipsel:
case llvm::Triple::nvptx:
@@ -1233,6 +1242,7 @@ Triple Triple::get32BitArchVariant() const {
case Triple::hexagon:
case Triple::kalimba:
case Triple::le32:
case Triple::asmjs: // @LOCALMOD Emscripten
case Triple::mips:
case Triple::mipsel:
case Triple::nvptx:
@@ -1286,6 +1296,7 @@ Triple Triple::get64BitArchVariant() const {
case Triple::tce:
case Triple::tcele:
case Triple::xcore:
case Triple::asmjs: // @LOCALMOD Emscripten
case Triple::sparcel:
case Triple::shave:
T.setArch(UnknownArch);
@@ -1345,6 +1356,7 @@ Triple Triple::getBigEndianArchVariant() const {
case Triple::amdgcn:
case Triple::amdil64:
case Triple::amdil:
case Triple::asmjs:
case Triple::avr:
case Triple::hexagon:
case Triple::hsail64:
@@ -1428,6 +1440,7 @@ bool Triple::isLittleEndian() const {
case Triple::amdil64:
case Triple::amdil:
case Triple::arm:
case Triple::asmjs:
case Triple::avr:
case Triple::bpfel:
case Triple::hexagon:

Large diffs are not rendered by default.

Oops, something went wrong.
@@ -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)

Large diffs are not rendered by default.

Oops, something went wrong.
@@ -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

Large diffs are not rendered by default.

Oops, something went wrong.
@@ -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();
}
Oops, something went wrong.