Chromium Code Reviews| 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 -----------------===// | |
|
Jim Stichnoth
2016/08/23 17:20:36
I would prefer capitalized Subzero... here and bel
Karl
2016/08/23 17:44:14
Done.
| |
| 7 // | |
| 8 //===----------------------------------------------------------------------===// | |
| 9 // | |
| 10 // 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.
| |
| 11 // yet fully deployed until 10/2016). Does this by replacing calls to | |
| 12 // memset with constant (negative) byte value, and corresponding | |
| 13 // constant count arguments, with an zero-add. This causes the broken | |
| 14 // (and fixed) optimization 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 |