@@ -0,0 +1,206 @@
//===- ExpandByVal.cpp - Expand out use of "byval" and "sret" attributes---===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This pass expands out by-value passing of structs as arguments and
// return values. In LLVM IR terms, it expands out the "byval" and
// "sret" function argument attributes.
//
// The semantics of the "byval" attribute are that the callee function
// gets a private copy of the pointed-to argument that it is allowed
// to modify. In implementing this, we have a choice between making
// the caller responsible for making the copy or making the callee
// responsible for making the copy. We choose the former, because
// this matches how the normal native calling conventions work, and
// because it often allows the caller to write struct contents
// directly into the stack slot that it passes the callee, without an
// additional copy.
//
// Note that this pass does not attempt to modify functions that pass
// structs by value without using "byval" or "sret", such as:
//
// define %struct.X @func() ; struct return
// define void @func(%struct.X %arg) ; struct arg
//
// The pass only handles functions such as:
//
// define void @func(%struct.X* sret %result_buffer) ; struct return
// define void @func(%struct.X* byval %ptr_to_arg) ; struct arg
//
// This is because PNaCl Clang generates the latter and not the former.
//
//===----------------------------------------------------------------------===//

#include "llvm/IR/Attributes.h"
#include "llvm/IR/DataLayout.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/IRBuilder.h"
#include "llvm/IR/Instructions.h"
#include "llvm/IR/Module.h"
#include "llvm/Pass.h"
#include "llvm/Transforms/NaCl.h"

using namespace llvm;

namespace {
// This is a ModulePass so that it can strip attributes from
// declared functions as well as defined functions.
class ExpandByVal : public ModulePass {
public:
static char ID; // Pass identification, replacement for typeid
ExpandByVal() : ModulePass(ID) {
initializeExpandByValPass(*PassRegistry::getPassRegistry());
}

virtual bool runOnModule(Module &M);
};
}

char ExpandByVal::ID = 0;
INITIALIZE_PASS(ExpandByVal, "expand-byval",
"Expand out by-value passing of structs",
false, false)

// removeAttribute() currently does not work on Attribute::Alignment
// (it fails with an assertion error), so we have to take a more
// convoluted route to removing this attribute by recreating the
// AttributeSet.
AttributeSet RemoveAttrs(LLVMContext &Context, AttributeSet Attrs) {
SmallVector<AttributeSet, 8> AttrList;
for (unsigned Slot = 0; Slot < Attrs.getNumSlots(); ++Slot) {
unsigned Index = Attrs.getSlotIndex(Slot);
AttrBuilder AB;
for (AttributeSet::iterator Attr = Attrs.begin(Slot), E = Attrs.end(Slot);
Attr != E; ++Attr) {
if (Attr->isEnumAttribute() &&
Attr->getKindAsEnum() != Attribute::ByVal &&
Attr->getKindAsEnum() != Attribute::StructRet) {
AB.addAttribute(*Attr);
}
// IR semantics require that ByVal implies NoAlias. However, IR
// semantics do not require StructRet to imply NoAlias. For
// example, a global variable address can be passed as a
// StructRet argument, although Clang does not do so and Clang
// explicitly adds NoAlias to StructRet arguments.
if (Attr->isEnumAttribute() &&
Attr->getKindAsEnum() == Attribute::ByVal) {
AB.addAttribute(Attribute::get(Context, Attribute::NoAlias));
}
}
AttrList.push_back(AttributeSet::get(Context, Index, AB));
}
return AttributeSet::get(Context, AttrList);
}

// ExpandCall() can take a CallInst or an InvokeInst. It returns
// whether the instruction was modified.
template <class InstType>
static bool ExpandCall(DataLayout *DL, InstType *Call) {
bool Modify = false;
AttributeSet Attrs = Call->getAttributes();
for (unsigned ArgIdx = 0; ArgIdx < Call->getNumArgOperands(); ++ArgIdx) {
unsigned AttrIdx = ArgIdx + 1;

if (Attrs.hasAttribute(AttrIdx, Attribute::StructRet))
Modify = true;

if (Attrs.hasAttribute(AttrIdx, Attribute::ByVal)) {
Modify = true;

Value *ArgPtr = Call->getArgOperand(ArgIdx);
Type *ArgType = ArgPtr->getType()->getPointerElementType();
ConstantInt *ArgSize = ConstantInt::get(
Call->getContext(), APInt(64, DL->getTypeStoreSize(ArgType)));
// In principle, using the alignment from the argument attribute
// should be enough. However, Clang is not emitting this
// attribute for PNaCl. LLVM alloca instructions do not use the
// ABI alignment of the type, so this must be specified
// explicitly.
// See https://code.google.com/p/nativeclient/issues/detail?id=3403
//
// Note that the parameter may have no alignment, but we have
// more useful information from the type which we can use here
// -- 0 in the parameter means no alignment is specified there,
// so it has default alignment, but in memcpy 0 means
// pessimistic alignment, the same as 1.
unsigned Alignment =
std::max(Attrs.getParamAlignment(AttrIdx),
DL->getABITypeAlignment(ArgType));

// Make a copy of the byval argument.
Instruction *CopyBuf = new AllocaInst(ArgType, 0, Alignment,
ArgPtr->getName() + ".byval_copy");
Function *Func = Call->getParent()->getParent();
Func->getEntryBlock().getInstList().push_front(CopyBuf);
IRBuilder<> Builder(Call);
Builder.CreateLifetimeStart(CopyBuf, ArgSize);
// Using the argument's alignment attribute for the memcpy
// should be OK because the LLVM Language Reference says that
// the alignment attribute specifies "the alignment of the stack
// slot to form and the known alignment of the pointer specified
// to the call site".
Instruction *MemCpy = Builder.CreateMemCpy(CopyBuf, ArgPtr, ArgSize,
Alignment);
MemCpy->setDebugLoc(Call->getDebugLoc());

Call->setArgOperand(ArgIdx, CopyBuf);

// Mark the argument copy as unused using llvm.lifetime.end.
if (isa<CallInst>(Call)) {
BasicBlock::iterator It = BasicBlock::iterator(Call);
Builder.SetInsertPoint(&*(++It));
Builder.CreateLifetimeEnd(CopyBuf, ArgSize);
} else if (InvokeInst *Invoke = dyn_cast<InvokeInst>(Call)) {
Builder.SetInsertPoint(&*Invoke->getNormalDest()->getFirstInsertionPt());
Builder.CreateLifetimeEnd(CopyBuf, ArgSize);
Builder.SetInsertPoint(&*Invoke->getUnwindDest()->getFirstInsertionPt());
Builder.CreateLifetimeEnd(CopyBuf, ArgSize);
}
}
}
if (Modify) {
Call->setAttributes(RemoveAttrs(Call->getContext(), Attrs));

if (CallInst *CI = dyn_cast<CallInst>(Call)) {
// This is no longer a tail call because the callee references
// memory alloca'd by the caller.
CI->setTailCall(false);
}
}
return Modify;
}

bool ExpandByVal::runOnModule(Module &M) {
bool Modified = false;
DataLayout DL(&M);

for (Module::iterator Func = M.begin(), E = M.end(); Func != E; ++Func) {
AttributeSet NewAttrs = RemoveAttrs(Func->getContext(),
Func->getAttributes());
Modified |= (NewAttrs != Func->getAttributes());
Func->setAttributes(NewAttrs);

for (Function::iterator BB = Func->begin(), E = Func->end();
BB != E; ++BB) {
for (BasicBlock::iterator Inst = BB->begin(), E = BB->end();
Inst != E; ++Inst) {
if (CallInst *Call = dyn_cast<CallInst>(Inst)) {
Modified |= ExpandCall(&DL, Call);
} else if (InvokeInst *Call = dyn_cast<InvokeInst>(Inst)) {
Modified |= ExpandCall(&DL, Call);
}
}
}
}

return Modified;
}

ModulePass *llvm::createExpandByValPass() {
return new ExpandByVal();
}
@@ -0,0 +1,121 @@
//===- ExpandConstantExpr.cpp - Convert ConstantExprs to Instructions------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This pass expands out ConstantExprs into Instructions.
//
// Note that this only converts ConstantExprs that are referenced by
// Instructions. It does not convert ConstantExprs that are used as
// initializers for global variables.
//
// This simplifies the language so that the PNaCl translator does not
// need to handle ConstantExprs as part of a stable wire format for
// PNaCl.
//
//===----------------------------------------------------------------------===//

#include <map>

#include "llvm/IR/Constants.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/Instructions.h"
#include "llvm/Pass.h"
#include "llvm/Transforms/NaCl.h"

using namespace llvm;

static bool expandInstruction(Instruction *Inst);

namespace {
// This is a FunctionPass because our handling of PHI nodes means
// that our modifications may cross BasicBlocks.
struct ExpandConstantExpr : public FunctionPass {
static char ID; // Pass identification, replacement for typeid
ExpandConstantExpr() : FunctionPass(ID) {
initializeExpandConstantExprPass(*PassRegistry::getPassRegistry());
}

virtual bool runOnFunction(Function &Func);
};
}

char ExpandConstantExpr::ID = 0;
INITIALIZE_PASS(ExpandConstantExpr, "expand-constant-expr",
"Expand out ConstantExprs into Instructions",
false, false)

static Value *expandConstantExpr(Instruction *InsertPt, ConstantExpr *Expr) {
Instruction *NewInst = Expr->getAsInstruction();
NewInst->insertBefore(InsertPt);
NewInst->setName("expanded");
expandInstruction(NewInst);
return NewInst;
}

// XXX Emscripten: Utilities for illegal expressions.
static bool isIllegal(Type *T) {
if (!T->isIntegerTy()) return false;
unsigned Bits = T->getIntegerBitWidth();
// we need to expand out not just 64-bit and larger values, but also i24s, so PromoteIntegers can process them
return Bits != 1 && Bits != 8 && Bits != 16 && Bits != 32;
}
static bool ContainsIllegalTypes(const Value *Expr) {
if (isIllegal(Expr->getType()))
return true;
if (const User *U = dyn_cast<User>(Expr)) {
for (User::const_op_iterator I = U->op_begin(), E = U->op_end(); I != E; ++I) {
if (Constant *C = dyn_cast<Constant>(*I)) {
if (!isa<GlobalValue>(C) && ContainsIllegalTypes(C)) {
return true;
}
}
}
}
return false;
}

static bool expandInstruction(Instruction *Inst) {
// A landingpad can only accept ConstantExprs, so it should remain
// unmodified.
if (isa<LandingPadInst>(Inst))
return false;

bool Modified = false;
for (unsigned OpNum = 0; OpNum < Inst->getNumOperands(); OpNum++) {
if (ConstantExpr *Expr =
dyn_cast<ConstantExpr>(Inst->getOperand(OpNum))) {
// XXX Emscripten: Only do the expansion of the expression contains
// illegal types, for now, since we can handle legal ConstantExprs
// in the backend directly.
if (ContainsIllegalTypes(Expr)) {
Modified = true;
Use *U = &Inst->getOperandUse(OpNum);
PhiSafeReplaceUses(U, expandConstantExpr(PhiSafeInsertPt(U), Expr));
}
}
}
return Modified;
}

