Chromium Code Reviews| Index: tools/pnacl-hack-memset/pnacl-hack-memset.cpp |
| diff --git a/tools/pnacl-hack-memset/pnacl-hack-memset.cpp b/tools/pnacl-hack-memset/pnacl-hack-memset.cpp |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..4cfc658de524a536db5d1e6dd1a1cea69dbc6f87 |
| --- /dev/null |
| +++ b/tools/pnacl-hack-memset/pnacl-hack-memset.cpp |
| @@ -0,0 +1,207 @@ |
| +/* Copyright 2016 The Native Client Authors. All rights reserved. |
| + * Use of this source code is governed by a BSD-style license that can |
| + * be found in the LICENSE file. |
| + */ |
| + |
| +//===-- pnacl-hack-memset.cpp - Fix (interim) subzero bug -----------------===// |
|
Jim Stichnoth
2016/08/23 17:20:36
I would prefer capitalized Subzero... here and bel
Karl
2016/08/23 17:44:14
Done.
|
| +// |
| +//===----------------------------------------------------------------------===// |
| +// |
| +// Fixes generated pexe's so that a fixed fixed subzero bug (but not |
|
Jim Stichnoth
2016/08/23 17:20:36
Reflow to 80-col. :)
"fixed fixed"
This first s
Karl
2016/08/23 17:44:14
Done.
|
| +// yet fully deployed until 10/2016). Does this by replacing calls to |
| +// memset with constant (negative) byte value, and corresponding |
| +// constant count arguments, with an zero-add. This causes the broken |
| +// (and fixed) optimization to not be fired. |
| +// |
| +//===----------------------------------------------------------------------===// |
| + |
| +#include "llvm/Bitcode/NaCl/NaClReaderWriter.h" |
| +#include "llvm/IR/Constants.h" |
| +#include "llvm/IR/InstIterator.h" |
| +#include "llvm/IR/Instructions.h" |
| +#include "llvm/IR/LLVMContext.h" |
| +#include "llvm/IR/Module.h" |
| +#include "llvm/Support/CommandLine.h" |
| +#include "llvm/Support/DataStream.h" |
| +#include "llvm/Support/FileSystem.h" |
| +#include "llvm/Support/ManagedStatic.h" |
| +#include "llvm/Support/PrettyStackTrace.h" |
| +#include "llvm/Support/Signals.h" |
| +#include "llvm/Support/StreamingMemoryObject.h" |
| +#include "llvm/Support/ToolOutputFile.h" |
| + |
| +using namespace llvm; |
| + |
| +namespace { |
| + |
| +cl::opt<std::string> |
| +OutputFilename("o", cl::desc("Specify fixed pexe filename"), |
| + cl::value_desc("fixed pexe file"), cl::init("-")); |
| + |
| +cl::opt<std::string> |
| +InputFilename(cl::Positional, cl::desc("<pexe file>"), cl::init("-")); |
| + |
| +cl::opt<bool> |
| +ShowFixes("show-fixes", cl::desc("Show fixes to memset"), cl::init(false)); |
| + |
| +void WriteOutputFile(const Module *M) { |
| + |
| + std::error_code EC; |
| + std::unique_ptr<tool_output_file> Out( |
| + new tool_output_file(OutputFilename, EC, sys::fs::F_None)); |
| + if (EC) { |
| + errs() << EC.message() << '\n'; |
| + exit(1); |
| + } |
| + |
| + NaClWriteBitcodeToFile(M, Out->os(), /* AcceptSupportedOnly = */ false); |
| + |
| + // Declare success. |
| + Out->keep(); |
| +} |
| + |
| +Module *readBitcode(std::string &Filename, LLVMContext &Context, |
| + std::string &ErrorMessage) { |
| + // Use the bitcode streaming interface |
| + DataStreamer *Streamer = getDataFileStreamer(InputFilename, &ErrorMessage); |
| + if (Streamer == nullptr) |
| + return nullptr; |
| + std::unique_ptr<StreamingMemoryObject> Buffer( |
| + new StreamingMemoryObjectImpl(Streamer)); |
| + std::string DisplayFilename; |
| + if (Filename == "-") |
| + DisplayFilename = "<stdin>"; |
| + else |
| + DisplayFilename = Filename; |
| + DiagnosticHandlerFunction DiagnosticHandler = nullptr; |
| + Module *M = getNaClStreamedBitcodeModule( |
| + DisplayFilename, Buffer.release(), Context, DiagnosticHandler, |
| + &ErrorMessage, /*AcceptSupportedOnly=*/false); |
| + if (!M) |
| + return nullptr; |
| + if (std::error_code EC = M->materializeAllPermanently()) { |
| + ErrorMessage = EC.message(); |
| + delete M; |
| + return nullptr; |
| + } |
| + return M; |
| +} |
| + |
| +// Fixes the memset call if appropriate. Returns 1 if the Call to memset has |
| +// been fixed, and zero otherwise. |
| +size_t fixCallToMemset(CallInst *Call) { |
| + if (Call->getNumArgOperands() != 5) |
| + return 0; |
| + Value *Val = Call->getArgOperand(1); |
| + auto *CVal = dyn_cast<ConstantInt>(Val); |
| + if (CVal == nullptr) |
| + return 0; |
| + if (!CVal->getType()->isIntegerTy(8)) |
| + return 0; |
| + const APInt &IVal = CVal->getUniqueInteger(); |
| + if (!IVal.isNegative()) |
| + return 0; |
| + Value *Count = Call->getArgOperand(2); |
| + auto *CCount = dyn_cast<ConstantInt>(Count); |
| + if (CCount == nullptr) |
| + return 0; |
| + if (!CCount->getType()->isIntegerTy(32)) |
| + return 0; |
| + if (ShowFixes) { |
| + Call->print(errs()); |
| + errs() << "\n-->\n"; |
| + } |
| + auto *Zero = ConstantInt::getSigned(CCount->getType(), 0); |
| + auto *Add = BinaryOperator::Create(Instruction::BinaryOps::Add, CCount, Zero); |
| + auto *IAdd = dyn_cast<Instruction>(Add); |
| + if (IAdd == nullptr) |
| + return 0; |
| + Call->setArgOperand(2, Add); |
| + IAdd->insertBefore(Call); |
| + if (ShowFixes) { |
| + IAdd->print(errs()); |
| + errs() << "\n"; |
| + Call->print(errs()); |
| + errs() << "\n\n"; |
| + } |
| + return 1; |
| +} |
| + |
| +// Fixes the instruction Inst, if it is a memset call that needs to be fixed. |
| +// Returns 1 if the instruction Inst has been fixed, and zero otherwise. |
| +size_t fixCallToMemset(Instruction *Inst) { |
| + size_t Count = 0; |
| + if (auto *Call = dyn_cast<CallInst>(Inst)) { |
| + if (Function *Fcn = Call->getCalledFunction()) { |
| + if ("llvm.memset.p0i8.i32" == Fcn->getName()) { |
| + Count += fixCallToMemset(Call); |
| + } |
| + } |
| + } |
| + return Count; |
| +} |
| + |
| +// Fixes appropriate memset calls in the basic Block. Returns the number of |
| +// fixed memset calls in the given basic Block. |
| +size_t fixCallsToMemset(BasicBlock *Block) { |
| + size_t Count = 0; |
| + for (auto &Inst : *Block) { |
| + Count += fixCallToMemset(&Inst); |
| + } |
| + return Count; |
| +} |
| + |
| +// Fixes appropriate memset calls in the function Fcn. Returns the number of |
| +// fixed memset calls for the given function. |
| +size_t fixCallsToMemset(Function *Fcn) { |
| + size_t Count = 0; |
| + for (auto &Block : *Fcn) { |
| + Count += fixCallsToMemset(&Block); |
| + } |
| + return Count; |
| +} |
| + |
| +// Fixes appropriate memset calls in module M> Returns the number of fixed |
| +// memset calls. |
| +size_t fixCallsToMemset(Module *M) { |
| + size_t ErrorCount = 0; |
| + for (auto &Fcn : *M) { |
| + if (!Fcn.isDeclaration()) |
| + ErrorCount += fixCallsToMemset(&Fcn); |
| + } |
| + return ErrorCount; |
| +} |
| + |
| +} // end of anonymous namespace |
| + |
| +int main(int argc, char **argv) { |
| + // Print a stack trace if we signal out. |
| + sys::PrintStackTraceOnErrorSignal(); |
| + PrettyStackTraceProgram X(argc, argv); |
| + |
| + LLVMContext &Context = getGlobalContext(); |
| + llvm_shutdown_obj Y; // Call llvm_shutdown() on exit. |
| + |
| + cl::ParseCommandLineOptions( |
| + argc, argv, "Converts NaCl pexe wire format into LLVM bitcode format\n"); |
| + |
| + std::string ErrorMessage; |
| + std::unique_ptr<Module> M(readBitcode(InputFilename, Context, ErrorMessage)); |
| + |
| + if (!M.get()) { |
| + errs() << argv[0] << ": "; |
| + if (ErrorMessage.size()) |
| + errs() << ErrorMessage << "\n"; |
| + else |
| + errs() << "bitcode didn't read correctly.\n"; |
| + return 1; |
| + } |
| + |
| + size_t ErrorCount = fixCallsToMemset(M.get()); |
| + if (ErrorCount > 0) { |
| + errs() << argv[0] << ": Fixed " << ErrorCount << " calls to memset.\n"; |
| + } |
| + |
| + WriteOutputFile(M.get()); |
| + return 0; |
| +} |