aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEli Bendersky <eliben@chromium.org>2013-05-28 11:23:28 -0700
committerEli Bendersky <eliben@chromium.org>2013-05-28 11:23:28 -0700
commitffc13bcb40d4257202295fc0ffe25b38bdf64263 (patch)
treee3269675fec1127c195d6b3c248a6a47376b32f0
parenta7b1caf4ea69d2cc6ff207fcef7085494bbc686a (diff)
Add two passes that implement conversions from PNaCl's specific intrinsics
to external function calls during the translation stage (llc). One of the passes is a ModulePass that adds the appropriate function declarations to the module. The other is a FunctionPass that performs the actual call replacement. This split exists because of bitcode streaming. Initially the passes handle the llvm.nacl.{set|long}jmp intrinsics. In the future they may handle additional intrinsics that are part of the PNaCl stable bitcode ABI. This CL also removes the previous approach to handling this conversion (in SelectionDAGBuilder.cpp). That ended up not working - more details in issue 3429. BUG=https://code.google.com/p/nativeclient/issues/detail?id=3429 R=mseaborn@chromium.org Review URL: https://codereview.chromium.org/16047002
-rw-r--r--include/llvm/InitializePasses.h2
-rw-r--r--include/llvm/Transforms/NaCl.h2
-rw-r--r--lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp7
-rw-r--r--lib/Transforms/NaCl/AddPNaClExternalDecls.cpp71
-rw-r--r--lib/Transforms/NaCl/CMakeLists.txt4
-rw-r--r--lib/Transforms/NaCl/ResolvePNaClIntrinsics.cpp100
-rw-r--r--test/NaCl/ARM/nacl-setlongjmp-intrinsics.ll2
-rw-r--r--test/NaCl/X86/nacl-setlongjmp-intrinsics.ll2
-rw-r--r--test/Transforms/NaCl/add-pnacl-external-decls.ll6
-rw-r--r--test/Transforms/NaCl/resolve-pnacl-intrinsics.ll25
-rw-r--r--tools/llc/llc.cpp23
-rw-r--r--tools/opt/opt.cpp2
-rw-r--r--tools/pnacl-llc/pnacl-llc.cpp13
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.