bool ExpandConstantExpr::runOnFunction(Function &Func) {
bool Modified = false;
for (llvm::Function::iterator BB = Func.begin(), E = Func.end();
BB != E;
++BB) {
for (BasicBlock::InstListType::iterator Inst = BB->begin(), E = BB->end();
Inst != E;
++Inst) {
Modified |= expandInstruction(&*Inst);
}
}
return Modified;
}

FunctionPass *llvm::createExpandConstantExprPass() {
return new ExpandConstantExpr();
}
@@ -0,0 +1,154 @@
//===- ExpandCtors.cpp - Convert ctors/dtors to concrete arrays -----------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This pass converts LLVM's special symbols llvm.global_ctors and
// llvm.global_dtors to concrete arrays, __init_array_start/end and
// __fini_array_start/end, that are usable by a C library.
//
// This pass sorts the contents of global_ctors/dtors according to the
// priority values they contain and removes the priority values.
//
//===----------------------------------------------------------------------===//

#include <vector>

#include "llvm/Pass.h"
#include "llvm/IR/Constants.h"
#include "llvm/IR/DerivedTypes.h"
#include "llvm/IR/Instructions.h"
#include "llvm/IR/Module.h"
#include "llvm/IR/TypeBuilder.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Transforms/NaCl.h"

using namespace llvm;

namespace {
struct ExpandCtors : public ModulePass {
static char ID; // Pass identification, replacement for typeid
ExpandCtors() : ModulePass(ID) {
initializeExpandCtorsPass(*PassRegistry::getPassRegistry());
}

virtual bool runOnModule(Module &M);
};
}

char ExpandCtors::ID = 0;
INITIALIZE_PASS(ExpandCtors, "nacl-expand-ctors",
"Hook up constructor and destructor arrays to libc",
false, false)

static void setGlobalVariableValue(Module &M, const char *Name,
Constant *Value) {
if (GlobalVariable *Var = M.getNamedGlobal(Name)) {
if (Var->hasInitializer()) {
report_fatal_error(std::string("Variable ") + Name +
" already has an initializer");
}
Var->replaceAllUsesWith(ConstantExpr::getBitCast(Value, Var->getType()));
Var->eraseFromParent();
}
}

struct FuncArrayEntry {
uint64_t priority;
Constant *func;
};

static bool compareEntries(FuncArrayEntry Entry1, FuncArrayEntry Entry2) {
return Entry1.priority < Entry2.priority;
}

static void readFuncList(GlobalVariable *Array, std::vector<Constant*> *Funcs) {
if (!Array->hasInitializer())
return;
Constant *Init = Array->getInitializer();
ArrayType *Ty = dyn_cast<ArrayType>(Init->getType());
if (!Ty) {
errs() << "Initializer: " << *Array->getInitializer() << "\n";
report_fatal_error("ExpandCtors: Initializer is not of array type");
}
if (Ty->getNumElements() == 0)
return;
ConstantArray *InitList = dyn_cast<ConstantArray>(Init);
if (!InitList) {
errs() << "Initializer: " << *Array->getInitializer() << "\n";
report_fatal_error("ExpandCtors: Unexpected initializer ConstantExpr");
}
std::vector<FuncArrayEntry> FuncsToSort;
for (unsigned Index = 0; Index < InitList->getNumOperands(); ++Index) {
ConstantStruct *CS = cast<ConstantStruct>(InitList->getOperand(Index));
FuncArrayEntry Entry;
Entry.priority = cast<ConstantInt>(CS->getOperand(0))->getZExtValue();
Entry.func = CS->getOperand(1);
FuncsToSort.push_back(Entry);
}

std::sort(FuncsToSort.begin(), FuncsToSort.end(), compareEntries);
for (std::vector<FuncArrayEntry>::iterator Iter = FuncsToSort.begin();
Iter != FuncsToSort.end();
++Iter) {
Funcs->push_back(Iter->func);
}
}

static void defineFuncArray(Module &M, const char *LlvmArrayName,
const char *StartSymbol,
const char *EndSymbol) {
std::vector<Constant*> Funcs;

GlobalVariable *Array = M.getNamedGlobal(LlvmArrayName);
if (Array) {
readFuncList(Array, &Funcs);
// No code should be referencing global_ctors/global_dtors,
// because this symbol is internal to LLVM.
Array->eraseFromParent();
}

Type *FuncTy = FunctionType::get(Type::getVoidTy(M.getContext()), false);
Type *FuncPtrTy = FuncTy->getPointerTo();
ArrayType *ArrayTy = ArrayType::get(FuncPtrTy, Funcs.size());
GlobalVariable *NewArray =
new GlobalVariable(M, ArrayTy, /* isConstant= */ true,
GlobalValue::InternalLinkage,
ConstantArray::get(ArrayTy, Funcs));
setGlobalVariableValue(M, StartSymbol, NewArray);
// We do this last so that LLVM gives NewArray the name
// "__{init,fini}_array_start" without adding any suffixes to
// disambiguate from the original GlobalVariable's name. This is
// not essential -- it just makes the output easier to understand
// when looking at symbols for debugging.
NewArray->setName(StartSymbol);

// We replace "__{init,fini}_array_end" with the address of the end
// of NewArray. This removes the name "__{init,fini}_array_end"
// from the output, which is not ideal for debugging. Ideally we
// would convert "__{init,fini}_array_end" to being a GlobalAlias
// that points to the end of the array. However, unfortunately LLVM
// does not generate correct code when a GlobalAlias contains a
// GetElementPtr ConstantExpr.
Constant *NewArrayEnd =
ConstantExpr::getGetElementPtr(ArrayTy, NewArray,
ConstantInt::get(M.getContext(),
APInt(32, 1)));
setGlobalVariableValue(M, EndSymbol, NewArrayEnd);
}

bool ExpandCtors::runOnModule(Module &M) {
defineFuncArray(M, "llvm.global_ctors",
"__init_array_start", "__init_array_end");
defineFuncArray(M, "llvm.global_dtors",
"__fini_array_start", "__fini_array_end");
return true;
}

ModulePass *llvm::createExpandCtorsPass() {
return new ExpandCtors();
}
@@ -0,0 +1,151 @@
//===- ExpandGetElementPtr.cpp - Expand GetElementPtr into arithmetic------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This pass expands out GetElementPtr instructions into ptrtoint,
// inttoptr and arithmetic instructions.
//
// This simplifies the language so that the PNaCl translator does not
// need to handle GetElementPtr and struct types as part of a stable
// wire format for PNaCl.
//
// Note that we drop the "inbounds" attribute of GetElementPtr.
//
//===----------------------------------------------------------------------===//

#include "llvm/IR/BasicBlock.h"
#include "llvm/IR/Constants.h"
#include "llvm/IR/DataLayout.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/InstrTypes.h"
#include "llvm/IR/Instructions.h"
#include "llvm/IR/Module.h"
#include "llvm/IR/Type.h"
#include "llvm/Pass.h"
#include "llvm/Transforms/NaCl.h"

using namespace llvm;

namespace {
class ExpandGetElementPtr : public BasicBlockPass {
public:
static char ID; // Pass identification, replacement for typeid
ExpandGetElementPtr() : BasicBlockPass(ID) {
initializeExpandGetElementPtrPass(*PassRegistry::getPassRegistry());
}

virtual bool runOnBasicBlock(BasicBlock &BB);
};
}

char ExpandGetElementPtr::ID = 0;
INITIALIZE_PASS(ExpandGetElementPtr, "expand-getelementptr",
"Expand out GetElementPtr instructions into arithmetic",
false, false)

static Value *CastToPtrSize(Value *Val, Instruction *InsertPt,
const DebugLoc &Debug, Type *PtrType) {
unsigned ValSize = Val->getType()->getIntegerBitWidth();
unsigned PtrSize = PtrType->getIntegerBitWidth();
if (ValSize == PtrSize)
return Val;
Instruction *Inst;
if (ValSize > PtrSize) {
Inst = new TruncInst(Val, PtrType, "gep_trunc", InsertPt);
} else {
// GEP indexes must be sign-extended.
Inst = new SExtInst(Val, PtrType, "gep_sext", InsertPt);
}
Inst->setDebugLoc(Debug);
return Inst;
}

static void FlushOffset(Instruction **Ptr, uint64_t *CurrentOffset,
Instruction *InsertPt, const DebugLoc &Debug,
Type *PtrType) {
if (*CurrentOffset) {
*Ptr = BinaryOperator::Create(Instruction::Add, *Ptr,
ConstantInt::get(PtrType, *CurrentOffset),
"gep", InsertPt);
(*Ptr)->setDebugLoc(Debug);
*CurrentOffset = 0;
}
}

static void ExpandGEP(GetElementPtrInst *GEP, DataLayout *DL, Type *PtrType) {
const DebugLoc &Debug = GEP->getDebugLoc();
Instruction *Ptr = new PtrToIntInst(GEP->getPointerOperand(), PtrType,
"gep_int", GEP);
Ptr->setDebugLoc(Debug);

Type *CurrentTy = GEP->getPointerOperand()->getType();
// We do some limited constant folding ourselves. An alternative
// would be to generate verbose, unfolded output (e.g. multiple
// adds; adds of zero constants) and use a later pass such as
// "-instcombine" to clean that up. However, "-instcombine" can
// reintroduce GetElementPtr instructions.
uint64_t CurrentOffset = 0;

for (GetElementPtrInst::op_iterator Op = GEP->op_begin() + 1;
Op != GEP->op_end();
++Op) {
Value *Index = *Op;
if (StructType *StTy = dyn_cast<StructType>(CurrentTy)) {
uint64_t Field = cast<ConstantInt>(Op)->getZExtValue();
CurrentTy = StTy->getElementType(Field);
CurrentOffset += DL->getStructLayout(StTy)->getElementOffset(Field);
} else {
CurrentTy = cast<SequentialType>(CurrentTy)->getElementType();
uint64_t ElementSize = DL->getTypeAllocSize(CurrentTy);
if (ConstantInt *C = dyn_cast<ConstantInt>(Index)) {
CurrentOffset += C->getSExtValue() * ElementSize;
} else {
FlushOffset(&Ptr, &CurrentOffset, GEP, Debug, PtrType);
Index = CastToPtrSize(Index, GEP, Debug, PtrType);
if (ElementSize != 1) {
Index = CopyDebug(
BinaryOperator::Create(Instruction::Mul, Index,
ConstantInt::get(PtrType, ElementSize),
"gep_array", GEP),
GEP);
}
Ptr = BinaryOperator::Create(Instruction::Add, Ptr,
Index, "gep", GEP);
Ptr->setDebugLoc(Debug);
}
}
}
FlushOffset(&Ptr, &CurrentOffset, GEP, Debug, PtrType);

assert(CurrentTy == GEP->getType()->getElementType());
Instruction *Result = new IntToPtrInst(Ptr, GEP->getType(), "", GEP);
Result->setDebugLoc(Debug);
Result->takeName(GEP);
GEP->replaceAllUsesWith(Result);
GEP->eraseFromParent();
}

