diff options
-rw-r--r-- | include/llvm/InitializePasses.h | 2 | ||||
-rw-r--r-- | include/llvm/Transforms/NaCl.h | 2 | ||||
-rw-r--r-- | lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp | 7 | ||||
-rw-r--r-- | lib/Transforms/NaCl/AddPNaClExternalDecls.cpp | 71 | ||||
-rw-r--r-- | lib/Transforms/NaCl/CMakeLists.txt | 4 | ||||
-rw-r--r-- | lib/Transforms/NaCl/ResolvePNaClIntrinsics.cpp | 100 | ||||
-rw-r--r-- | test/NaCl/ARM/nacl-setlongjmp-intrinsics.ll | 2 | ||||
-rw-r--r-- | test/NaCl/X86/nacl-setlongjmp-intrinsics.ll | 2 | ||||
-rw-r--r-- | test/Transforms/NaCl/add-pnacl-external-decls.ll | 6 | ||||
-rw-r--r-- | test/Transforms/NaCl/resolve-pnacl-intrinsics.ll | 25 | ||||
-rw-r--r-- | tools/llc/llc.cpp | 23 | ||||
-rw-r--r-- | tools/opt/opt.cpp | 2 | ||||
-rw-r--r-- | tools/pnacl-llc/pnacl-llc.cpp | 13 |
13 files changed, 249 insertions, 10 deletions
diff --git a/include/llvm/InitializePasses.h b/include/llvm/InitializePasses.h index b55970ad84..a55ea5ce1e 100644 --- a/include/llvm/InitializePasses.h +++ b/include/llvm/InitializePasses.h @@ -277,6 +277,7 @@ void initializeLoopVectorizePass(PassRegistry&); void initializeBBVectorizePass(PassRegistry&); void initializeMachineFunctionPrinterPassPass(PassRegistry&); // @LOCALMOD-BEGIN +void initializeAddPNaClExternalDeclsPass(PassRegistry&); void initializeExpandByValPass(PassRegistry&); void initializeExpandConstantExprPass(PassRegistry&); void initializeExpandCtorsPass(PassRegistry&); @@ -294,6 +295,7 @@ void initializePNaClABIVerifyFunctionsPass(PassRegistry&); void initializePromoteIntegersPass(PassRegistry&); void initializeReplacePtrsWithIntsPass(PassRegistry&); void initializeResolveAliasesPass(PassRegistry&); +void initializeResolvePNaClIntrinsicsPass(PassRegistry&); void initializeRewritePNaClLibraryCallsPass(PassRegistry&); void initializeStripMetadataPass(PassRegistry&); // @LOCALMOD-END diff --git a/include/llvm/Transforms/NaCl.h b/include/llvm/Transforms/NaCl.h index 3b9ce35dc8..f42336fc67 100644 --- a/include/llvm/Transforms/NaCl.h +++ b/include/llvm/Transforms/NaCl.h @@ -20,6 +20,7 @@ class PassManager; class Use; class Value; +ModulePass *createAddPNaClExternalDeclsPass(); ModulePass *createExpandByValPass(); FunctionPass *createExpandConstantExprPass(); ModulePass *createExpandCtorsPass(); @@ -33,6 +34,7 @@ ModulePass *createGlobalCleanupPass(); FunctionPass *createPromoteIntegersPass(); ModulePass *createReplacePtrsWithIntsPass(); ModulePass *createResolveAliasesPass(); +FunctionPass *createResolvePNaClIntrinsicsPass(); ModulePass *createRewritePNaClLibraryCallsPass(); ModulePass *createStripMetadataPass(); FunctionPass *createInsertDivideCheckPass(); diff --git a/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp b/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp index 9113fb1b6f..b7a7e2e133 100644 --- a/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp +++ b/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp @@ -5215,13 +5215,6 @@ SelectionDAGBuilder::visitIntrinsicCall(const CallInst &I, unsigned Intrinsic) { setValue(&I, DAG.getNode(ISD::NACL_TARGET_ARCH, dl, DestVT)); return 0; } - // Native Client Intrinsics for setjmp/longjmp - case Intrinsic::nacl_setjmp: { - return "setjmp"; - } - case Intrinsic::nacl_longjmp: { - return "longjmp"; - } // @LOCALMOD-END } } diff --git a/lib/Transforms/NaCl/AddPNaClExternalDecls.cpp b/lib/Transforms/NaCl/AddPNaClExternalDecls.cpp new file mode 100644 index 0000000000..f96db09b2f --- /dev/null +++ b/lib/Transforms/NaCl/AddPNaClExternalDecls.cpp @@ -0,0 +1,71 @@ +//===- AddPNaClExternalDecls.cpp - Add decls for PNaCl external functions -===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This pass adds function declarations for external functions used by PNaCl. +// These externals are implemented in native libraries and calls to them are +// created as part of the translation process. +// +// Running this pass is a precondition for running ResolvePNaClIntrinsics. They +// are separate because one is a ModulePass and the other is a FunctionPass. +// +//===----------------------------------------------------------------------===// + +#include "llvm/IR/DerivedTypes.h" +#include "llvm/IR/Module.h" +#include "llvm/IR/Type.h" +#include "llvm/Pass.h" +#include "llvm/Transforms/NaCl.h" + +using namespace llvm; + +namespace { + // This is a module pass because it adds declarations to the module. + class AddPNaClExternalDecls : public ModulePass { + public: + static char ID; + AddPNaClExternalDecls() : ModulePass(ID) { + initializeAddPNaClExternalDeclsPass(*PassRegistry::getPassRegistry()); + } + + virtual bool runOnModule(Module &M); + }; +} + +bool AddPNaClExternalDecls::runOnModule(Module &M) { + // Add declarations for a pre-defined set of external functions to the module. + // The function names must match the functions implemented in native code (in + // pnacl/support). The function types must match the types of the LLVM + // intrinsics. + // We expect these declarations not to exist in the module before this pass + // runs, but don't assert it; it will be handled by the ABI verifier. + LLVMContext &C = M.getContext(); + M.getOrInsertFunction("setjmp", + // return type + Type::getInt32Ty(C), + // arguments + Type::getInt8Ty(C)->getPointerTo(), + NULL); + M.getOrInsertFunction("longjmp", + // return type + Type::getVoidTy(C), + // arguments + Type::getInt8Ty(C)->getPointerTo(), + Type::getInt32Ty(C), + NULL); + return true; +} + +char AddPNaClExternalDecls::ID = 0; +INITIALIZE_PASS(AddPNaClExternalDecls, "add-pnacl-external-decls", + "Add declarations of external functions used by PNaCl", + false, false) + +ModulePass *llvm::createAddPNaClExternalDeclsPass() { + return new AddPNaClExternalDecls(); +} diff --git a/lib/Transforms/NaCl/CMakeLists.txt b/lib/Transforms/NaCl/CMakeLists.txt index a98d929f83..14225d79b8 100644 --- a/lib/Transforms/NaCl/CMakeLists.txt +++ b/lib/Transforms/NaCl/CMakeLists.txt @@ -1,4 +1,7 @@ +set(LLVM_LINK_COMPONENTS ipo) + add_llvm_library(LLVMNaClTransforms + AddPNaClExternalDecls.cpp ExpandByVal.cpp ExpandConstantExpr.cpp ExpandCtors.cpp @@ -14,6 +17,7 @@ add_llvm_library(LLVMNaClTransforms PNaClABISimplify.cpp PromoteIntegers.cpp ReplacePtrsWithInts.cpp + ResolvePNaClIntrinsics.cpp RewritePNaClLibraryCalls.cpp StripMetadata.cpp ) diff --git a/lib/Transforms/NaCl/ResolvePNaClIntrinsics.cpp b/lib/Transforms/NaCl/ResolvePNaClIntrinsics.cpp new file mode 100644 index 0000000000..e4efeb67c3 --- /dev/null +++ b/lib/Transforms/NaCl/ResolvePNaClIntrinsics.cpp @@ -0,0 +1,100 @@ +//===- ResolvePNaClIntrinsics.cpp - Resolve calls to PNaCl intrinsics ----====// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This pass resolves calls to PNaCl stable bitcode intrinsics. It is +// normally run in the PNaCl translator. +// +// Running AddPNaClExternalDeclsPass is a precondition for running this pass. +// They are separate because one is a ModulePass and the other is a +// FunctionPass. +// +//===----------------------------------------------------------------------===// + +#include "llvm/ADT/SmallVector.h" +#include "llvm/IR/Instructions.h" +#include "llvm/IR/Intrinsics.h" +#include "llvm/IR/Module.h" +#include "llvm/Pass.h" +#include "llvm/Transforms/NaCl.h" + +using namespace llvm; + +namespace { + class ResolvePNaClIntrinsics : public FunctionPass { + public: + ResolvePNaClIntrinsics() : FunctionPass(ID) { + initializeResolvePNaClIntrinsicsPass(*PassRegistry::getPassRegistry()); + } + + static char ID; + virtual bool runOnFunction(Function &F); + private: + // Some intrinsic calls are resolved simply by replacing the call with a + // call to an alternative function with exactly the same type. + bool resolveSimpleCall(Function &F, Intrinsic::ID IntrinsicID, + const char *TargetFunctionName); + }; +} + +bool ResolvePNaClIntrinsics::resolveSimpleCall(Function &F, + Intrinsic::ID IntrinsicID, + const char *TargetFunctionName) { + Module *M = F.getParent(); + bool Changed = false; + Function *IntrinsicFunction = Intrinsic::getDeclaration(M, IntrinsicID); + + if (!IntrinsicFunction) { + return false; + } + + // Expect to find the target function for this intrinsic already declared + Function *TargetFunction = M->getFunction(TargetFunctionName); + if (!TargetFunction) { + report_fatal_error( + std::string("Expected to find external declaration of ") + + TargetFunctionName); + } + + for (Value::use_iterator UI = IntrinsicFunction->use_begin(), + UE = IntrinsicFunction->use_end(); UI != UE;) { + // At this point, the only uses of the intrinsic can be calls, since + // we assume this pass runs on bitcode that passed ABI verification. + CallInst *Call = dyn_cast<CallInst>(*UI++); + + if (!Call) { + report_fatal_error( + std::string("Expected use of intrinsic to be a call: ") + + Intrinsic::getName(IntrinsicID)); + } + + // To be a well-behaving FunctionPass, don't touch uses in other + // functions. These will be handled when the pass manager gets to those + // functions. + if (Call->getParent()->getParent() == &F) { + Call->setCalledFunction(TargetFunction); + Changed = true; + } + } + + return Changed; +} + +bool ResolvePNaClIntrinsics::runOnFunction(Function &F) { + bool Changed = resolveSimpleCall(F, Intrinsic::nacl_setjmp, "setjmp"); + Changed |= resolveSimpleCall(F, Intrinsic::nacl_longjmp, "longjmp"); + return Changed; +} + +char ResolvePNaClIntrinsics::ID = 0; +INITIALIZE_PASS(ResolvePNaClIntrinsics, "resolve-pnacl-intrinsics", + "Resolve PNaCl intrinsic calls", false, false) + +FunctionPass *llvm::createResolvePNaClIntrinsicsPass() { + return new ResolvePNaClIntrinsics(); +} diff --git a/test/NaCl/ARM/nacl-setlongjmp-intrinsics.ll b/test/NaCl/ARM/nacl-setlongjmp-intrinsics.ll index 73251d10f3..e0854db4ff 100644 --- a/test/NaCl/ARM/nacl-setlongjmp-intrinsics.ll +++ b/test/NaCl/ARM/nacl-setlongjmp-intrinsics.ll @@ -10,7 +10,7 @@ define void @foo(i8* %arg) { %num = call i32 @llvm.nacl.setjmp(i8* %arg) ; ARM: bl setjmp - call void @llvm.nacl.longjmp(i8* %arg, i32 %num) + call void @llvm.nacl.longjmp(i8* %arg, i32 %num) ; ARM: bl longjmp ret void diff --git a/test/NaCl/X86/nacl-setlongjmp-intrinsics.ll b/test/NaCl/X86/nacl-setlongjmp-intrinsics.ll index fa827a2758..ac595d613a 100644 --- a/test/NaCl/X86/nacl-setlongjmp-intrinsics.ll +++ b/test/NaCl/X86/nacl-setlongjmp-intrinsics.ll @@ -10,7 +10,7 @@ define void @foo(i8* %arg) { %num = call i32 @llvm.nacl.setjmp(i8* %arg) ; X86: naclcall setjmp - call void @llvm.nacl.longjmp(i8* %arg, i32 %num) + call void @llvm.nacl.longjmp(i8* %arg, i32 %num) ; X86: naclcall longjmp ret void diff --git a/test/Transforms/NaCl/add-pnacl-external-decls.ll b/test/Transforms/NaCl/add-pnacl-external-decls.ll new file mode 100644 index 0000000000..1f525a9268 --- /dev/null +++ b/test/Transforms/NaCl/add-pnacl-external-decls.ll @@ -0,0 +1,6 @@ +; RUN: opt < %s -add-pnacl-external-decls -S | FileCheck %s + +declare void @foobar(i32) + +; CHECK: declare i32 @setjmp(i8*) +; CHECK: declare void @longjmp(i8*, i32) diff --git a/test/Transforms/NaCl/resolve-pnacl-intrinsics.ll b/test/Transforms/NaCl/resolve-pnacl-intrinsics.ll new file mode 100644 index 0000000000..3aa263fa9a --- /dev/null +++ b/test/Transforms/NaCl/resolve-pnacl-intrinsics.ll @@ -0,0 +1,25 @@ +; RUN: opt < %s -resolve-pnacl-intrinsics -S | FileCheck %s + +declare i32 @llvm.nacl.setjmp(i8*) +declare void @llvm.nacl.longjmp(i8*, i32) + +; These declarations must be here because the function pass expects +; to find them. In real life they're inserted by the translator +; before the function pass runs. +declare i32 @setjmp(i8*) +declare void @longjmp(i8*, i32) + +; CHECK-NOT: call i32 @llvm.nacl.setjmp +; CHECK-NOT: call void @llvm.nacl.longjmp + +define i32 @call_setjmp(i8* %arg) { + %val = call i32 @llvm.nacl.setjmp(i8* %arg) +; CHECK: %val = call i32 @setjmp(i8* %arg) + ret i32 %val +} + +define void @call_longjmp(i8* %arg, i32 %num) { + call void @llvm.nacl.longjmp(i8* %arg, i32 %num) +; CHECK: call void @longjmp(i8* %arg, i32 %num) + ret void +} diff --git a/tools/llc/llc.cpp b/tools/llc/llc.cpp index 64bb6991d8..0fcd1f3c06 100644 --- a/tools/llc/llc.cpp +++ b/tools/llc/llc.cpp @@ -15,7 +15,7 @@ #include "llvm/IR/LLVMContext.h" #include "llvm/ADT/Triple.h" -#include "llvm/Analysis/NaCl.h" +#include "llvm/Analysis/NaCl.h" // @LOCALMOD #include "llvm/Assembly/PrintModulePass.h" #include "llvm/Support/DataStream.h" // @LOCALMOD #include "llvm/CodeGen/CommandFlags.h" @@ -33,6 +33,7 @@ #include "llvm/Support/Host.h" #include "llvm/Support/IRReader.h" #include "llvm/Support/ManagedStatic.h" +#include "llvm/Transforms/NaCl.h" // @LOCALMOD #if !defined(__native_client__) #include "llvm/Support/PluginLoader.h" #endif @@ -392,6 +393,7 @@ static int compileModule(char **argv, LLVMContext &Context) { VerifyPass->runOnModule(*mod); CheckABIVerifyErrors(ABIErrorReporter, "Module"); } + #if defined(__native_client__) && defined(NACL_SRPC) RecordMetadataForSrpc(*mod); @@ -413,6 +415,19 @@ static int compileModule(char **argv, LLVMContext &Context) { if (!TargetTriple.empty()) mod->setTargetTriple(Triple::normalize(TargetTriple)); TheTriple = Triple(mod->getTargetTriple()); + + // @LOCALMOD-BEGIN + // Add declarations for external functions required by PNaCl. The + // ResolvePNaClIntrinsics function pass running during streaming + // depends on these declarations being in the module. + if (TheTriple.isOSNaCl()) { + // TODO(eliben): pnacl-llc presumably won't need the isOSNaCl + // test. + OwningPtr<ModulePass> AddPNaClExternalDeclsPass( + createAddPNaClExternalDeclsPass()); + AddPNaClExternalDeclsPass->runOnModule(*mod); + } + // @LOCALMOD-END } else { TheTriple = Triple(Triple::normalize(TargetTriple)); } @@ -525,6 +540,12 @@ static int compileModule(char **argv, LLVMContext &Context) { FunctionVerifyPass = createPNaClABIVerifyFunctionsPass(&ABIErrorReporter); PM->add(FunctionVerifyPass); } + + if (TheTriple.isOSNaCl()) { + // Add the intrinsic resolution pass. It assumes ABI-conformant code. + PM->add(createResolvePNaClIntrinsicsPass()); + } + // @LOCALMOD-END // Add an appropriate TargetLibraryInfo pass for the module's triple. diff --git a/tools/opt/opt.cpp b/tools/opt/opt.cpp index 35e18d02ad..f12c36a7c7 100644 --- a/tools/opt/opt.cpp +++ b/tools/opt/opt.cpp @@ -598,6 +598,7 @@ int main(int argc, char **argv) { initializeInstrumentation(Registry); initializeTarget(Registry); // @LOCALMOD-BEGIN + initializeAddPNaClExternalDeclsPass(Registry); initializeExpandByValPass(Registry); initializeExpandConstantExprPass(Registry); initializeExpandCtorsPass(Registry); @@ -614,6 +615,7 @@ int main(int argc, char **argv) { initializePromoteIntegersPass(Registry); initializeReplacePtrsWithIntsPass(Registry); initializeResolveAliasesPass(Registry); + initializeResolvePNaClIntrinsicsPass(Registry); initializeRewritePNaClLibraryCallsPass(Registry); initializeStripMetadataPass(Registry); // @LOCALMOD-END diff --git a/tools/pnacl-llc/pnacl-llc.cpp b/tools/pnacl-llc/pnacl-llc.cpp index f75bada099..060c1b6c94 100644 --- a/tools/pnacl-llc/pnacl-llc.cpp +++ b/tools/pnacl-llc/pnacl-llc.cpp @@ -38,6 +38,7 @@ #include "llvm/Support/ToolOutputFile.h" #include "llvm/Target/TargetLibraryInfo.h" #include "llvm/Target/TargetMachine.h" +#include "llvm/Transforms/NaCl.h" #include <memory> @@ -326,6 +327,14 @@ static int compileModule(char **argv, LLVMContext &Context) { VerifyPass->runOnModule(*mod); CheckABIVerifyErrors(ABIErrorReporter, "Module"); } + + // Add declarations for external functions required by PNaCl. The + // ResolvePNaClIntrinsics function pass running during streaming + // depends on these declarations being in the module. + OwningPtr<ModulePass> AddPNaClExternalDeclsPass( + createAddPNaClExternalDeclsPass()); + AddPNaClExternalDeclsPass->runOnModule(*mod); + #if defined(__native_client__) && defined(NACL_SRPC) // Record that this isn't a shared library. // TODO(eliben): clean this up more once the pnacl-llc switch-over is @@ -462,6 +471,10 @@ static int compileModule(char **argv, LLVMContext &Context) { FunctionVerifyPass = createPNaClABIVerifyFunctionsPass(&ABIErrorReporter); PM->add(FunctionVerifyPass); } + + // Add the intrinsic resolution pass. It assumes ABI-conformant code. + PM->add(createResolvePNaClIntrinsicsPass()); + // @LOCALMOD-END // Add an appropriate TargetLibraryInfo pass for the module's triple. |