Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(458)

Unified Diff: lib/Transforms/NaCl/RewritePNaClLibraryCalls.cpp

Issue 14617017: Adding a pass - RewritePNaClLibraryCalls, that replaces known library calls with stable bitcode int… (Closed) Base URL: http://git.chromium.org/native_client/pnacl-llvm.git@master
Patch Set: Added llvm.nacl.{set|long}jmp to the list of whitelisted intrinsics for ABI Created 7 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: lib/Transforms/NaCl/RewritePNaClLibraryCalls.cpp
diff --git a/lib/Transforms/NaCl/RewritePNaClLibraryCalls.cpp b/lib/Transforms/NaCl/RewritePNaClLibraryCalls.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..57e98dc125fbf8f0e832423f595fb0d47b5a160b
--- /dev/null
+++ b/lib/Transforms/NaCl/RewritePNaClLibraryCalls.cpp
@@ -0,0 +1,223 @@
+//===- RewritePNaClLibraryCalls.cpp - PNaCl library calls to intrinsics ---===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This pass replaces calls to known library functions with calls to intrinsics
+// that are part of the PNaCl stable bitcode ABI.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/Twine.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 RewritePNaClLibraryCalls : public ModulePass {
+ public:
+ static char ID;
+ RewritePNaClLibraryCalls() :
+ ModulePass(ID), TheModule(NULL) {
+ // This is a module pass because it may have to introduce
+ // intrinsic declarations into the module and modify a global function.
+ initializeRewritePNaClLibraryCallsPass(*PassRegistry::getPassRegistry());
+ }
+
+ virtual bool runOnModule(Module &M);
+ private:
+ /// Rewrites the given \p Call of setjmp to a direct intrinsic call.
+ void rewriteSetjmpCall(CallInst *Call);
+
+ /// Rewrites the given \p Call of longjmp to a direct intrinsic call.
+ void rewriteLongjmpCall(CallInst *Call);
+
+ /// Populates the body of longjmp as a wrapper of the intrinsic call.
+ /// Should only be called once. Modifies the given \p LongjmpFunc.
+ void populateLongjmpWrapper(Function *LongjmpFunc);
+
+ /// The module this pass runs on.
+ Module *TheModule;
+ };
+}
+
+static const char *LONGJMP_NAME = "longjmp";
Mark Seaborn 2013/05/13 23:39:58 I don't think LLVM uses NAMES_IN_CAPS for non-#def
eliben 2013/05/14 17:38:58 These constants are now just used in a single plac
+static const char *SETJMP_NAME = "setjmp";
+
+char RewritePNaClLibraryCalls::ID = 0;
+INITIALIZE_PASS(RewritePNaClLibraryCalls, "rewrite-pnacl-library-calls",
+ "Rewrite PNaCl library calls to stable intrinsics",
+ false, false)
+
+bool RewritePNaClLibraryCalls::runOnModule(Module &M) {
+ TheModule = &M;
+ bool Changed = false;
+
+ // Iterate over all uses of the setjmp, if it exists in the module with
+ // external linkage. If it exists but the linkage is not external, this may
+ // come from code that defines its own function named setjmp and doesn't
+ // include <setjmp.h>. In such a case we leave the code as it is.
+ //
+ // The calls are replaced with intrinsics. All other uses
+ // of setjmp are disallowed (taking the address of setjmp is disallowed in
Mark Seaborn 2013/05/13 23:39:58 Re-wrap (partly fits on previous line)
eliben 2013/05/14 17:38:58 Done.
+ // C and C++).
+ Function *SetjmpFunc = TheModule->getFunction(SETJMP_NAME);
+ if (SetjmpFunc && SetjmpFunc->hasExternalLinkage()) {
+ for (Value::use_iterator UI = SetjmpFunc->use_begin(),
+ UE = SetjmpFunc->use_end(); UI != UE;) {
+ Value *Use = *UI++;
+ if (CallInst *Call = dyn_cast<CallInst>(Use)) {
+ rewriteSetjmpCall(Call);
+ Changed = true;
+ } else {
+ report_fatal_error("Taking the address of setjmp is invalid");
+ }
+ }
+ }
+
+ // For longjmp things are a little more complicated, since longjmp's address
+ // can be taken. Therefore, longjmp can appear in a variety of Uses. The
+ // common case is still a direct call and we want that to be as efficient as
+ // possible, so we rewrite it into a direct intrinsic call. If there are other
+ // uses, the actual body of longjmp is populated with a wrapper that calls
+ // the intrinsic.
+ Function *LongjmpFunc = TheModule->getFunction(LONGJMP_NAME);
+ bool LongjmpHasNoncallUses = false;
+
+ if (LongjmpFunc && LongjmpFunc->hasExternalLinkage()) {
+ for (Value::use_iterator UI = LongjmpFunc->use_begin(),
+ UE = LongjmpFunc->use_end(); UI != UE;) {
+ Value *Use = *UI++;
+ if (CallInst *Call = dyn_cast<CallInst>(Use)) {
+ rewriteLongjmpCall(Call);
+ Changed = true;
+ } else {
+ LongjmpHasNoncallUses = true;
+ }
+ }
+ }
+
+ if (LongjmpHasNoncallUses) {
Mark Seaborn 2013/05/13 23:39:58 Could just do: if (!LongjmpFunc->use_empty()) th
eliben 2013/05/14 17:38:58 Done.
+ populateLongjmpWrapper(LongjmpFunc);
+ Changed = true;
+ }
+
+ return Changed;
+}
+
+void RewritePNaClLibraryCalls::rewriteSetjmpCall(CallInst *Call) {
+ FunctionType *FTy = Call->getCalledFunction()->getFunctionType();
+
+ // Sanity check on the setjmp call.
+ if (FTy->getNumParams() != 1 ||
+ !FTy->getReturnType()->isIntegerTy() ||
+ !FTy->getParamType(0)->isPointerTy()) {
+ report_fatal_error(Twine("Wrong signature of function ") +
+ Call->getCalledFunction()->getName());
+ }
+ const DebugLoc &DLoc = Call->getDebugLoc();
+
+ // Find the intrinsic function.
+ Function *NaClSetjmpFunc = Intrinsic::getDeclaration(TheModule,
+ Intrinsic::nacl_setjmp);
+ // Cast the jmp_buf argument to the type NaClSetjmpCall expects.
+ Type *PtrTy = NaClSetjmpFunc->getFunctionType()->getParamType(0);
+ BitCastInst *JmpBufCast = new BitCastInst(Call->getArgOperand(0), PtrTy,
+ "jmp_buf_i8", Call);
+ JmpBufCast->setDebugLoc(DLoc);
+
+ // Emit the updated call.
+ SmallVector<Value *, 1> Args;
+ Args.push_back(JmpBufCast);
+ CallInst *NaClSetjmpCall = CallInst::Create(NaClSetjmpFunc, Args, "", Call);
+ NaClSetjmpCall->setDebugLoc(DLoc);
+ NaClSetjmpCall->takeName(Call);
+
+ // Replace the original call.
+ Call->replaceAllUsesWith(NaClSetjmpCall);
+ Call->eraseFromParent();
+}
+
+void RewritePNaClLibraryCalls::rewriteLongjmpCall(CallInst *Call) {
+ FunctionType *FTy = Call->getCalledFunction()->getFunctionType();
+
+ // Sanity check on the longjmp call.
+ if (FTy->getNumParams() != 2 ||
+ !FTy->getReturnType()->isVoidTy() ||
+ !FTy->getParamType(0)->isPointerTy()) {
+ report_fatal_error(Twine("Wrong signature of function ") +
+ Call->getCalledFunction()->getName());
+ }
+ const DebugLoc &DLoc = Call->getDebugLoc();
+
+ // Find the intrinsic function.
+ Function *NaClLongjmpFunc = Intrinsic::getDeclaration(
+ TheModule, Intrinsic::nacl_longjmp);
+ // Cast the jmp_buf argument to the type NaClLongjmpCall expects.
+ Type *PtrTy = NaClLongjmpFunc->getFunctionType()->getParamType(0);
+ BitCastInst *JmpBufCast = new BitCastInst(Call->getArgOperand(0), PtrTy,
+ "jmp_buf_i8", Call);
+ JmpBufCast->setDebugLoc(DLoc);
+
+ // Emit the call.
+ SmallVector<Value *, 2> Args;
+ Args.push_back(JmpBufCast);
+ Args.push_back(Call->getArgOperand(1));
+ CallInst *NaClLongjmpCall = CallInst::Create(NaClLongjmpFunc, Args, "", Call);
+ NaClLongjmpCall->setDebugLoc(DLoc);
+ // No takeName here since longjmp is a void call that does not get assigned to
+ // a value.
+
+ // Remove the original call. There's no need for RAUW because longjmp
+ // returns void.
+ Call->eraseFromParent();
+}
+
+void RewritePNaClLibraryCalls::populateLongjmpWrapper(Function *LongjmpFunc) {
+ assert(LongjmpFunc->size() == 0 &&
+ "Expected to be called when longjmp has an empty body");
+
+ // Populate longjmp with code.
+ LLVMContext &Context = TheModule->getContext();
+ BasicBlock *BB = BasicBlock::Create(Context, "entry", LongjmpFunc);
+
+ Function::arg_iterator LongjmpArgs = LongjmpFunc->arg_begin();
Mark Seaborn 2013/05/13 23:39:58 Also do a sanity check on this function's args, as
eliben 2013/05/14 17:38:58 Refactored
+ Value *EnvArg = LongjmpArgs++;
+ EnvArg->setName("env");
+ Value *ValArg = LongjmpArgs++;
+ ValArg->setName("val");
+
+ // Insert an unreachable instruction to terminate this function since longjmp
+ // does not return.
+ Instruction *End = new UnreachableInst(Context, BB);
Mark Seaborn 2013/05/13 23:39:58 Nit: It would be a little more obvious to add the
eliben 2013/05/14 17:38:58 Done.
+
+ // Find the intrinsic function.
+ Function *NaClLongjmpFunc = Intrinsic::getDeclaration(
+ TheModule, Intrinsic::nacl_longjmp);
+ // Cast the jmp_buf argument to the type NaClLongjmpCall expects.
+ Type *PtrTy = NaClLongjmpFunc->getFunctionType()->getParamType(0);
+ BitCastInst *JmpBufCast = new BitCastInst(EnvArg, PtrTy, "jmp_buf_i8", End);
+
+ // Emit the call.
+ SmallVector<Value *, 2> Args;
+ Args.push_back(JmpBufCast);
+ Args.push_back(ValArg);
+ CallInst::Create(NaClLongjmpFunc, Args, "", End);
+
+ // Finally, set the linkage to internal
+ LongjmpFunc->setLinkage(Function::InternalLinkage);
+}
+
+ModulePass *llvm::createRewritePNaClLibraryCallsPass() {
+ return new RewritePNaClLibraryCalls();
+}
+
Mark Seaborn 2013/05/13 23:39:58 Nit: don't put empty lines at the end of the file
eliben 2013/05/14 17:38:58 Done.

Powered by Google App Engine
This is Rietveld 408576698