bool ExpandGetElementPtr::runOnBasicBlock(BasicBlock &BB) {
bool Modified = false;
DataLayout DL(BB.getParent()->getParent());
Type *PtrType = DL.getIntPtrType(BB.getContext());

for (BasicBlock::InstListType::iterator Iter = BB.begin();
Iter != BB.end(); ) {
Instruction *Inst = &*Iter++;
if (GetElementPtrInst *GEP = dyn_cast<GetElementPtrInst>(Inst)) {
Modified = true;
ExpandGEP(GEP, &DL, PtrType);
}
}
return Modified;
}

BasicBlockPass *llvm::createExpandGetElementPtrPass() {
return new ExpandGetElementPtr();
}

Large diffs are not rendered by default.

Oops, something went wrong.
@@ -0,0 +1,152 @@
//===- ExpandIndirectBr.cpp - Expand out indirectbr and blockaddress-------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This pass expands out indirectbr instructions and blockaddress
// ConstantExprs, which are not currently supported in PNaCl's stable
// ABI. indirectbr is used to implement computed gotos (a GNU
// extension to C). This pass replaces indirectbr instructions with
// switch instructions.
//
// The resulting use of switches might not be as fast as the original
// indirectbrs. If you are compiling a program that has a
// compile-time option for using computed gotos, it's possible that
// the program will run faster with the option turned off than with
// using computed gotos + ExpandIndirectBr (for example, if the
// program does extra work to take advantage of computed gotos).
//
//===----------------------------------------------------------------------===//

#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/DenseSet.h"
#include "llvm/IR/Constants.h"
#include "llvm/IR/Instructions.h"
#include "llvm/IR/Module.h"
#include "llvm/Pass.h"
#include "llvm/Transforms/NaCl.h"

using namespace llvm;

namespace {
// This is a ModulePass so that it can expand out blockaddress
// ConstantExprs inside global variable initializers.
class ExpandIndirectBr : public ModulePass {
public:
static char ID; // Pass identification, replacement for typeid
ExpandIndirectBr() : ModulePass(ID) {
initializeExpandIndirectBrPass(*PassRegistry::getPassRegistry());
}

virtual bool runOnModule(Module &M);
};
}

char ExpandIndirectBr::ID = 0;
INITIALIZE_PASS(ExpandIndirectBr, "expand-indirectbr",
"Expand out indirectbr and blockaddress (computed gotos)",
false, false)

static bool convertFunction(Function *Func) {
bool Changed = false;
IntegerType *I32 = Type::getInt32Ty(Func->getContext());

// Skip zero in case programs treat a null pointer as special.
uint32_t NextNum = 1;
DenseMap<BasicBlock *, ConstantInt *> LabelNums;
BasicBlock *DefaultBB = NULL;

// Replace each indirectbr with a switch.
//
// If there are multiple indirectbr instructions in the function,
// this could be expensive. While an indirectbr is usually
// converted to O(1) machine instructions, the switch we generate
// here will be O(n) in the number of target labels.
//
// However, Clang usually generates just a single indirectbr per
// function anyway when compiling C computed gotos.
//
// We could try to generate one switch to handle all the indirectbr
// instructions in the function, but that would be complicated to
// implement given that variables that are live at one indirectbr
// might not be live at others.
for (llvm::Function::iterator BB = Func->begin(), E = Func->end();
BB != E; ++BB) {
if (IndirectBrInst *Br = dyn_cast<IndirectBrInst>(BB->getTerminator())) {
Changed = true;

if (!DefaultBB) {
DefaultBB = BasicBlock::Create(Func->getContext(),
"indirectbr_default", Func);
new UnreachableInst(Func->getContext(), DefaultBB);
}

// An indirectbr can list the same target block multiple times.
// Keep track of the basic blocks we've handled to avoid adding
// the same case multiple times.
DenseSet<BasicBlock *> BlocksSeen;

Value *Cast = new PtrToIntInst(Br->getAddress(), I32,
"indirectbr_cast", Br);
unsigned Count = Br->getNumSuccessors();
SwitchInst *Switch = SwitchInst::Create(Cast, DefaultBB, Count, Br);
for (unsigned I = 0; I < Count; ++I) {
BasicBlock *Dest = Br->getSuccessor(I);
if (!BlocksSeen.insert(Dest).second) {
// Remove duplicated entries from phi nodes.
for (BasicBlock::iterator Inst = Dest->begin(); ; ++Inst) {
PHINode *Phi = dyn_cast<PHINode>(Inst);
if (!Phi)
break;
Phi->removeIncomingValue(Br->getParent());
}
continue;
}
ConstantInt *Val;
if (LabelNums.count(Dest) == 0) {
Val = ConstantInt::get(I32, NextNum++);
LabelNums[Dest] = Val;

BlockAddress *BA = BlockAddress::get(Func, Dest);
Value *ValAsPtr = ConstantExpr::getIntToPtr(Val, BA->getType());
BA->replaceAllUsesWith(ValAsPtr);
BA->destroyConstant();
} else {
Val = LabelNums[Dest];
}
Switch->addCase(Val, Br->getSuccessor(I));
}
Br->eraseFromParent();
}
}

// If there are any blockaddresses that are never used by an
// indirectbr, replace them with dummy values.
SmallVector<Value *, 20> Users(Func->user_begin(), Func->user_end());
for (auto U : Users) {
if (BlockAddress *BA = dyn_cast<BlockAddress>(U)) {
Changed = true;
Value *DummyVal = ConstantExpr::getIntToPtr(ConstantInt::get(I32, ~0L),
BA->getType());
BA->replaceAllUsesWith(DummyVal);
BA->destroyConstant();
}
}
return Changed;
}

bool ExpandIndirectBr::runOnModule(Module &M) {
bool Changed = false;
for (Module::iterator Func = M.begin(), E = M.end(); Func != E; ++Func) {
Changed |= convertFunction(&*Func);
}
return Changed;
}

ModulePass *llvm::createExpandIndirectBrPass() {
return new ExpandIndirectBr();
}
@@ -0,0 +1,100 @@
//==- ExpandInsertExtractElement.cpp - Expand vector insert and extract -=//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===------------------------------------------------------------------===//
//
// This pass expands insertelement and extractelement instructions with
// variable indices, which SIMD.js doesn't natively support yet.
//
//===------------------------------------------------------------------===//

#include "llvm/ADT/SmallVector.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/IRBuilder.h"
#include "llvm/IR/InstIterator.h"
#include "llvm/IR/Instructions.h"
#include "llvm/IR/Module.h"
#include "llvm/Pass.h"
#include "llvm/Transforms/NaCl.h"
#include "llvm/Transforms/Utils/Local.h"
#include <map>
#include <vector>

#include "llvm/Support/raw_ostream.h"

using namespace llvm;

namespace {

class ExpandInsertExtractElement : public FunctionPass {
bool Changed;

public:
static char ID;
ExpandInsertExtractElement() : FunctionPass(ID) {
initializeExpandInsertExtractElementPass(*PassRegistry::getPassRegistry());
}

bool runOnFunction(Function &F) override;
};
}

char ExpandInsertExtractElement::ID = 0;
INITIALIZE_PASS(ExpandInsertExtractElement, "expand-insert-extract-elements",
"Expand and lower insert and extract element operations",
false, false)

// Utilities

bool ExpandInsertExtractElement::runOnFunction(Function &F) {
Changed = false;

Instruction *Entry = &*F.getEntryBlock().begin();
Type *Int32 = Type::getInt32Ty(F.getContext());
Constant *Zero = ConstantInt::get(Int32, 0);
for (inst_iterator I = inst_begin(&F), E = inst_end(&F); I != E; ) {
Instruction *Inst = &*I++;

if (InsertElementInst *III = dyn_cast<InsertElementInst>(Inst)) {
if (isa<ConstantInt>(III->getOperand(2)))
continue;

Type *AllocaTy = III->getType();
Instruction *A = new AllocaInst(AllocaTy, 0, "", Entry);
CopyDebug(new StoreInst(III->getOperand(0), A, III), III);

Value *Idxs[] = { Zero, III->getOperand(2) };
Instruction *B = CopyDebug(
GetElementPtrInst::Create(AllocaTy, A, Idxs, "", III), III);
CopyDebug(new StoreInst(III->getOperand(1), B, III), III);

Instruction *L = CopyDebug(new LoadInst(A, "", III), III);
III->replaceAllUsesWith(L);
III->eraseFromParent();
} else if (ExtractElementInst *EII = dyn_cast<ExtractElementInst>(Inst)) {
if (isa<ConstantInt>(EII->getOperand(1)))
continue;

Type *AllocaTy = EII->getOperand(0)->getType();
Instruction *A = new AllocaInst(AllocaTy, 0, "", Entry);
CopyDebug(new StoreInst(EII->getOperand(0), A, EII), EII);

Value *Idxs[] = { Zero, EII->getOperand(1) };
Instruction *B = CopyDebug(
GetElementPtrInst::Create(AllocaTy, A, Idxs, "", EII), EII);
Instruction *L = CopyDebug(new LoadInst(B, "", EII), EII);
EII->replaceAllUsesWith(L);
EII->eraseFromParent();
}
}

return Changed;
}

FunctionPass *llvm::createExpandInsertExtractElementPass() {
return new ExpandInsertExtractElement();
}

Large diffs are not rendered by default.

Oops, something went wrong.
@@ -0,0 +1,110 @@
//===- ExpandShuffleVector.cpp - shufflevector to {insert/extract}element -===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// Replace all shufflevector instructions by insertelement / extractelement.
// BackendCanonicalize is able to reconstruct the shufflevector.
//
//===----------------------------------------------------------------------===//

#include "llvm/IR/BasicBlock.h"
#include "llvm/IR/Constants.h"
#include "llvm/IR/Instruction.h"
#include "llvm/IR/Instructions.h"
#include "llvm/IR/Module.h"
#include "llvm/IR/Type.h"
#include "llvm/Pass.h"
#include "llvm/Transforms/NaCl.h"

using namespace llvm;

namespace {
class ExpandShuffleVector : public BasicBlockPass {
public:
static char ID; // Pass identification, replacement for typeid
ExpandShuffleVector() : BasicBlockPass(ID), M(0) {
initializeExpandShuffleVectorPass(*PassRegistry::getPassRegistry());
}
using BasicBlockPass::doInitialization;
bool doInitialization(Module &Mod) override {
M = &Mod;
return false; // Unchanged.
}
bool runOnBasicBlock(BasicBlock &BB) override;

private:
const Module *M;
void Expand(ShuffleVectorInst *Shuf, Type *Int32);
};
}

