1 //===-- ImplicitNullChecks.cpp - Fold null checks into memory accesses ----===// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 // 10 // This pass turns explicit null checks of the form 11 // 12 // test %r10, %r10 13 // je throw_npe 14 // movl (%r10), %esi 15 // ... 16 // 17 // to 18 // 19 // faulting_load_op("movl (%r10), %esi", throw_npe) 20 // ... 21 // 22 // With the help of a runtime that understands the .fault_maps section, 23 // faulting_load_op branches to throw_npe if executing movl (%r10), %esi incurs 24 // a page fault. 25 // 26 //===----------------------------------------------------------------------===// 27 28 #include "llvm/ADT/DenseSet.h" 29 #include "llvm/ADT/SmallVector.h" 30 #include "llvm/ADT/Statistic.h" 31 #include "llvm/CodeGen/Passes.h" 32 #include "llvm/CodeGen/MachineFunction.h" 33 #include "llvm/CodeGen/MachineMemOperand.h" 34 #include "llvm/CodeGen/MachineOperand.h" 35 #include "llvm/CodeGen/MachineFunctionPass.h" 36 #include "llvm/CodeGen/MachineInstrBuilder.h" 37 #include "llvm/CodeGen/MachineRegisterInfo.h" 38 #include "llvm/CodeGen/MachineModuleInfo.h" 39 #include "llvm/IR/BasicBlock.h" 40 #include "llvm/IR/Instruction.h" 41 #include "llvm/IR/LLVMContext.h" 42 #include "llvm/Support/CommandLine.h" 43 #include "llvm/Support/Debug.h" 44 #include "llvm/Target/TargetSubtargetInfo.h" 45 #include "llvm/Target/TargetInstrInfo.h" 46 47 using namespace llvm; 48 49 static cl::opt<unsigned> PageSize("imp-null-check-page-size", 50 cl::desc("The page size of the target in " 51 "bytes"), 52 cl::init(4096)); 53 54 #define DEBUG_TYPE "implicit-null-checks" 55 56 STATISTIC(NumImplicitNullChecks, 57 "Number of explicit null checks made implicit"); 58 59 namespace { 60 61 class ImplicitNullChecks : public MachineFunctionPass { 62 /// Represents one null check that can be made implicit. 63 struct NullCheck { 64 // The memory operation the null check can be folded into. 65 MachineInstr *MemOperation; 66 67 // The instruction actually doing the null check (Ptr != 0). 68 MachineInstr *CheckOperation; 69 70 // The block the check resides in. 71 MachineBasicBlock *CheckBlock; 72 73 // The block branched to if the pointer is non-null. 74 MachineBasicBlock *NotNullSucc; 75 76 // The block branched to if the pointer is null. 77 MachineBasicBlock *NullSucc; 78 79 NullCheck() 80 : MemOperation(), CheckOperation(), CheckBlock(), NotNullSucc(), 81 NullSucc() {} 82 83 explicit NullCheck(MachineInstr *memOperation, MachineInstr *checkOperation, 84 MachineBasicBlock *checkBlock, 85 MachineBasicBlock *notNullSucc, 86 MachineBasicBlock *nullSucc) 87 : MemOperation(memOperation), CheckOperation(checkOperation), 88 CheckBlock(checkBlock), NotNullSucc(notNullSucc), NullSucc(nullSucc) { 89 } 90 }; 91 92 const TargetInstrInfo *TII = nullptr; 93 const TargetRegisterInfo *TRI = nullptr; 94 MachineModuleInfo *MMI = nullptr; 95 96 bool analyzeBlockForNullChecks(MachineBasicBlock &MBB, 97 SmallVectorImpl<NullCheck> &NullCheckList); 98 MachineInstr *insertFaultingLoad(MachineInstr *LoadMI, MachineBasicBlock *MBB, 99 MCSymbol *HandlerLabel); 100 void rewriteNullChecks(ArrayRef<NullCheck> NullCheckList); 101 102 public: 103 static char ID; 104 105 ImplicitNullChecks() : MachineFunctionPass(ID) { 106 initializeImplicitNullChecksPass(*PassRegistry::getPassRegistry()); 107 } 108 109 bool runOnMachineFunction(MachineFunction &MF) override; 110 }; 111 } 112 113 bool ImplicitNullChecks::runOnMachineFunction(MachineFunction &MF) { 114 TII = MF.getSubtarget().getInstrInfo(); 115 TRI = MF.getRegInfo().getTargetRegisterInfo(); 116 MMI = &MF.getMMI(); 117 118 SmallVector<NullCheck, 16> NullCheckList; 119 120 for (auto &MBB : MF) 121 analyzeBlockForNullChecks(MBB, NullCheckList); 122 123 if (!NullCheckList.empty()) 124 rewriteNullChecks(NullCheckList); 125 126 return !NullCheckList.empty(); 127 } 128 129 /// Analyze MBB to check if its terminating branch can be turned into an 130 /// implicit null check. If yes, append a description of the said null check to 131 /// NullCheckList and return true, else return false. 132 bool ImplicitNullChecks::analyzeBlockForNullChecks( 133 MachineBasicBlock &MBB, SmallVectorImpl<NullCheck> &NullCheckList) { 134 typedef TargetInstrInfo::MachineBranchPredicate MachineBranchPredicate; 135 136 MDNode *BranchMD = 137 MBB.getBasicBlock() 138 ? MBB.getBasicBlock()->getTerminator()->getMetadata(LLVMContext::MD_make_implicit) 139 : nullptr; 140 if (!BranchMD) 141 return false; 142 143 MachineBranchPredicate MBP; 144 145 if (TII->AnalyzeBranchPredicate(MBB, MBP, true)) 146 return false; 147 148 // Is the predicate comparing an integer to zero? 149 if (!(MBP.LHS.isReg() && MBP.RHS.isImm() && MBP.RHS.getImm() == 0 && 150 (MBP.Predicate == MachineBranchPredicate::PRED_NE || 151 MBP.Predicate == MachineBranchPredicate::PRED_EQ))) 152 return false; 153 154 // If we cannot erase the test instruction itself, then making the null check 155 // implicit does not buy us much. 156 if (!MBP.SingleUseCondition) 157 return false; 158 159 MachineBasicBlock *NotNullSucc, *NullSucc; 160 161 if (MBP.Predicate == MachineBranchPredicate::PRED_NE) { 162 NotNullSucc = MBP.TrueDest; 163 NullSucc = MBP.FalseDest; 164 } else { 165 NotNullSucc = MBP.FalseDest; 166 NullSucc = MBP.TrueDest; 167 } 168 169 // We handle the simplest case for now. We can potentially do better by using 170 // the machine dominator tree. 171 if (NotNullSucc->pred_size() != 1) 172 return false; 173 174 // Starting with a code fragment like: 175 // 176 // test %RAX, %RAX 177 // jne LblNotNull 178 // 179 // LblNull: 180 // callq throw_NullPointerException 181 // 182 // LblNotNull: 183 // Inst0 184 // Inst1 185 // ... 186 // Def = Load (%RAX + <offset>) 187 // ... 188 // 189 // 190 // we want to end up with 191 // 192 // Def = TrappingLoad (%RAX + <offset>), LblNull 193 // jmp LblNotNull ;; explicit or fallthrough 194 // 195 // LblNotNull: 196 // Inst0 197 // Inst1 198 // ... 199 // 200 // LblNull: 201 // callq throw_NullPointerException 202 // 203 204 unsigned PointerReg = MBP.LHS.getReg(); 205 206 // As we scan NotNullSucc for a suitable load instruction, we keep track of 207 // the registers defined and used by the instructions we scan past. This bit 208 // of information lets us decide if it is legal to hoist the load instruction 209 // we find (if we do find such an instruction) to before NotNullSucc. 210 DenseSet<unsigned> RegDefs, RegUses; 211 212 // Returns true if it is safe to reorder MI to before NotNullSucc. 213 auto IsSafeToHoist = [&](MachineInstr *MI) { 214 // Right now we don't want to worry about LLVM's memory model. This can be 215 // made more precise later. 216 for (auto *MMO : MI->memoperands()) 217 if (!MMO->isUnordered()) 218 return false; 219 220 for (auto &MO : MI->operands()) { 221 if (MO.isReg() && MO.getReg()) { 222 for (unsigned Reg : RegDefs) 223 if (TRI->regsOverlap(Reg, MO.getReg())) 224 return false; // We found a write-after-write or read-after-write 225 226 if (MO.isDef()) 227 for (unsigned Reg : RegUses) 228 if (TRI->regsOverlap(Reg, MO.getReg())) 229 return false; // We found a write-after-read 230 } 231 } 232 233 return true; 234 }; 235 236 for (auto MII = NotNullSucc->begin(), MIE = NotNullSucc->end(); MII != MIE; 237 ++MII) { 238 MachineInstr *MI = &*MII; 239 unsigned BaseReg, Offset; 240 if (TII->getMemOpBaseRegImmOfs(MI, BaseReg, Offset, TRI)) 241 if (MI->mayLoad() && !MI->isPredicable() && BaseReg == PointerReg && 242 Offset < PageSize && MI->getDesc().getNumDefs() <= 1 && 243 IsSafeToHoist(MI)) { 244 NullCheckList.emplace_back(MI, MBP.ConditionDef, &MBB, NotNullSucc, 245 NullSucc); 246 return true; 247 } 248 249 // MI did not match our criteria for conversion to a trapping load. Check 250 // if we can continue looking. 251 252 if (MI->mayStore() || MI->hasUnmodeledSideEffects()) 253 return false; 254 255 for (auto *MMO : MI->memoperands()) 256 // Right now we don't want to worry about LLVM's memory model. 257 if (!MMO->isUnordered()) 258 return false; 259 260 // It _may_ be okay to reorder a later load instruction across MI. Make a 261 // note of its operands so that we can make the legality check if we find a 262 // suitable load instruction: 263 264 for (auto &MO : MI->operands()) { 265 if (!MO.isReg() || !MO.getReg()) 266 continue; 267 268 if (MO.isDef()) 269 RegDefs.insert(MO.getReg()); 270 else 271 RegUses.insert(MO.getReg()); 272 } 273 } 274 275 return false; 276 } 277 278 /// Wrap a machine load instruction, LoadMI, into a FAULTING_LOAD_OP machine 279 /// instruction. The FAULTING_LOAD_OP instruction does the same load as LoadMI 280 /// (defining the same register), and branches to HandlerLabel if the load 281 /// faults. The FAULTING_LOAD_OP instruction is inserted at the end of MBB. 282 MachineInstr *ImplicitNullChecks::insertFaultingLoad(MachineInstr *LoadMI, 283 MachineBasicBlock *MBB, 284 MCSymbol *HandlerLabel) { 285 const unsigned NoRegister = 0; // Guaranteed to be the NoRegister value for 286 // all targets. 287 288 DebugLoc DL; 289 unsigned NumDefs = LoadMI->getDesc().getNumDefs(); 290 assert(NumDefs <= 1 && "other cases unhandled!"); 291 292 unsigned DefReg = NoRegister; 293 if (NumDefs != 0) { 294 DefReg = LoadMI->defs().begin()->getReg(); 295 assert(std::distance(LoadMI->defs().begin(), LoadMI->defs().end()) == 1 && 296 "expected exactly one def!"); 297 } 298 299 auto MIB = BuildMI(MBB, DL, TII->get(TargetOpcode::FAULTING_LOAD_OP), DefReg) 300 .addSym(HandlerLabel) 301 .addImm(LoadMI->getOpcode()); 302 303 for (auto &MO : LoadMI->uses()) 304 MIB.addOperand(MO); 305 306 MIB.setMemRefs(LoadMI->memoperands_begin(), LoadMI->memoperands_end()); 307 308 return MIB; 309 } 310 311 /// Rewrite the null checks in NullCheckList into implicit null checks. 312 void ImplicitNullChecks::rewriteNullChecks( 313 ArrayRef<ImplicitNullChecks::NullCheck> NullCheckList) { 314 DebugLoc DL; 315 316 for (auto &NC : NullCheckList) { 317 MCSymbol *HandlerLabel = MMI->getContext().createTempSymbol(); 318 319 // Remove the conditional branch dependent on the null check. 320 unsigned BranchesRemoved = TII->RemoveBranch(*NC.CheckBlock); 321 (void)BranchesRemoved; 322 assert(BranchesRemoved > 0 && "expected at least one branch!"); 323 324 // Insert a faulting load where the conditional branch was originally. We 325 // check earlier ensures that this bit of code motion is legal. We do not 326 // touch the successors list for any basic block since we haven't changed 327 // control flow, we've just made it implicit. 328 insertFaultingLoad(NC.MemOperation, NC.CheckBlock, HandlerLabel); 329 NC.MemOperation->eraseFromParent(); 330 NC.CheckOperation->eraseFromParent(); 331 332 // Insert an *unconditional* branch to not-null successor. 333 TII->InsertBranch(*NC.CheckBlock, NC.NotNullSucc, nullptr, /*Cond=*/None, 334 DL); 335 336 // Emit the HandlerLabel as an EH_LABEL. 337 BuildMI(*NC.NullSucc, NC.NullSucc->begin(), DL, 338 TII->get(TargetOpcode::EH_LABEL)).addSym(HandlerLabel); 339 340 NumImplicitNullChecks++; 341 } 342 } 343 344 char ImplicitNullChecks::ID = 0; 345 char &llvm::ImplicitNullChecksID = ImplicitNullChecks::ID; 346 INITIALIZE_PASS_BEGIN(ImplicitNullChecks, "implicit-null-checks", 347 "Implicit null checks", false, false) 348 INITIALIZE_PASS_END(ImplicitNullChecks, "implicit-null-checks", 349 "Implicit null checks", false, false) 350