| OLD | NEW |
| (Empty) | |
| 1 /* Copyright 2016 The Native Client Authors. All rights reserved. |
| 2 * Use of this source code is governed by a BSD-style license that can |
| 3 * be found in the LICENSE file. |
| 4 */ |
| 5 |
| 6 //===-- pnacl-hack-memset.cpp - Fix (interim) Subzero bug -----------------===// |
| 7 // |
| 8 //===----------------------------------------------------------------------===// |
| 9 // |
| 10 // Fixes generated pexe's so that a Subzero bug (fixed but not yet fully |
| 11 // deployed until 10/2016). Does this by replacing calls to memset with a |
| 12 // constant (negative) byte value, and corresponding constant count arguments, |
| 13 // with a zero-add to the count. This causes the broken (and fixed) optimization |
| 14 // to not be fired. |
| 15 // |
| 16 //===----------------------------------------------------------------------===// |
| 17 |
| 18 #include "llvm/Bitcode/NaCl/NaClReaderWriter.h" |
| 19 #include "llvm/IR/Constants.h" |
| 20 #include "llvm/IR/InstIterator.h" |
| 21 #include "llvm/IR/Instructions.h" |
| 22 #include "llvm/IR/LLVMContext.h" |
| 23 #include "llvm/IR/Module.h" |
| 24 #include "llvm/Support/CommandLine.h" |
| 25 #include "llvm/Support/DataStream.h" |
| 26 #include "llvm/Support/FileSystem.h" |
| 27 #include "llvm/Support/ManagedStatic.h" |
| 28 #include "llvm/Support/PrettyStackTrace.h" |
| 29 #include "llvm/Support/Signals.h" |
| 30 #include "llvm/Support/StreamingMemoryObject.h" |
| 31 #include "llvm/Support/ToolOutputFile.h" |
| 32 |
| 33 using namespace llvm; |
| 34 |
| 35 namespace { |
| 36 |
| 37 cl::opt<std::string> |
| 38 OutputFilename("o", cl::desc("Specify fixed pexe filename"), |
| 39 cl::value_desc("fixed pexe file"), cl::init("-")); |
| 40 |
| 41 cl::opt<std::string> |
| 42 InputFilename(cl::Positional, cl::desc("<pexe file>"), cl::init("-")); |
| 43 |
| 44 cl::opt<bool> |
| 45 ShowFixes("show-fixes", cl::desc("Show fixes to memset"), cl::init(false)); |
| 46 |
| 47 void WriteOutputFile(const Module *M) { |
| 48 |
| 49 std::error_code EC; |
| 50 std::unique_ptr<tool_output_file> Out( |
| 51 new tool_output_file(OutputFilename, EC, sys::fs::F_None)); |
| 52 if (EC) { |
| 53 errs() << EC.message() << '\n'; |
| 54 exit(1); |
| 55 } |
| 56 |
| 57 NaClWriteBitcodeToFile(M, Out->os(), /* AcceptSupportedOnly = */ false); |
| 58 |
| 59 // Declare success. |
| 60 Out->keep(); |
| 61 } |
| 62 |
| 63 Module *readBitcode(std::string &Filename, LLVMContext &Context, |
| 64 std::string &ErrorMessage) { |
| 65 // Use the bitcode streaming interface |
| 66 DataStreamer *Streamer = getDataFileStreamer(InputFilename, &ErrorMessage); |
| 67 if (Streamer == nullptr) |
| 68 return nullptr; |
| 69 std::unique_ptr<StreamingMemoryObject> Buffer( |
| 70 new StreamingMemoryObjectImpl(Streamer)); |
| 71 std::string DisplayFilename; |
| 72 if (Filename == "-") |
| 73 DisplayFilename = "<stdin>"; |
| 74 else |
| 75 DisplayFilename = Filename; |
| 76 DiagnosticHandlerFunction DiagnosticHandler = nullptr; |
| 77 Module *M = getNaClStreamedBitcodeModule( |
| 78 DisplayFilename, Buffer.release(), Context, DiagnosticHandler, |
| 79 &ErrorMessage, /*AcceptSupportedOnly=*/false); |
| 80 if (!M) |
| 81 return nullptr; |
| 82 if (std::error_code EC = M->materializeAllPermanently()) { |
| 83 ErrorMessage = EC.message(); |
| 84 delete M; |
| 85 return nullptr; |
| 86 } |
| 87 return M; |
| 88 } |
| 89 |
| 90 // Fixes the memset call if appropriate. Returns 1 if the Call to memset has |
| 91 // been fixed, and zero otherwise. |
| 92 size_t fixCallToMemset(CallInst *Call) { |
| 93 if (Call->getNumArgOperands() != 5) |
| 94 return 0; |
| 95 Value *Val = Call->getArgOperand(1); |
| 96 auto *CVal = dyn_cast<ConstantInt>(Val); |
| 97 if (CVal == nullptr) |
| 98 return 0; |
| 99 if (!CVal->getType()->isIntegerTy(8)) |
| 100 return 0; |
| 101 const APInt &IVal = CVal->getUniqueInteger(); |
| 102 if (!IVal.isNegative()) |
| 103 return 0; |
| 104 Value *Count = Call->getArgOperand(2); |
| 105 auto *CCount = dyn_cast<ConstantInt>(Count); |
| 106 if (CCount == nullptr) |
| 107 return 0; |
| 108 if (!CCount->getType()->isIntegerTy(32)) |
| 109 return 0; |
| 110 if (ShowFixes) { |
| 111 Call->print(errs()); |
| 112 errs() << "\n-->\n"; |
| 113 } |
| 114 auto *Zero = ConstantInt::getSigned(CCount->getType(), 0); |
| 115 auto *Add = BinaryOperator::Create(Instruction::BinaryOps::Add, CCount, Zero); |
| 116 auto *IAdd = dyn_cast<Instruction>(Add); |
| 117 if (IAdd == nullptr) |
| 118 return 0; |
| 119 Call->setArgOperand(2, Add); |
| 120 IAdd->insertBefore(Call); |
| 121 if (ShowFixes) { |
| 122 IAdd->print(errs()); |
| 123 errs() << "\n"; |
| 124 Call->print(errs()); |
| 125 errs() << "\n\n"; |
| 126 } |
| 127 return 1; |
| 128 } |
| 129 |
| 130 // Fixes the instruction Inst, if it is a memset call that needs to be fixed. |
| 131 // Returns 1 if the instruction Inst has been fixed, and zero otherwise. |
| 132 size_t fixCallToMemset(Instruction *Inst) { |
| 133 size_t Count = 0; |
| 134 if (auto *Call = dyn_cast<CallInst>(Inst)) { |
| 135 if (Function *Fcn = Call->getCalledFunction()) { |
| 136 if ("llvm.memset.p0i8.i32" == Fcn->getName()) { |
| 137 Count += fixCallToMemset(Call); |
| 138 } |
| 139 } |
| 140 } |
| 141 return Count; |
| 142 } |
| 143 |
| 144 // Fixes appropriate memset calls in the basic Block. Returns the number of |
| 145 // fixed memset calls in the given basic Block. |
| 146 size_t fixCallsToMemset(BasicBlock *Block) { |
| 147 size_t Count = 0; |
| 148 for (auto &Inst : *Block) { |
| 149 Count += fixCallToMemset(&Inst); |
| 150 } |
| 151 return Count; |
| 152 } |
| 153 |
| 154 // Fixes appropriate memset calls in the function Fcn. Returns the number of |
| 155 // fixed memset calls for the given function. |
| 156 size_t fixCallsToMemset(Function *Fcn) { |
| 157 size_t Count = 0; |
| 158 for (auto &Block : *Fcn) { |
| 159 Count += fixCallsToMemset(&Block); |
| 160 } |
| 161 return Count; |
| 162 } |
| 163 |
| 164 // Fixes appropriate memset calls in module M> Returns the number of fixed |
| 165 // memset calls. |
| 166 size_t fixCallsToMemset(Module *M) { |
| 167 size_t ErrorCount = 0; |
| 168 for (auto &Fcn : *M) { |
| 169 if (!Fcn.isDeclaration()) |
| 170 ErrorCount += fixCallsToMemset(&Fcn); |
| 171 } |
| 172 return ErrorCount; |
| 173 } |
| 174 |
| 175 } // end of anonymous namespace |
| 176 |
| 177 int main(int argc, char **argv) { |
| 178 // Print a stack trace if we signal out. |
| 179 sys::PrintStackTraceOnErrorSignal(); |
| 180 PrettyStackTraceProgram X(argc, argv); |
| 181 |
| 182 LLVMContext &Context = getGlobalContext(); |
| 183 llvm_shutdown_obj Y; // Call llvm_shutdown() on exit. |
| 184 |
| 185 cl::ParseCommandLineOptions( |
| 186 argc, argv, "Converts NaCl pexe wire format into LLVM bitcode format\n"); |
| 187 |
| 188 std::string ErrorMessage; |
| 189 std::unique_ptr<Module> M(readBitcode(InputFilename, Context, ErrorMessage)); |
| 190 |
| 191 if (!M.get()) { |
| 192 errs() << argv[0] << ": "; |
| 193 if (ErrorMessage.size()) |
| 194 errs() << ErrorMessage << "\n"; |
| 195 else |
| 196 errs() << "bitcode didn't read correctly.\n"; |
| 197 return 1; |
| 198 } |
| 199 |
| 200 size_t ErrorCount = fixCallsToMemset(M.get()); |
| 201 if (ErrorCount > 0) { |
| 202 errs() << argv[0] << ": Fixed " << ErrorCount << " calls to memset.\n"; |
| 203 } |
| 204 |
| 205 WriteOutputFile(M.get()); |
| 206 return 0; |
| 207 } |
| OLD | NEW |