char ExpandShuffleVector::ID = 0;
INITIALIZE_PASS(
ExpandShuffleVector, "expand-shufflevector",
"Expand shufflevector instructions into insertelement and extractelement",
false, false)

void ExpandShuffleVector::Expand(ShuffleVectorInst *Shuf, Type *Int32) {
Value *L = Shuf->getOperand(0);
Value *R = Shuf->getOperand(1);
assert(L->getType() == R->getType());
VectorType *SrcVecTy = cast<VectorType>(L->getType());
VectorType *DstVecTy = Shuf->getType();
Type *ElemTy = DstVecTy->getElementType();
SmallVector<int, 16> Mask = Shuf->getShuffleMask();
unsigned NumSrcElems = SrcVecTy->getNumElements();
unsigned NumDstElems = Mask.size();

// Start with an undefined vector, extract each element from either L
// or R according to the Mask, and insert it into contiguous element
// locations in the result vector.
//
// The sources for shufflevector must have the same type but the
// destination could be a narrower or wider vector with the same
// element type.
Instruction *ExtractLoc = Shuf;
Value *Res = UndefValue::get(DstVecTy);
for (unsigned Elem = 0; Elem != NumDstElems; ++Elem) {
bool IsUndef =
0 > Mask[Elem] || static_cast<unsigned>(Mask[Elem]) >= NumSrcElems * 2;
bool IsL = static_cast<unsigned>(Mask[Elem]) < NumSrcElems;
Value *From = IsL ? L : R;
int Adjustment = IsL ? 0 : NumSrcElems;
Constant *ExtractIdx = ConstantInt::get(Int32, Mask[Elem] - Adjustment);
Constant *InsertIdx = ConstantInt::get(Int32, Elem);
Value *ElemToInsert = IsUndef ? UndefValue::get(ElemTy)
: (Value *)ExtractElementInst::Create(
From, ExtractIdx, "", ExtractLoc);
Res = InsertElementInst::Create(Res, ElemToInsert, InsertIdx, "", Shuf);
if (ExtractLoc == Shuf)
// All the extracts should be added just before the first insert we added.
ExtractLoc = cast<Instruction>(Res);
}

Shuf->replaceAllUsesWith(Res);
Shuf->eraseFromParent();
}

bool ExpandShuffleVector::runOnBasicBlock(BasicBlock &BB) {
Type *Int32 = Type::getInt32Ty(M->getContext());
typedef SmallVector<ShuffleVectorInst *, 8> Instructions;
Instructions Shufs;

for (BasicBlock::iterator BBI = BB.begin(); BBI != BB.end(); ++BBI)
if (ShuffleVectorInst *S = dyn_cast<ShuffleVectorInst>(&*BBI))
Shufs.push_back(S);

for (Instructions::iterator S = Shufs.begin(), E = Shufs.end(); S != E; ++S)
Expand(*S, Int32);

return !Shufs.empty();
}

BasicBlockPass *llvm::createExpandShuffleVectorPass() {
return new ExpandShuffleVector();
}
@@ -0,0 +1,250 @@
//===- ExpandSmallArguments.cpp - Expand out arguments smaller than i32----===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// LLVM IR allows function return types and argument types such as
// "zeroext i8" and "signext i8". The Language Reference says that
// zeroext "indicates to the code generator that the parameter or
// return value should be zero-extended to the extent required by the
// target's ABI (which is usually 32-bits, but is 8-bits for a i1 on
// x86-64) by the caller (for a parameter) or the callee (for a return
// value)".
//
// This can lead to non-portable behaviour when calling functions
// without C prototypes or with wrong C prototypes.
//
// In order to remove this non-portability from PNaCl, and to simplify
// the language that the PNaCl translator accepts, the
// ExpandSmallArguments pass widens integer arguments and return types
// to be at least 32 bits. The pass inserts explicit cast
// instructions (ZExtInst/SExtInst/TruncInst) as needed.
//
// The pass chooses between ZExtInst and SExtInst widening based on
// whether a "signext" attribute is present. However, in principle
// the pass could always use zero-extension, because the extent to
// which either zero-extension or sign-extension is done is up to the
// target ABI, which is up to PNaCl to specify.
//
//===----------------------------------------------------------------------===//

#include "llvm/IR/Function.h"
#include "llvm/IR/Instructions.h"
#include "llvm/IR/IntrinsicInst.h"
#include "llvm/IR/Module.h"
#include "llvm/Pass.h"
#include "llvm/Transforms/NaCl.h"
#include "llvm/Transforms/Utils/BasicBlockUtils.h"

using namespace llvm;

namespace {
// This is a ModulePass because the pass recreates functions in
// order to change their arguments' types.
class ExpandSmallArguments : public ModulePass {
public:
static char ID; // Pass identification, replacement for typeid
ExpandSmallArguments() : ModulePass(ID) {
initializeExpandSmallArgumentsPass(*PassRegistry::getPassRegistry());
}

virtual bool runOnModule(Module &M);
};
}

char ExpandSmallArguments::ID = 0;
INITIALIZE_PASS(ExpandSmallArguments, "expand-small-arguments",
"Expand function arguments to be at least 32 bits in size",
false, false)

// Returns the normalized version of the given argument/return type.
static Type *NormalizeType(Type *Ty) {
if (IntegerType *IntTy = dyn_cast<IntegerType>(Ty)) {
if (IntTy->getBitWidth() < 32) {
return IntegerType::get(Ty->getContext(), 32);
}
}
return Ty;
}

// Returns the normalized version of the given function type.
static FunctionType *NormalizeFunctionType(FunctionType *FTy) {
if (FTy->isVarArg()) {
report_fatal_error(
"ExpandSmallArguments does not handle varargs functions");
}
SmallVector<Type *, 8> ArgTypes;
for (unsigned I = 0; I < FTy->getNumParams(); ++I) {
ArgTypes.push_back(NormalizeType(FTy->getParamType(I)));
}
return FunctionType::get(NormalizeType(FTy->getReturnType()),
ArgTypes, false);
}

// Convert the given function to use normalized argument/return types.
static bool ConvertFunction(Function *Func) {
FunctionType *FTy = Func->getFunctionType();
FunctionType *NFTy = NormalizeFunctionType(FTy);
if (NFTy == FTy)
return false; // No change needed.
Function *NewFunc = RecreateFunction(Func, NFTy);

// Move the arguments across to the new function.
for (Function::arg_iterator I = Func->arg_begin(), E = Func->arg_end(),
NewI = NewFunc->arg_begin();
I != E; ++I, ++NewI) {
auto Arg = &*I;
auto NewArg = &*NewI;
NewArg->takeName(Arg);
if (Arg->getType() == NewArg->getType()) {
Arg->replaceAllUsesWith(NewArg);
} else {
Instruction *Trunc = new TruncInst(
NewArg, Arg->getType(), NewArg->getName() + ".arg_trunc",
&*NewFunc->getEntryBlock().getFirstInsertionPt());
Arg->replaceAllUsesWith(Trunc);
}
}

if (FTy->getReturnType() != NFTy->getReturnType()) {
// Fix up return instructions.
Instruction::CastOps CastType =
Func->getAttributes().hasAttribute(0, Attribute::SExt) ?
Instruction::SExt : Instruction::ZExt;
for (Function::iterator BB = NewFunc->begin(), E = NewFunc->end();
BB != E;
++BB) {
for (BasicBlock::iterator Iter = BB->begin(), E = BB->end();
Iter != E; ) {
Instruction *Inst = &*Iter++;
if (ReturnInst *Ret = dyn_cast<ReturnInst>(Inst)) {
Value *Ext = CopyDebug(
CastInst::Create(CastType, Ret->getReturnValue(),
NFTy->getReturnType(),
Ret->getReturnValue()->getName() + ".ret_ext",
Ret),
Ret);
CopyDebug(ReturnInst::Create(Ret->getContext(), Ext, Ret), Ret);
Ret->eraseFromParent();
}
}
}
}

Func->eraseFromParent();
return true;
}

// Convert the given call to use normalized argument/return types.
template <class T> static bool ConvertCall(T *Call, Pass *P) {
// Don't try to change calls to intrinsics.
if (isa<IntrinsicInst>(Call))
return false;
FunctionType *FTy = cast<FunctionType>(
Call->getCalledValue()->getType()->getPointerElementType());
FunctionType *NFTy = NormalizeFunctionType(FTy);
if (NFTy == FTy)
return false; // No change needed.

// Convert arguments.
SmallVector<Value *, 8> Args;
for (unsigned I = 0; I < Call->getNumArgOperands(); ++I) {
Value *Arg = Call->getArgOperand(I);
if (NFTy->getParamType(I) != FTy->getParamType(I)) {
Instruction::CastOps CastType =
Call->getAttributes().hasAttribute(I + 1, Attribute::SExt) ?
Instruction::SExt : Instruction::ZExt;
Arg = CopyDebug(CastInst::Create(CastType, Arg, NFTy->getParamType(I),
"arg_ext", Call), Call);
}
Args.push_back(Arg);
}
Value *CastFunc =
CopyDebug(new BitCastInst(Call->getCalledValue(), NFTy->getPointerTo(),
Call->getName() + ".arg_cast", Call), Call);
Value *Result = NULL;
if (CallInst *OldCall = dyn_cast<CallInst>(Call)) {
CallInst *NewCall = CopyDebug(CallInst::Create(CastFunc, Args, "", OldCall),
OldCall);
NewCall->takeName(OldCall);
NewCall->setAttributes(OldCall->getAttributes());
NewCall->setCallingConv(OldCall->getCallingConv());
NewCall->setTailCall(OldCall->isTailCall());
Result = NewCall;

if (FTy->getReturnType() != NFTy->getReturnType()) {
Result = CopyDebug(new TruncInst(NewCall, FTy->getReturnType(),
NewCall->getName() + ".ret_trunc", Call),
Call);
}
} else if (InvokeInst *OldInvoke = dyn_cast<InvokeInst>(Call)) {
BasicBlock *Parent = OldInvoke->getParent();
BasicBlock *NormalDest = OldInvoke->getNormalDest();
BasicBlock *UnwindDest = OldInvoke->getUnwindDest();

if (FTy->getReturnType() != NFTy->getReturnType()) {
if (BasicBlock *SplitDest = SplitCriticalEdge(Parent, NormalDest)) {
NormalDest = SplitDest;
}
}

InvokeInst *New = CopyDebug(InvokeInst::Create(CastFunc, NormalDest,
UnwindDest, Args,
"", OldInvoke),
OldInvoke);
New->takeName(OldInvoke);

if (FTy->getReturnType() != NFTy->getReturnType()) {
Result = CopyDebug(new TruncInst(New, FTy->getReturnType(),
New->getName() + ".ret_trunc",
NormalDest->getTerminator()),
OldInvoke);
} else {
Result = New;
}

New->setAttributes(OldInvoke->getAttributes());
New->setCallingConv(OldInvoke->getCallingConv());
}
Call->replaceAllUsesWith(Result);
Call->eraseFromParent();
return true;
}

