aboutsummaryrefslogtreecommitdiff
path: root/lib/Transforms
diff options
context:
space:
mode:
Diffstat (limited to 'lib/Transforms')
-rw-r--r--lib/Transforms/CMakeLists.txt1
-rw-r--r--lib/Transforms/IPO/ExtractGV.cpp18
-rw-r--r--lib/Transforms/LLVMBuild.txt2
-rw-r--r--lib/Transforms/Makefile7
-rw-r--r--lib/Transforms/NaCl/CMakeLists.txt7
-rw-r--r--lib/Transforms/NaCl/ExpandCtors.cpp145
-rw-r--r--lib/Transforms/NaCl/ExpandTls.cpp351
-rw-r--r--lib/Transforms/NaCl/ExpandTlsConstantExpr.cpp110
-rw-r--r--lib/Transforms/NaCl/LLVMBuild.txt23
-rw-r--r--lib/Transforms/NaCl/Makefile15
-rw-r--r--lib/Transforms/Scalar/CMakeLists.txt1
-rw-r--r--lib/Transforms/Scalar/NaClCcRewrite.cpp1053
-rw-r--r--lib/Transforms/Utils/CloneModule.cpp6
-rw-r--r--lib/Transforms/Utils/SimplifyLibCalls.cpp7
14 files changed, 1742 insertions, 4 deletions
diff --git a/lib/Transforms/CMakeLists.txt b/lib/Transforms/CMakeLists.txt
index 2bb6e90590..328bc13cdd 100644
--- a/lib/Transforms/CMakeLists.txt
+++ b/lib/Transforms/CMakeLists.txt
@@ -6,3 +6,4 @@ add_subdirectory(IPO)
add_subdirectory(Vectorize)
add_subdirectory(Hello)
add_subdirectory(ObjCARC)
+add_subdirectory(NaCl)
diff --git a/lib/Transforms/IPO/ExtractGV.cpp b/lib/Transforms/IPO/ExtractGV.cpp
index 8a6bfc6d88..09f9d7c788 100644
--- a/lib/Transforms/IPO/ExtractGV.cpp
+++ b/lib/Transforms/IPO/ExtractGV.cpp
@@ -58,6 +58,15 @@ namespace {
continue;
if (I->getName() == "llvm.global_ctors")
continue;
+ // @LOCALMOD-BEGIN - this is likely upstreamable
+ // Note: there will likely be more cases once this
+ // is exercises more thorougly.
+ if (I->getName() == "llvm.global_dtors")
+ continue;
+ // not observed yet
+ if (I->hasExternalWeakLinkage())
+ continue;
+ // @LOCALMOD-END
}
bool Local = I->hasLocalLinkage();
@@ -78,8 +87,15 @@ namespace {
if (!Delete) {
if (I->hasAvailableExternallyLinkage())
continue;
+ // @LOCALMOD-BEGIN - this is likely upstreamable
+ // Note: there will likely be more cases once this
+ // is exercises more thorougly.
+ // observed for pthread_cancel
+ if (I->hasExternalWeakLinkage())
+ continue;
+ // @LOCALMOD-END
}
-
+
bool Local = I->hasLocalLinkage();
if (Local)
I->setVisibility(GlobalValue::HiddenVisibility);
diff --git a/lib/Transforms/LLVMBuild.txt b/lib/Transforms/LLVMBuild.txt
index 15e9fba0a7..3594de54a2 100644
--- a/lib/Transforms/LLVMBuild.txt
+++ b/lib/Transforms/LLVMBuild.txt
@@ -16,7 +16,7 @@
;===------------------------------------------------------------------------===;
[common]
-subdirectories = IPO InstCombine Instrumentation Scalar Utils Vectorize ObjCARC
+subdirectories = IPO InstCombine Instrumentation Scalar Utils Vectorize ObjCARC NaCl
[component_0]
type = Group
diff --git a/lib/Transforms/Makefile b/lib/Transforms/Makefile
index c390517d07..c2a2a6b485 100644
--- a/lib/Transforms/Makefile
+++ b/lib/Transforms/Makefile
@@ -8,7 +8,12 @@
##===----------------------------------------------------------------------===##
LEVEL = ../..
-PARALLEL_DIRS = Utils Instrumentation Scalar InstCombine IPO Vectorize Hello ObjCARC
+PARALLEL_DIRS = Utils Instrumentation Scalar InstCombine IPO Vectorize Hello ObjCARC NaCl
+
+
+ifeq ($(NACL_SANDBOX),1)
+ PARALLEL_DIRS := $(filter-out Hello, $(PARALLEL_DIRS))
+endif
include $(LEVEL)/Makefile.config
diff --git a/lib/Transforms/NaCl/CMakeLists.txt b/lib/Transforms/NaCl/CMakeLists.txt
new file mode 100644
index 0000000000..5e24cc7e28
--- /dev/null
+++ b/lib/Transforms/NaCl/CMakeLists.txt
@@ -0,0 +1,7 @@
+add_llvm_library(LLVMTransformsNaCl
+ ExpandCtors.cpp
+ ExpandTls.cpp
+ ExpandTlsConstantExpr.cpp
+ )
+
+add_dependencies(LLVMTransformsNaCl intrinsics_gen)
diff --git a/lib/Transforms/NaCl/ExpandCtors.cpp b/lib/Transforms/NaCl/ExpandCtors.cpp
new file mode 100644
index 0000000000..30d56fee6b
--- /dev/null
+++ b/lib/Transforms/NaCl/ExpandCtors.cpp
@@ -0,0 +1,145 @@
+//===- 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) {
+ GlobalVariable *Var = M.getNamedGlobal(Name);
+ if (!Var) {
+ // This warning can happen in a program that does not use a libc
+ // and so does not call the functions in __init_array_start or
+ // __fini_array_end. Such a program might be linked with
+ // "-nostdlib".
+ errs() << "Warning: Variable " << Name << " not referenced\n";
+ } else {
+ 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 defineFuncArray(Module &M, const char *LlvmArrayName,
+ const char *StartSymbol,
+ const char *EndSymbol) {
+ std::vector<Constant*> Funcs;
+
+ GlobalVariable *Array = M.getNamedGlobal(LlvmArrayName);
+ if (Array) {
+ if (Array->hasInitializer() && !Array->getInitializer()->isNullValue()) {
+ ConstantArray *InitList = cast<ConstantArray>(Array->getInitializer());
+ 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);
+ }
+ }
+ // 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(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();
+}
diff --git a/lib/Transforms/NaCl/ExpandTls.cpp b/lib/Transforms/NaCl/ExpandTls.cpp
new file mode 100644
index 0000000000..065226fedd
--- /dev/null
+++ b/lib/Transforms/NaCl/ExpandTls.cpp
@@ -0,0 +1,351 @@
+//===- 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/Module.h"
+#include "llvm/Support/raw_ostream.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) {
+ GlobalVariable *Var = M.getNamedGlobal(Name);
+ if (!Var) {
+ // This warning can happen in a program that does not use a libc
+ // and does not initialize TLS variables. Such a program might be
+ // linked with "-nostdlib".
+ errs() << "Warning: Variable " << Name << " not referenced\n";
+ } else {
+ 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 PointerType *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(
+ TemplateDataVar,
+ ConstantInt::get(M.getContext(), APInt(32, 1)));
+ setGlobalVariableValue(M, "__tls_template_tdata_end", TdataEnd);
+
+ Constant *TotalEnd = ConstantExpr::getGetElementPtr(
+ 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 TemplatePtrType;
+}
+
+static void rewriteTlsVars(Module &M, std::vector<VarInfo> *TlsVars,
+ PointerType *TemplatePtrType) {
+ // Set up the intrinsic that reads the thread pointer.
+ Type *i8 = Type::getInt8Ty(M.getContext());
+ FunctionType *ReadTpType = FunctionType::get(PointerType::get(i8, 0),
+ /*isVarArg=*/false);
+ AttrBuilder B;
+ B.addAttribute(Attribute::ReadOnly);
+ B.addAttribute(Attribute::NoUnwind);
+ AttributeSet ReadTpAttrs = AttributeSet().addAttr(
+ M.getContext(), AttributeSet::FunctionIndex,
+ Attribute::get(M.getContext(), B));
+ Constant *ReadTpFunc = M.getOrInsertTargetIntrinsic("llvm.nacl.read.tp",
+ ReadTpType,
+ ReadTpAttrs);
+
+ for (std::vector<VarInfo>::iterator VarInfo = TlsVars->begin();
+ VarInfo != TlsVars->end();
+ ++VarInfo) {
+ GlobalVariable *Var = VarInfo->TlsVar;
+ while (!Var->use_empty()) {
+ Instruction *U = cast<Instruction>(*Var->use_begin());
+ Instruction *InsertPt = U;
+ if (PHINode *PN = dyn_cast<PHINode>(InsertPt)) {
+ // We cannot insert instructions before a PHI node, so insert
+ // before the incoming block's terminator. Note that if the
+ // terminator is conditional, this could be suboptimal,
+ // because we might be calling ReadTpFunc unnecessarily.
+ InsertPt = PN->getIncomingBlock(Var->use_begin())->getTerminator();
+ }
+ Value *RawThreadPtr = CallInst::Create(ReadTpFunc, "tls_raw", InsertPt);
+ Value *TypedThreadPtr = new BitCastInst(RawThreadPtr, TemplatePtrType,
+ "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(TypedThreadPtr, Indexes,
+ "field", InsertPt);
+ U->replaceUsesOfWith(Var, TlsField);
+ }
+ VarInfo->TlsVar->eraseFromParent();
+ }
+}
+
+// Provide fixed definitions for PNaCl's TLS layout intrinsics. We
+// adopt the x86-style layout: ExpandTls will output a program that
+// uses the x86-style layout wherever it runs. This overrides any
+// architecture-specific definitions of the intrinsics that the LLVM
+// backend might provide.
+static void defineTlsLayoutIntrinsics(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 intrinsic 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);
+ if (Function *Intrinsic = M.getFunction("llvm.nacl.tp.tdb.offset")) {
+ Intrinsic->replaceAllUsesWith(NewFunc);
+ Intrinsic->eraseFromParent();
+ }
+
+ // Define the intrinsic 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);
+ if (Function *Intrinsic = M.getFunction("llvm.nacl.tp.tls.offset")) {
+ Intrinsic->replaceAllUsesWith(NewFunc);
+ Intrinsic->eraseFromParent();
+ }
+}
+
+bool ExpandTls::runOnModule(Module &M) {
+ ModulePass *Pass = createExpandTlsConstantExprPass();
+ Pass->runOnModule(M);
+ delete Pass;
+
+ std::vector<VarInfo> TlsVars;
+ PointerType *TemplatePtrType = buildTlsTemplate(M, &TlsVars);
+ rewriteTlsVars(M, &TlsVars, TemplatePtrType);
+
+ defineTlsLayoutIntrinsics(M);
+
+ return true;
+}
+
+ModulePass *llvm::createExpandTlsPass() {
+ return new ExpandTls();
+}
diff --git a/lib/Transforms/NaCl/ExpandTlsConstantExpr.cpp b/lib/Transforms/NaCl/ExpandTlsConstantExpr.cpp
new file mode 100644
index 0000000000..45612b2616
--- /dev/null
+++ b/lib/Transforms/NaCl/ExpandTlsConstantExpr.cpp
@@ -0,0 +1,110 @@
+//===- 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 (Value::use_iterator UI = Expr->use_begin();
+ UI != Expr->use_end();
+ ++UI) {
+ if (ConstantExpr *CE = dyn_cast<ConstantExpr>(*UI)) {
+ expandConstExpr(CE);
+ }
+ }
+ Expr->removeDeadConstantUsers();
+
+ if (ConstantExpr *CE = dyn_cast<ConstantExpr>(Expr)) {
+ while (!Expr->use_empty()) {
+ Instruction *U = cast<Instruction>(*Expr->use_begin());
+ Instruction *InsertPt = U;
+ 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(Expr->use_begin())->getTerminator();
+ }
+ Instruction *NewInst = CE->getAsInstruction();
+ NewInst->insertBefore(InsertPt);
+ NewInst->setName("expanded");
+ U->replaceUsesOfWith(CE, NewInst);
+ }
+ }
+}
+
+bool ExpandTlsConstantExpr::runOnModule(Module &M) {
+ 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();
+}
diff --git a/lib/Transforms/NaCl/LLVMBuild.txt b/lib/Transforms/NaCl/LLVMBuild.txt
new file mode 100644
index 0000000000..14c85c9c04
--- /dev/null
+++ b/lib/Transforms/NaCl/LLVMBuild.txt
@@ -0,0 +1,23 @@
+;===- ./lib/Transforms/NaCl/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 = NaClTransforms
+parent = Transforms
+library_name = NaClTransforms
+required_libraries = Core
diff --git a/lib/Transforms/NaCl/Makefile b/lib/Transforms/NaCl/Makefile
new file mode 100644
index 0000000000..ecf8db6eae
--- /dev/null
+++ b/lib/Transforms/NaCl/Makefile
@@ -0,0 +1,15 @@
+##===- lib/Transforms/NaCl/Makefile-------------------------*- Makefile -*-===##
+#
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+##===----------------------------------------------------------------------===##
+
+LEVEL = ../../..
+LIBRARYNAME = LLVMTransformsNaCl
+BUILD_ARCHIVE = 1
+
+include $(LEVEL)/Makefile.common
+
diff --git a/lib/Transforms/Scalar/CMakeLists.txt b/lib/Transforms/Scalar/CMakeLists.txt
index fd55e082ac..7a855ab99a 100644
--- a/lib/Transforms/Scalar/CMakeLists.txt
+++ b/lib/Transforms/Scalar/CMakeLists.txt
@@ -31,6 +31,7 @@ add_llvm_library(LLVMScalarOpts
SimplifyLibCalls.cpp
Sink.cpp
TailRecursionElimination.cpp
+ NaClCcRewrite.cpp
)
add_dependencies(LLVMScalarOpts intrinsics_gen)
diff --git a/lib/Transforms/Scalar/NaClCcRewrite.cpp b/lib/Transforms/Scalar/NaClCcRewrite.cpp
new file mode 100644
index 0000000000..72a8e7e358
--- /dev/null
+++ b/lib/Transforms/Scalar/NaClCcRewrite.cpp
@@ -0,0 +1,1053 @@
+//===- ConstantProp.cpp - Code to perform Simple Constant Propagation -----===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements calling convention rewrite for Native Client to ensure
+// compatibility between pnacl and gcc generated code when calling
+// ppapi interface functions.
+//===----------------------------------------------------------------------===//
+
+
+// Major TODOs:
+// * dealing with vararg
+// (We shoulf exclude all var arg functions and calls to them from rewrites)
+
+#define DEBUG_TYPE "naclcc"
+
+#include "llvm/Pass.h"
+#include "llvm/IR/Argument.h"
+#include "llvm/IR/Attributes.h"
+#include "llvm/IR/Constant.h"
+#include "llvm/IR/DataLayout.h"
+#include "llvm/IR/Instruction.h"
+#include "llvm/IR/Instructions.h"
+#include "llvm/IR/IntrinsicInst.h"
+#include "llvm/IR/Function.h"
+#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/raw_ostream.h"
+#include "llvm/Support/InstIterator.h"
+#include "llvm/Target/TargetLibraryInfo.h"
+#include "llvm/Target/TargetMachine.h"
+#include "llvm/Target/TargetLowering.h"
+#include "llvm/Target/TargetLoweringObjectFile.h"
+#include "llvm/Transforms/Scalar.h"
+
+#include <vector>
+
+using namespace llvm;
+
+namespace llvm {
+
+cl::opt<bool> FlagEnableCcRewrite(
+ "nacl-cc-rewrite",
+ cl::desc("enable NaCl CC rewrite"));
+}
+
+namespace {
+
+// This represents a rule for rewiriting types
+struct TypeRewriteRule {
+ const char* src; // type pattern we are trying to match
+ const char* dst; // replacement type
+ const char* name; // name of the rule for diagnosis
+};
+
+// Note: all rules must be well-formed
+// * parentheses must match
+// * TODO: add verification for this
+
+// Legend:
+// s(): struct (also used for unions)
+// c: char (= 8 bit int) (only allowed for src)
+// i: 32 bit int
+// l: 64 bit int
+// f: 32 bit float
+// d: 64 bit float (= double)
+// p: untyped pointer (only allowed for src)
+// P(): typed pointer (currently not used, only allowed for src)
+// F: generic function type (only allowed for src)
+
+// The X8664 Rewrite rules are also subject to
+// register constraints, c.f.: section 3.2.3
+// http://www.x86-64.org/documentation/abi.pdf
+// (roughly) for X8664: up to 2 regs per struct can be used for struct passsing
+// and up to 2 regs for struct returns
+// The rewrite rules are straight forward except for: s(iis(d)) => ll
+// which would be straight forward if the frontend had lowered the union inside
+// of PP_Var to s(l) instead of s(d), yielding: s(iis(l)) =>