| 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..5cc891cd659e9d73eff663858552809661bc6243
|
| --- /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 -----------------===//
|
| +//
|
| +//===----------------------------------------------------------------------===//
|
| +//
|
| +// Fixes generated pexe's so that a Subzero bug (fixed but not yet fully
|
| +// deployed until 10/2016). Does this by replacing calls to memset with a
|
| +// constant (negative) byte value, and corresponding constant count arguments,
|
| +// with a zero-add to the count. 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;
|
| +}
|
|
|