bool ExpandSmallArguments::runOnModule(Module &M) {
bool Changed = false;
for (Module::iterator Iter = M.begin(), E = M.end(); Iter != E; ) {
Function *Func = &*Iter++;
// Don't try to change intrinsic declarations because intrinsics
// will continue to have non-normalized argument types. For
// example, memset() takes an i8 argument. It shouldn't matter
// whether we modify the types of other function declarations, but
// we don't expect to see non-intrinsic function declarations in a
// PNaCl pexe.
if (Func->empty())
continue;

for (Function::iterator BB = Func->begin(), E = Func->end(); BB != E;
++BB) {
for (BasicBlock::iterator Iter = BB->begin(), E = BB->end(); Iter != E;) {
Instruction *Inst = &*Iter++;
if (CallInst *Call = dyn_cast<CallInst>(Inst)) {
Changed |= ConvertCall(Call, this);
} else if (InvokeInst *Invoke = dyn_cast<InvokeInst>(Inst)) {
Changed |= ConvertCall(Invoke, this);
}
}
}

Changed |= ConvertFunction(Func);
}
return Changed;
}

ModulePass *llvm::createExpandSmallArgumentsPass() {
return new ExpandSmallArguments();
}

Large diffs are not rendered by default.

Oops, something went wrong.
@@ -0,0 +1,336 @@
//===- ExpandTls.cpp - Convert TLS variables to a concrete layout----------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This pass expands out uses of thread-local (TLS) variables into
// more primitive operations.
//
// A reference to the address of a TLS variable is expanded into code
// which gets the current thread's thread pointer using
// @llvm.nacl.read.tp() and adds a fixed offset.
//
// This pass allocates the offsets (relative to the thread pointer)
// that will be used for TLS variables. It sets up the global
// variables __tls_template_start, __tls_template_end etc. to contain
// a template for initializing TLS variables' values for each thread.
// This is a task normally performed by the linker in ELF systems.
//
//===----------------------------------------------------------------------===//

#include <vector>

#include "llvm/Pass.h"
#include "llvm/IR/Constants.h"
#include "llvm/IR/DataLayout.h"
#include "llvm/IR/DerivedTypes.h"
#include "llvm/IR/Instructions.h"
#include "llvm/IR/Intrinsics.h"
#include "llvm/IR/Module.h"
#include "llvm/Transforms/NaCl.h"

using namespace llvm;

namespace {
struct VarInfo {
GlobalVariable *TlsVar;
bool IsBss; // Whether variable is in zero-intialized part of template
int TemplateIndex;
};

class PassState {
public:
PassState(Module *M): M(M), DL(M), Offset(0), Alignment(1) {}

Module *M;
DataLayout DL;
uint64_t Offset;
// 'Alignment' is the maximum variable alignment seen so far, in
// bytes. After visiting all TLS variables, this is the overall
// alignment required for the TLS template.
uint32_t Alignment;
};

class ExpandTls : public ModulePass {
public:
static char ID; // Pass identification, replacement for typeid
ExpandTls() : ModulePass(ID) {
initializeExpandTlsPass(*PassRegistry::getPassRegistry());
}

virtual bool runOnModule(Module &M);
};
}

char ExpandTls::ID = 0;
INITIALIZE_PASS(ExpandTls, "nacl-expand-tls",
"Expand out TLS variables and fix TLS variable layout",
false, false)

static void setGlobalVariableValue(Module &M, const char *Name,
Constant *Value) {
if (GlobalVariable *Var = M.getNamedGlobal(Name)) {
if (Var->hasInitializer()) {
report_fatal_error(std::string("Variable ") + Name +
" already has an initializer");
}
Var->replaceAllUsesWith(ConstantExpr::getBitCast(Value, Var->getType()));
Var->eraseFromParent();
}
}

// Insert alignment padding into the TLS template.
static void padToAlignment(PassState *State,
std::vector<Type*> *FieldTypes,
std::vector<Constant*> *FieldValues,
unsigned Alignment) {
if ((State->Offset & (Alignment - 1)) != 0) {
unsigned PadSize = Alignment - (State->Offset & (Alignment - 1));
Type *i8 = Type::getInt8Ty(State->M->getContext());
Type *PadType = ArrayType::get(i8, PadSize);
FieldTypes->push_back(PadType);
if (FieldValues)
FieldValues->push_back(Constant::getNullValue(PadType));
State->Offset += PadSize;
}
if (State->Alignment < Alignment) {
State->Alignment = Alignment;
}
}

static void addVarToTlsTemplate(PassState *State,
std::vector<Type*> *FieldTypes,
std::vector<Constant*> *FieldValues,
GlobalVariable *TlsVar) {
unsigned Alignment = State->DL.getPreferredAlignment(TlsVar);
padToAlignment(State, FieldTypes, FieldValues, Alignment);

FieldTypes->push_back(TlsVar->getType()->getElementType());
if (FieldValues)
FieldValues->push_back(TlsVar->getInitializer());
State->Offset +=
State->DL.getTypeAllocSize(TlsVar->getType()->getElementType());
}

static StructType *buildTlsTemplate(Module &M, std::vector<VarInfo> *TlsVars) {
std::vector<Type*> FieldBssTypes;
std::vector<Type*> FieldInitTypes;
std::vector<Constant*> FieldInitValues;
PassState State(&M);

for (Module::global_iterator GV = M.global_begin();
GV != M.global_end();
++GV) {
if (GV->isThreadLocal()) {
if (!GV->hasInitializer()) {
// Since this is a whole-program transformation, "extern" TLS
// variables are not allowed at this point.
report_fatal_error(std::string("TLS variable without an initializer: ")
+ GV->getName());
}
if (!GV->getInitializer()->isNullValue()) {
addVarToTlsTemplate(&State, &FieldInitTypes,
&FieldInitValues, &*GV);
VarInfo Info;
Info.TlsVar = &*GV;
Info.IsBss = false;
Info.TemplateIndex = FieldInitTypes.size() - 1;
TlsVars->push_back(Info);
}
}
}
// Handle zero-initialized TLS variables in a second pass, because
// these should follow non-zero-initialized TLS variables.
for (Module::global_iterator GV = M.global_begin();
GV != M.global_end();
++GV) {
if (GV->isThreadLocal() && GV->getInitializer()->isNullValue()) {
addVarToTlsTemplate(&State, &FieldBssTypes, NULL, &*GV);
VarInfo Info;
Info.TlsVar = &*GV;
Info.IsBss = true;
Info.TemplateIndex = FieldBssTypes.size() - 1;
TlsVars->push_back(Info);
}
}
// Add final alignment padding so that
// (struct tls_struct *) __nacl_read_tp() - 1
// gives the correct, aligned start of the TLS variables given the
// x86-style layout we are using. This requires some more bytes to
// be memset() to zero at runtime. This wastage doesn't seem
// important gives that we're not trying to optimize packing by
// reordering to put similarly-aligned variables together.
padToAlignment(&State, &FieldBssTypes, NULL, State.Alignment);

// We create the TLS template structs as "packed" because we insert
// alignment padding ourselves, and LLVM's implicit insertion of
// padding would interfere with ours. tls_bss_template can start at
// a non-aligned address immediately following the last field in
// tls_init_template.
StructType *InitTemplateType =
StructType::create(M.getContext(), "tls_init_template");
InitTemplateType->setBody(FieldInitTypes, /*isPacked=*/true);
StructType *BssTemplateType =
StructType::create(M.getContext(), "tls_bss_template");
BssTemplateType->setBody(FieldBssTypes, /*isPacked=*/true);

StructType *TemplateType = StructType::create(M.getContext(), "tls_struct");
SmallVector<Type*, 2> TemplateTopFields;
TemplateTopFields.push_back(InitTemplateType);
TemplateTopFields.push_back(BssTemplateType);
TemplateType->setBody(TemplateTopFields, /*isPacked=*/true);
PointerType *TemplatePtrType = PointerType::get(TemplateType, 0);

// We define the following symbols, which are the same as those
// defined by NaCl's original customized binutils linker scripts:
// __tls_template_start
// __tls_template_tdata_end
// __tls_template_end
// We also define __tls_template_alignment, which was not defined by
// the original linker scripts.

const char *StartSymbol = "__tls_template_start";
Constant *TemplateData = ConstantStruct::get(InitTemplateType,
FieldInitValues);
GlobalVariable *TemplateDataVar =
new GlobalVariable(M, InitTemplateType, /*isConstant=*/true,
GlobalValue::InternalLinkage, TemplateData);
setGlobalVariableValue(M, StartSymbol, TemplateDataVar);
TemplateDataVar->setName(StartSymbol);

Constant *TdataEnd = ConstantExpr::getGetElementPtr(
InitTemplateType,
TemplateDataVar,
ConstantInt::get(M.getContext(), APInt(32, 1)));
setGlobalVariableValue(M, "__tls_template_tdata_end", TdataEnd);

Constant *TotalEnd = ConstantExpr::getGetElementPtr(
TemplateType,
ConstantExpr::getBitCast(TemplateDataVar, TemplatePtrType),
ConstantInt::get(M.getContext(), APInt(32, 1)));
setGlobalVariableValue(M, "__tls_template_end", TotalEnd);

const char *AlignmentSymbol = "__tls_template_alignment";
Type *i32 = Type::getInt32Ty(M.getContext());
GlobalVariable *AlignmentVar = new GlobalVariable(
M, i32, /*isConstant=*/true,
GlobalValue::InternalLinkage,
ConstantInt::get(M.getContext(), APInt(32, State.Alignment)));
setGlobalVariableValue(M, AlignmentSymbol, AlignmentVar);
AlignmentVar->setName(AlignmentSymbol);

return TemplateType;
}

static void rewriteTlsVars(Module &M, std::vector<VarInfo> *TlsVars,
StructType *TemplateType) {
// Set up the intrinsic that reads the thread pointer.
Function *ReadTpFunc = Intrinsic::getDeclaration(&M, Intrinsic::nacl_read_tp);

for (std::vector<VarInfo>::iterator VarInfo = TlsVars->begin();
VarInfo != TlsVars->end();
++VarInfo) {
GlobalVariable *Var = VarInfo->TlsVar;
while (Var->hasNUsesOrMore(1)) {
Use *U = &*Var->use_begin();
Instruction *InsertPt = PhiSafeInsertPt(U);
Value *RawThreadPtr = CallInst::Create(ReadTpFunc, "tls_raw", InsertPt);
Value *TypedThreadPtr = new BitCastInst(
RawThreadPtr, TemplateType->getPointerTo(), "tls_struct", InsertPt);
SmallVector<Value*, 3> Indexes;
// We use -1 because we use the x86-style TLS layout in which
// the TLS data is stored at addresses below the thread pointer.
// This is largely because a check in nacl_irt_thread_create()
// in irt/irt_thread.c requires the thread pointer to be a
// self-pointer on x86-32.
// TODO(mseaborn): I intend to remove that check because it is
// non-portable. In the mean time, we want PNaCl pexes to work
// in older Chromium releases when translated to nexes.
Indexes.push_back(ConstantInt::get(
M.getContext(), APInt(32, -1)));
Indexes.push_back(ConstantInt::get(
M.getContext(), APInt(32, VarInfo->IsBss ? 1 : 0)));
Indexes.push_back(ConstantInt::get(
M.getContext(), APInt(32, VarInfo->TemplateIndex)));
Value *TlsField = GetElementPtrInst::Create(
TemplateType, TypedThreadPtr, Indexes, "field", InsertPt);
PhiSafeReplaceUses(U, TlsField);
}
VarInfo->TlsVar->eraseFromParent();
}
}

static void replaceFunction(Module &M, const char *Name, Value *NewFunc) {
if (Function *Func = M.getFunction(Name)) {
if (Func->hasLocalLinkage())
return;
if (!Func->isDeclaration())
report_fatal_error(std::string("Function already defined: ") + Name);
Func->replaceAllUsesWith(NewFunc);
Func->eraseFromParent();
}
}

// Provide fixed definitions for NaCl's TLS layout functions,
// __nacl_tp_*(). We adopt the x86-style layout: ExpandTls will
// output a program that uses the x86-style layout wherever it runs.
//
// This overrides the architecture-specific definitions of
// __nacl_tp_*() that PNaCl's native support code makes available to
// non-ABI-stable code.
static void defineTlsLayoutFunctions(Module &M) {
Type *i32 = Type::getInt32Ty(M.getContext());
SmallVector<Type*, 1> ArgTypes;
ArgTypes.push_back(i32);
FunctionType *FuncType = FunctionType::get(i32, ArgTypes, /*isVarArg=*/false);
Function *NewFunc;
BasicBlock *BB;

// Define the function as follows:
// uint32_t __nacl_tp_tdb_offset(uint32_t tdb_size) {
// return 0;
// }
// This means the thread pointer points to the TDB.
NewFunc = Function::Create(FuncType, GlobalValue::InternalLinkage,
"nacl_tp_tdb_offset", &M);
BB = BasicBlock::Create(M.getContext(), "entry", NewFunc);
ReturnInst::Create(M.getContext(),
ConstantInt::get(M.getContext(), APInt(32, 0)), BB);
replaceFunction(M, "__nacl_tp_tdb_offset", NewFunc);

// Define the function as follows:
// uint32_t __nacl_tp_tls_offset(uint32_t tls_size) {
// return -tls_size;
// }
// This means the TLS variables are stored below the thread pointer.
NewFunc = Function::Create(FuncType, GlobalValue::InternalLinkage,
"nacl_tp_tls_offset", &M);
BB = BasicBlock::Create(M.getContext(), "entry", NewFunc);
Value *Arg = &*NewFunc->arg_begin();
Arg->setName("size");
Value *Result = BinaryOperator::CreateNeg(Arg, "result", BB);
ReturnInst::Create(M.getContext(), Result, BB);
replaceFunction(M, "__nacl_tp_tls_offset", NewFunc);
}

bool ExpandTls::runOnModule(Module &M) {
ModulePass *Pass = createExpandTlsConstantExprPass();
Pass->runOnModule(M);
delete Pass;

std::vector<VarInfo> TlsVars;
StructType *TemplateType = buildTlsTemplate(M, &TlsVars);
rewriteTlsVars(M, &TlsVars, TemplateType);

defineTlsLayoutFunctions(M);

return true;
}

ModulePass *llvm::createExpandTlsPass() {
return new ExpandTls();
}
@@ -0,0 +1,107 @@
//===- ExpandTlsConstantExpr.cpp - Convert ConstantExprs to Instructions---===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This pass is a helper used by the ExpandTls pass.
//
// LLVM treats the address of a TLS variable as a ConstantExpr. This
// is arguably a bug because the address of a TLS variable is *not* a
// constant: it varies between threads.
//
// See http://llvm.org/bugs/show_bug.cgi?id=14353
//
// This is also a problem for the ExpandTls pass, which wants to use
// replaceUsesOfWith() to replace each TLS variable with an
// Instruction sequence that calls @llvm.nacl.read.tp(). This doesn't
// work if the TLS variable is used inside other ConstantExprs,
// because ConstantExprs are interned and are not associated with any
// function, whereas each Instruction must be part of a function.
//
// To fix that problem, this pass converts ConstantExprs that
// reference TLS variables into Instructions.
//
// For example, this use of a 'ptrtoint' ConstantExpr:
//
// ret i32 ptrtoint (i32* @tls_var to i32)
//
// is converted into this 'ptrtoint' Instruction:
//
// %expanded = ptrtoint i32* @tls_var to i32
// ret i32 %expanded
//
//===----------------------------------------------------------------------===//

#include <vector>

#include "llvm/Pass.h"
#include "llvm/IR/Constants.h"
#include "llvm/IR/Instructions.h"
#include "llvm/IR/Module.h"
#include "llvm/Transforms/NaCl.h"

using namespace llvm;

namespace {
class ExpandTlsConstantExpr : public ModulePass {
public:
static char ID; // Pass identification, replacement for typeid
ExpandTlsConstantExpr() : ModulePass(ID) {
initializeExpandTlsConstantExprPass(*PassRegistry::getPassRegistry());
}

virtual bool runOnModule(Module &M);
};
}

char ExpandTlsConstantExpr::ID = 0;
INITIALIZE_PASS(ExpandTlsConstantExpr, "nacl-expand-tls-constant-expr",
"Eliminate ConstantExpr references to TLS variables",
false, false)

// This removes ConstantExpr references to the given Constant.
static void expandConstExpr(Constant *Expr) {
// First, ensure that ConstantExpr references to Expr are converted
// to Instructions so that we can modify them.
for (Use &U : Expr->uses())
if (ConstantExpr *CE = dyn_cast<ConstantExpr>(U.getUser()))
expandConstExpr(CE);
Expr->removeDeadConstantUsers();

if (ConstantExpr *CE = dyn_cast<ConstantExpr>(Expr)) {
while (Expr->hasNUsesOrMore(1)) {
Use *U = &*Expr->use_begin();
Instruction *NewInst = CE->getAsInstruction();
NewInst->insertBefore(PhiSafeInsertPt(U));
NewInst->setName("expanded");
PhiSafeReplaceUses(U, NewInst);
}
}
}

bool ExpandTlsConstantExpr::runOnModule(Module &M) {
for (Module::alias_iterator Iter = M.alias_begin();
Iter != M.alias_end(); ) {
GlobalAlias *GA = &*Iter++;
if (GA->isThreadDependent()) {
GA->replaceAllUsesWith(GA->getAliasee());
GA->eraseFromParent();
}
}
for (Module::global_iterator Global = M.global_begin();
Global != M.global_end();
++Global) {
if (Global->isThreadLocal()) {
expandConstExpr(&*Global);
}
}
return true;
}

ModulePass *llvm::createExpandTlsConstantExprPass() {
return new ExpandTlsConstantExpr();
}
@@ -0,0 +1,58 @@
//===-- ExpandUtils.cpp - Helper functions for expansion passes -----------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

#include "llvm/IR/BasicBlock.h"
#include "llvm/IR/Constants.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/Instructions.h"
#include "llvm/IR/Module.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Transforms/NaCl.h"

using namespace llvm;

Instruction *llvm::PhiSafeInsertPt(Use *U) {
Instruction *InsertPt = cast<Instruction>(U->getUser());
if (PHINode *PN = dyn_cast<PHINode>(InsertPt)) {
// We cannot insert instructions before a PHI node, so insert
// before the incoming block's terminator. This could be
// suboptimal if the terminator is a conditional.
InsertPt = PN->getIncomingBlock(*U)->getTerminator();
}
return InsertPt;
}

void llvm::PhiSafeReplaceUses(Use *U, Value *NewVal) {
User *UR = U->getUser();
if (PHINode *PN = dyn_cast<PHINode>(UR)) {
// A PHI node can have multiple incoming edges from the same
// block, in which case all these edges must have the same
// incoming value.
BasicBlock *BB = PN->getIncomingBlock(*U);
for (unsigned I = 0; I < PN->getNumIncomingValues(); ++I) {
if (PN->getIncomingBlock(I) == BB)
PN->setIncomingValue(I, NewVal);
}
} else {
UR->replaceUsesOfWith(U->get(), NewVal);
}
}

Function *llvm::RecreateFunction(Function *Func, FunctionType *NewType) {
Function *NewFunc = Function::Create(NewType, Func->getLinkage());
NewFunc->copyAttributesFrom(Func);
Func->getParent()->getFunctionList().insert(Func->getIterator(), NewFunc);
NewFunc->takeName(Func);
NewFunc->getBasicBlockList().splice(NewFunc->begin(),
Func->getBasicBlockList());
Func->replaceAllUsesWith(
ConstantExpr::getBitCast(NewFunc,
Func->getFunctionType()->getPointerTo()));
return NewFunc;
}
@@ -0,0 +1,324 @@
//===- ExpandVarArgs.cpp - Expand out variable argument function calls-----===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This pass expands out all use of variable argument functions.
//
// This pass replaces a varargs function call with a function call in
// which a pointer to the variable arguments is passed explicitly.
// The callee explicitly allocates space for the variable arguments on
// the stack using "alloca".
//
//===----------------------------------------------------------------------===//

#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/Triple.h"
#include "llvm/IR/Constants.h"
#include "llvm/IR/DataLayout.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/IRBuilder.h"
#include "llvm/IR/Instructions.h"
#include "llvm/IR/IntrinsicInst.h"
#include "llvm/IR/Module.h"
#include "llvm/Pass.h"
#include "llvm/Transforms/NaCl.h"

using namespace llvm;

namespace {
class ExpandVarArgs : public ModulePass {
public:
static char ID;
ExpandVarArgs() : ModulePass(ID) {
initializeExpandVarArgsPass(*PassRegistry::getPassRegistry());
}
virtual bool runOnModule(Module &M);
};
}

char ExpandVarArgs::ID = 0;
INITIALIZE_PASS(ExpandVarArgs, "expand-varargs",
"Expand out variable argument function definitions and calls",
false, false)

static bool isEmscriptenJSArgsFunc(Module *M, StringRef Name) {
// TODO(jfb) Make these intrinsics in clang and remove the assert: these
// intrinsics should only exist for Emscripten.
bool isEmscriptenSpecial = Name.equals("emscripten_asm_const_int") ||
Name.equals("emscripten_asm_const_double") ||
Name.equals("emscripten_landingpad") ||
Name.equals("emscripten_resume");
assert(isEmscriptenSpecial ? Triple(M->getTargetTriple()).isOSEmscripten()
: true);
return isEmscriptenSpecial;
}

static bool ExpandVarArgFunc(Module *M, Function *Func) {
if (Func->isDeclaration() && Func->use_empty())
return false; // No point in doing any work.

if (isEmscriptenJSArgsFunc(M, Func->getName()))
return false;

Type *PtrType = Type::getInt8PtrTy(Func->getContext());

FunctionType *FTy = Func->getFunctionType();
SmallVector<Type *, 8> Params(FTy->param_begin(), FTy->param_end());
Params.push_back(PtrType);
FunctionType *NFTy =
FunctionType::get(FTy->getReturnType(), Params, /*isVarArg=*/false);
Function *NewFunc = RecreateFunction(Func, NFTy);

// Declare the new argument as "noalias".
NewFunc->setAttributes(Func->getAttributes().addAttribute(
Func->getContext(), FTy->getNumParams() + 1, Attribute::NoAlias));

// Move the arguments across to the new function.
auto NewArg = NewFunc->arg_begin();
for (Argument &Arg : Func->args()) {
Arg.replaceAllUsesWith(&*NewArg);
NewArg->takeName(&Arg);
++NewArg;
}
// The last argument is the new `i8 * noalias %varargs`.
NewArg->setName("varargs");

Func->eraseFromParent();

// Expand out uses of llvm.va_start in this function.
for (BasicBlock &BB : *NewFunc) {
for (auto BI = BB.begin(), BE = BB.end(); BI != BE;) {
Instruction *I = &*BI++;
if (auto *VAS = dyn_cast<VAStartInst>(I)) {
IRBuilder<> IRB(VAS);
Value *Cast = IRB.CreateBitCast(VAS->getArgList(),
PtrType->getPointerTo(), "arglist");
IRB.CreateStore(&*NewArg, Cast);
VAS->eraseFromParent();
}
}
}

return true;
}

static void ExpandVAArgInst(VAArgInst *Inst, DataLayout *DL) {
Type *IntPtrTy = DL->getIntPtrType(Inst->getContext());
auto *One = ConstantInt::get(IntPtrTy, 1);
IRBuilder<> IRB(Inst);
auto *ArgList = IRB.CreateBitCast(
Inst->getPointerOperand(),
Inst->getType()->getPointerTo()->getPointerTo(), "arglist");

// The caller spilled all of the va_args onto the stack in an unpacked
// struct. Each va_arg load from that struct needs to realign the element to
// its target-appropriate alignment in the struct in order to jump over
// padding that may have been in-between arguments. Do this with ConstantExpr
// to ensure good code gets generated, following the same approach as
// Support/MathExtras.h:alignAddr:
// ((uintptr_t)Addr + Alignment - 1) & ~(uintptr_t)(Alignment - 1)
// This assumes the alignment of the type is a power of 2 (or 1, in which case
// no realignment occurs).
auto *Ptr = IRB.CreateLoad(ArgList, "arglist_current");
auto *AlignOf = ConstantExpr::getIntegerCast(
ConstantExpr::getAlignOf(Inst->getType()), IntPtrTy, /*isSigned=*/false);
auto *AlignMinus1 = ConstantExpr::getNUWSub(AlignOf, One);
auto *NotAlignMinus1 = IRB.CreateNot(AlignMinus1);
auto *CurrentPtr = IRB.CreateIntToPtr(
IRB.CreateAnd(
IRB.CreateNUWAdd(IRB.CreatePtrToInt(Ptr, IntPtrTy), AlignMinus1),
NotAlignMinus1),
Ptr->getType());

auto *Result = IRB.CreateLoad(CurrentPtr, "va_arg");
Result->takeName(Inst);

// Update the va_list to point to the next argument.
Value *Indexes[] = {One};
auto *Next = IRB.CreateInBoundsGEP(CurrentPtr, Indexes, "arglist_next");
IRB.CreateStore(Next, ArgList);

Inst->replaceAllUsesWith(Result);
Inst->eraseFromParent();
}

static void ExpandVAEnd(VAEndInst *VAE) {
// va_end() is a no-op in this implementation.
VAE->eraseFromParent();
}

static void ExpandVACopyInst(VACopyInst *Inst) {
// va_list may have more space reserved, but we only need to
// copy a single pointer.
Type *PtrTy = Type::getInt8PtrTy(Inst->getContext())->getPointerTo();
IRBuilder<> IRB(Inst);
auto *Src = IRB.CreateBitCast(Inst->getSrc(), PtrTy, "vacopy_src");
auto *Dest = IRB.CreateBitCast(Inst->getDest(), PtrTy, "vacopy_dest");
auto *CurrentPtr = IRB.CreateLoad(Src, "vacopy_currentptr");
IRB.CreateStore(CurrentPtr, Dest);
Inst->eraseFromParent();
}

// ExpandVarArgCall() converts a CallInst or InvokeInst to expand out
// of varargs. It returns whether the module was modified.
template <class InstType>
static bool ExpandVarArgCall(Module *M, InstType *Call, DataLayout *DL) {
FunctionType *FuncType = cast<FunctionType>(
Call->getCalledValue()->getType()->getPointerElementType());
if (!FuncType->isFunctionVarArg())
return false;
if (auto *F = dyn_cast<Function>(Call->getCalledValue()))
if (isEmscriptenJSArgsFunc(M, F->getName()))
return false;

Function *F = Call->getParent()->getParent();
LLVMContext &Ctx = M->getContext();

SmallVector<AttributeSet, 8> Attrs;
Attrs.push_back(Call->getAttributes().getFnAttributes());
Attrs.push_back(Call->getAttributes().getRetAttributes());

// Split argument list into fixed and variable arguments.
SmallVector<Value *, 8> FixedArgs;
SmallVector<Value *, 8> VarArgs;
SmallVector<Type *, 8> VarArgsTypes;
for (unsigned I = 0, E = FuncType->getNumParams(); I < E; ++I) {
FixedArgs.push_back(Call->getArgOperand(I));
// AttributeSets use 1-based indexing.
Attrs.push_back(Call->getAttributes().getParamAttributes(I + 1));
}
for (unsigned I = FuncType->getNumParams(), E = Call->getNumArgOperands();
I < E; ++I) {
Value *ArgVal = Call->getArgOperand(I);
VarArgs.push_back(ArgVal);
bool isByVal = Call->getAttributes().hasAttribute(I + 1, Attribute::ByVal);
// For "byval" arguments we must dereference the pointer.
VarArgsTypes.push_back(isByVal ? ArgVal->getType()->getPointerElementType()
: ArgVal->getType());
}
if (VarArgsTypes.size() == 0) {
// Some buggy code (e.g. 176.gcc in Spec2k) uses va_arg on an
// empty argument list, which gives undefined behaviour in C. To
// work around such programs, we create a dummy varargs buffer on
// the stack even though there are no arguments to put in it.
// This allows va_arg to read an undefined value from the stack
// rather than crashing by reading from an uninitialized pointer.
// An alternative would be to pass a null pointer to catch the
// invalid use of va_arg.
VarArgsTypes.push_back(Type::getInt32Ty(Ctx));
}

// Create struct type for packing variable arguments into.
StructType *VarArgsTy = StructType::get(Ctx, VarArgsTypes);

// Allocate space for the variable argument buffer. Do this at the
// start of the function so that we don't leak space if the function
// is called in a loop.
IRBuilder<> IRB(&*F->getEntryBlock().getFirstInsertionPt());
auto *Buf = IRB.CreateAlloca(VarArgsTy, nullptr, "vararg_buffer");

// Call llvm.lifetime.start/end intrinsics to indicate that Buf is
// only used for the duration of the function call, so that the
// stack space can be reused elsewhere.
auto LifetimeStart = Intrinsic::getDeclaration(M, Intrinsic::lifetime_start);
auto LifetimeEnd = Intrinsic::getDeclaration(M, Intrinsic::lifetime_end);
auto *I8Ptr = Type::getInt8Ty(Ctx)->getPointerTo();
auto *BufPtr = IRB.CreateBitCast(Buf, I8Ptr, "vararg_lifetime_bitcast");
auto *BufSize =
ConstantInt::get(Ctx, APInt(64, DL->getTypeAllocSize(VarArgsTy)));
IRB.CreateCall(LifetimeStart, {BufSize, BufPtr});

// Copy variable arguments into buffer.
int Index = 0;
IRB.SetInsertPoint(Call);
for (Value *Arg : VarArgs) {
Value *Indexes[] = {ConstantInt::get(Ctx, APInt(32, 0)),
ConstantInt::get(Ctx, APInt(32, Index))};
Value *Ptr = IRB.CreateInBoundsGEP(Buf, Indexes, "vararg_ptr");
bool isByVal = Call->getAttributes().hasAttribute(
FuncType->getNumParams() + Index + 1, Attribute::ByVal);
if (isByVal)
IRB.CreateMemCpy(Ptr, Arg, DL->getTypeAllocSize(
Arg->getType()->getPointerElementType()),
/*Align=*/1);
else
IRB.CreateStore(Arg, Ptr);
++Index;
}

// Cast function to new type to add our extra pointer argument.
SmallVector<Type *, 8> ArgTypes(FuncType->param_begin(),
FuncType->param_end());
ArgTypes.push_back(VarArgsTy->getPointerTo());
FunctionType *NFTy = FunctionType::get(FuncType->getReturnType(), ArgTypes,
/*isVarArg=*/false);
Value *CastFunc = IRB.CreateBitCast(Call->getCalledValue(),
NFTy->getPointerTo(), "vararg_func");

// Create the converted function call.
FixedArgs.push_back(Buf);
Instruction *NewCall;
if (auto *C = dyn_cast<CallInst>(Call)) {
auto *N = IRB.CreateCall(CastFunc, FixedArgs);
N->setAttributes(AttributeSet::get(Ctx, Attrs));
NewCall = N;
IRB.CreateCall(LifetimeEnd, {BufSize, BufPtr});
} else if (auto *C = dyn_cast<InvokeInst>(Call)) {
auto *N = IRB.CreateInvoke(CastFunc, C->getNormalDest(), C->getUnwindDest(),
FixedArgs, C->getName());
N->setAttributes(AttributeSet::get(Ctx, Attrs));
(IRBuilder<>(&*C->getNormalDest()->getFirstInsertionPt()))
.CreateCall(LifetimeEnd, {BufSize, BufPtr});
(IRBuilder<>(&*C->getUnwindDest()->getFirstInsertionPt()))
.CreateCall(LifetimeEnd, {BufSize, BufPtr});
NewCall = N;
} else {
llvm_unreachable("not a call/invoke");
}

NewCall->takeName(Call);
Call->replaceAllUsesWith(NewCall);
Call->eraseFromParent();

return true;
}

bool ExpandVarArgs::runOnModule(Module &M) {
bool Changed = false;
DataLayout DL(&M);

for (auto MI = M.begin(), ME = M.end(); MI != ME;) {
Function *F = &*MI++;
for (BasicBlock &BB : *F) {
for (auto BI = BB.begin(), BE = BB.end(); BI != BE;) {
Instruction *I = &*BI++;
if (auto *VI = dyn_cast<VAArgInst>(I)) {
Changed = true;
ExpandVAArgInst(VI, &DL);
} else if (auto *VAE = dyn_cast<VAEndInst>(I)) {
Changed = true;
ExpandVAEnd(VAE);
} else if (auto *VAC = dyn_cast<VACopyInst>(I)) {
Changed = true;
ExpandVACopyInst(VAC);
} else if (auto *Call = dyn_cast<CallInst>(I)) {
Changed |= ExpandVarArgCall(&M, Call, &DL);
} else if (auto *Call = dyn_cast<InvokeInst>(I)) {
Changed |= ExpandVarArgCall(&M, Call, &DL);
}
}
}

if (F->isVarArg())
Changed |= ExpandVarArgFunc(&M, F);
}

return Changed;
}

ModulePass *llvm::createExpandVarArgsPass() { return new ExpandVarArgs(); }
@@ -0,0 +1,264 @@
//===- FixVectorLoadStoreAlignment.cpp - Vector load/store alignment ------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// Fix vector load/store alignment by:
// - Leaving as-is if the alignment is equal to the vector's element width.
// - Reducing the alignment to vector's element width if it's greater and the
// current alignment is a factor of the element alignment.
// - Scalarizing if the alignment is smaller than the element-wise alignment.
//
// Volatile vector load/store are handled the same, and can therefore be broken
// up as allowed by C/C++.
//
// TODO(jfb) Atomic accesses cause errors at compile-time. This could be
// implemented as a call to the C++ runtime, since 128-bit atomics
// aren't usually lock-free.
//
//===----------------------------------------------------------------------===//

#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/Support/Debug.h"
#include "llvm/Support/MathExtras.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Transforms/NaCl.h"

using namespace llvm;

namespace {
class FixVectorLoadStoreAlignment : public BasicBlockPass {
public:
static char ID; // Pass identification, replacement for typeid
FixVectorLoadStoreAlignment() : BasicBlockPass(ID), M(0), DL(0) {
initializeFixVectorLoadStoreAlignmentPass(*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;

/// Some sub-classes of Instruction have a non-virtual function
/// indicating which operand is the pointer operand. This template
/// function returns the pointer operand's type, and requires that
/// InstTy have a getPointerOperand function.
template <typename InstTy>
static PointerType *pointerOperandType(const InstTy *I) {
return cast<PointerType>(I->getPointerOperand()->getType());
}

/// Similar to pointerOperandType, this template function checks
/// whether the pointer operand is a pointer to a vector type.
template <typename InstTy>
static bool pointerOperandIsVectorPointer(const Instruction *I) {
return pointerOperandType(cast<InstTy>(I))->getElementType()->isVectorTy();
}

/// Returns true if one of the Instruction's operands is a pointer to
/// a vector type. This is more general than the above and assumes we
/// don't know which Instruction type is provided.
static bool hasVectorPointerOperand(const Instruction *I) {
for (User::const_op_iterator IB = I->op_begin(), IE = I->op_end(); IB != IE;
++IB)
if (PointerType *PtrTy = dyn_cast<PointerType>((*IB)->getType()))
if (isa<VectorType>(PtrTy->getElementType()))
return true;
return false;
}

/// Vectors are expected to be element-aligned. If they are, leave as-is; if
/// the alignment is too much then narrow the alignment (when possible);
/// otherwise return false.
template <typename InstTy>
static bool tryFixVectorAlignment(const DataLayout *DL, Instruction *I) {
InstTy *LoadStore = cast<InstTy>(I);
VectorType *VecTy =
cast<VectorType>(pointerOperandType(LoadStore)->getElementType());
Type *ElemTy = VecTy->getElementType();
uint64_t ElemBitSize = DL->getTypeSizeInBits(ElemTy);
uint64_t ElemByteSize = ElemBitSize / CHAR_BIT;
uint64_t CurrentByteAlign = LoadStore->getAlignment();
bool isABIAligned = CurrentByteAlign == 0;
uint64_t VecABIByteAlign = DL->getABITypeAlignment(VecTy);
CurrentByteAlign = isABIAligned ? VecABIByteAlign : CurrentByteAlign;

if (CHAR_BIT * ElemByteSize != ElemBitSize)
return false; // Minimum byte-size elements.
if (MinAlign(ElemByteSize, CurrentByteAlign) == ElemByteSize) {
// Element-aligned, or compatible over-aligned. Keep element-aligned.
LoadStore->setAlignment(ElemByteSize);
return true;
}
return false; // Under-aligned.
}

void visitVectorLoadStore(BasicBlock &BB, Instructions &Loads,
Instructions &Stores) const;
void scalarizeVectorLoadStore(BasicBlock &BB, const Instructions &Loads,
const Instructions &Stores) const;
};
} // anonymous namespace

char FixVectorLoadStoreAlignment::ID = 0;
INITIALIZE_PASS(FixVectorLoadStoreAlignment, "fix-vector-load-store-alignment",
"Ensure vector load/store have element-size alignment",
false, false)

void FixVectorLoadStoreAlignment::visitVectorLoadStore(
BasicBlock &BB, Instructions &Loads, Instructions &Stores) const {
for (BasicBlock::iterator BBI = BB.begin(), BBE = BB.end(); BBI != BBE;
++BBI) {
Instruction *I = &*BBI;
// The following list of instructions is based on mayReadOrWriteMemory.
switch (I->getOpcode()) {
case Instruction::Load:
if (pointerOperandIsVectorPointer<LoadInst>(I)) {
if (cast<LoadInst>(I)->isAtomic())
report_fatal_error("unhandled: atomic vector store");
if (!tryFixVectorAlignment<LoadInst>(DL, I))
Loads.push_back(I);
}
break;
case Instruction::Store:
if (pointerOperandIsVectorPointer<StoreInst>(I)) {
if (cast<StoreInst>(I)->isAtomic())
report_fatal_error("unhandled: atomic vector store");
if (!tryFixVectorAlignment<StoreInst>(DL, I))
Stores.push_back(I);
}
break;
case Instruction::Alloca:
case Instruction::Fence:
case Instruction::VAArg:
// Leave these memory operations as-is, even when they deal with
// vectors.
break;
case Instruction::Call:
case Instruction::Invoke:
// Call/invoke don't touch memory per-se, leave them as-is.
break;
case Instruction::AtomicCmpXchg:
if (pointerOperandIsVectorPointer<AtomicCmpXchgInst>(I))
report_fatal_error(
"unhandled: atomic compare and exchange operation on vector");
break;
case Instruction::AtomicRMW:
if (pointerOperandIsVectorPointer<AtomicRMWInst>(I))
report_fatal_error("unhandled: atomic RMW operation on vector");
break;
default:
if (I->mayReadOrWriteMemory() && hasVectorPointerOperand(I)) {
errs() << "Not handled: " << *I << '\n';
report_fatal_error(
"unexpected: vector operations which may read/write memory");
}
break;
}
}
}

void FixVectorLoadStoreAlignment::scalarizeVectorLoadStore(
BasicBlock &BB, const Instructions &Loads,
const Instructions &Stores) const {
for (Instructions::const_iterator IB = Loads.begin(), IE = Loads.end();
IB != IE; ++IB) {
LoadInst *VecLoad = cast<LoadInst>(*IB);
VectorType *LoadedVecTy =
cast<VectorType>(pointerOperandType(VecLoad)->getElementType());
Type *ElemTy = LoadedVecTy->getElementType();

// The base of the vector is as aligned as the vector load (where
// zero means ABI alignment for the vector), whereas subsequent
// elements are as aligned as the base+offset can be.
unsigned BaseAlign = VecLoad->getAlignment()
? VecLoad->getAlignment()
: DL->getABITypeAlignment(LoadedVecTy);
unsigned ElemAllocSize = DL->getTypeAllocSize(ElemTy);

// Fill in the vector element by element.
IRBuilder<> IRB(VecLoad);
Value *Loaded = UndefValue::get(LoadedVecTy);
Value *Base =
IRB.CreateBitCast(VecLoad->getPointerOperand(), ElemTy->getPointerTo());

for (unsigned Elem = 0, NumElems = LoadedVecTy->getNumElements();
Elem != NumElems; ++Elem) {
unsigned Align = MinAlign(BaseAlign, ElemAllocSize * Elem);
Value *GEP = IRB.CreateConstInBoundsGEP1_32(ElemTy, Base, Elem);
LoadInst *LoadedElem =
IRB.CreateAlignedLoad(GEP, Align, VecLoad->isVolatile());
LoadedElem->setSynchScope(VecLoad->getSynchScope());
Loaded = IRB.CreateInsertElement(
Loaded, LoadedElem,
ConstantInt::get(Type::getInt32Ty(M->getContext()), Elem));
}

VecLoad->replaceAllUsesWith(Loaded);
VecLoad->eraseFromParent();
}

for (Instructions::const_iterator IB = Stores.begin(), IE = Stores.end();
IB != IE; ++IB) {
StoreInst *VecStore = cast<StoreInst>(*IB);
Value *StoredVec = VecStore->getValueOperand();
VectorType *StoredVecTy = cast<VectorType>(StoredVec->getType());
Type *ElemTy = StoredVecTy->getElementType();

unsigned BaseAlign = VecStore->getAlignment()
? VecStore->getAlignment()
: DL->getABITypeAlignment(StoredVecTy);
unsigned ElemAllocSize = DL->getTypeAllocSize(ElemTy);

// Fill in the vector element by element.
IRBuilder<> IRB(VecStore);
Value *Base = IRB.CreateBitCast(VecStore->getPointerOperand(),
ElemTy->getPointerTo());

for (unsigned Elem = 0, NumElems = StoredVecTy->getNumElements();
Elem != NumElems; ++Elem) {
unsigned Align = MinAlign(BaseAlign, ElemAllocSize * Elem);
Value *GEP = IRB.CreateConstInBoundsGEP1_32(ElemTy, Base, Elem);
Value *ElemToStore = IRB.CreateExtractElement(
StoredVec, ConstantInt::get(Type::getInt32Ty(M->getContext()), Elem));
StoreInst *StoredElem = IRB.CreateAlignedStore(ElemToStore, GEP, Align,
VecStore->isVolatile());
StoredElem->setSynchScope(VecStore->getSynchScope());
}

VecStore->eraseFromParent();
}
}

bool FixVectorLoadStoreAlignment::runOnBasicBlock(BasicBlock &BB) {
bool Changed = false;
if (!DL)
DL = &BB.getParent()->getParent()->getDataLayout();
Instructions Loads;
Instructions Stores;
visitVectorLoadStore(BB, Loads, Stores);
if (!(Loads.empty() && Stores.empty())) {
Changed = true;
scalarizeVectorLoadStore(BB, Loads, Stores);
}
return Changed;
}

BasicBlockPass *llvm::createFixVectorLoadStoreAlignmentPass() {
return new FixVectorLoadStoreAlignment();
}
Oops, something went wrong.