| //===- InlineFastChecks.cpp - Inline Fast Checks -------------------------- --// |
| // |
| // The SAFECode Compiler |
| // |
| // This file was developed by the LLVM research group and is distributed under |
| // the University of Illinois Open Source License. See LICENSE.TXT for details. |
| // |
| //===----------------------------------------------------------------------===// |
| // |
| // This pass replaces calls to fastlscheck within inline code to perform the |
| // check. It is designed to provide the advantage of libLTO without libLTO. |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #define DEBUG_TYPE "inline-fastchecks" |
| |
| #include "llvm/ADT/Statistic.h" |
| #include "llvm/IR/Constants.h" |
| #include "llvm/IR/DataLayout.h" |
| #include "llvm/IR/Instruction.h" |
| #include "llvm/IR/Instructions.h" |
| #include "llvm/IR/Module.h" |
| #include "llvm/Pass.h" |
| #include "llvm/Transforms/Utils/Cloning.h" |
| |
| #include <vector> |
| |
| namespace { |
| STATISTIC (Inlined, "Number of Fast Checks Inlined"); |
| } |
| |
| namespace llvm { |
| // |
| // Pass: InlineFastChecks |
| // |
| // Description: |
| // This pass inlines fast checks to make them faster. |
| // |
| struct InlineFastChecks : public ModulePass { |
| public: |
| static char ID; |
| InlineFastChecks() : ModulePass(ID) {} |
| virtual bool runOnModule (Module & M); |
| const char *getPassName() const { |
| return "Inline fast checks transform"; |
| } |
| |
| virtual void getAnalysisUsage(AnalysisUsage &AU) const { |
| AU.addRequired<DataLayout>(); |
| return; |
| } |
| |
| private: |
| // Private methods |
| bool inlineCheck (Function * F); |
| bool createBodyFor (Function * F); |
| bool createDebugBodyFor (Function * F); |
| Value * castToInt (Value * Pointer, BasicBlock * BB); |
| Value * addComparisons (BasicBlock *, Value *, Value *, Value *); |
| }; |
| } |
| |
| using namespace llvm; |
| |
| // |
| // Method: findChecks() |
| // |
| // Description: |
| // Find the checks that need to be inlined and inline them. |
| // |
| // Inputs: |
| // F - A pointer to the function. Calls to this function will be inlined. |
| // The pointer is allowed to be NULL. |
| // |
| // Return value: |
| // true - One or more calls to the check were inlined. |
| // false - No calls to the check were inlined. |
| // |
| bool |
| llvm::InlineFastChecks::inlineCheck (Function * F) { |
| // |
| // Get the runtime function in the code. If no calls to the run-time |
| // function were added to the code, do nothing. |
| // |
| if (!F) return false; |
| |
| // |
| // Iterate though all calls to the function and search for pointers that are |
| // checked but only used in comparisons. If so, then schedule the check |
| // (i.e., the call) for removal. |
| // |
| bool modified = false; |
| std::vector<CallInst *> CallsToInline; |
| for (Value::use_iterator FU = F->use_begin(); FU != F->use_end(); ++FU) { |
| // |
| // We are only concerned about call instructions; any other use is of |
| // no interest to the organization. |
| // |
| if (CallInst * CI = dyn_cast<CallInst>(*FU)) { |
| // |
| // If the call instruction has no uses, we can remove it. |
| // |
| if (CI->use_begin() == CI->use_end()) |
| CallsToInline.push_back (CI); |
| } |
| } |
| |
| // |
| // Update the statistics and determine if we will modify anything. |
| // |
| if (CallsToInline.size()) { |
| modified = true; |
| Inlined += CallsToInline.size(); |
| } |
| |
| // |
| // Inline all of the fast calls we found. |
| // |
| DataLayout & TD = getAnalysis<DataLayout>(); |
| InlineFunctionInfo IFI (0, &TD); |
| for (unsigned index = 0; index < CallsToInline.size(); ++index) { |
| InlineFunction (CallsToInline[index], IFI); |
| } |
| |
| return modified; |
| } |
| |
| // |
| // Function: createFaultBlock() |
| // |
| // Description: |
| // Create a basic block which will cause the program to terminate. |
| // |
| // Inputs: |
| // F - A reference to a function to which a faulting basic block will be added. |
| // |
| static BasicBlock * |
| createFaultBlock (Function & F) { |
| // |
| // Create the basic block. |
| // |
| BasicBlock * faultBB = BasicBlock::Create (F.getContext(), "fault", &F); |
| |
| // |
| // Terminate the basic block with an unreachable instruction. |
| // |
| Instruction * UI = new UnreachableInst (F.getContext(), faultBB); |
| |
| // |
| // Add an instruction that will generate a trap. |
| // |
| LLVMContext & Context = F.getContext(); |
| Module * M = F.getParent(); |
| M->getOrInsertFunction ("abort", Type::getVoidTy (Context), NULL); |
| CallInst::Create (M->getFunction ("abort"), "", UI); |
| |
| return faultBB; |
| } |
| |
| // |
| // Function: createDebugFaultBlock() |
| // |
| // Description: |
| // Create a basic block which will cause the program to report a memory safety |
| // error. |
| // |
| // Inputs: |
| // F - A reference to a function to which a faulting basic block will be added. |
| // |
| static BasicBlock * |
| createDebugFaultBlock (Function & F) { |
| // |
| // Create the basic block. |
| // |
| BasicBlock * faultBB = BasicBlock::Create (F.getContext(), "fault", &F); |
| |
| // |
| // Terminate the basic block with a return instruction. |
| // |
| Instruction * Ret = ReturnInst::Create (F.getContext(), faultBB); |
| |
| // |
| // Create needed types. |
| // |
| LLVMContext & Context = F.getContext(); |
| Type * Int8Type = IntegerType::getInt8Ty (Context); |
| |
| // |
| // Add a call to print the debug information. |
| // |
| Module * M = F.getParent(); |
| M->getOrInsertFunction ("failLSCheck", |
| Type::getVoidTy (Context), |
| PointerType::getUnqual(Int8Type), |
| PointerType::getUnqual(Int8Type), |
| IntegerType::getInt32Ty(Context), |
| PointerType::getUnqual(Int8Type), |
| IntegerType::getInt32Ty (Context), |
| NULL); |
| std::vector<Value *> args; |
| unsigned index = 0; |
| for (Function::arg_iterator arg = F.arg_begin(); |
| arg != F.arg_end(); |
| ++arg, ++index) { |
| if ((index < 3) || (index > 4)) { |
| args.push_back (&*arg); |
| } |
| } |
| CallInst::Create (M->getFunction ("failLSCheck"), args, "", Ret); |
| |
| return faultBB; |
| } |
| |
| // |
| // Method: castToInt() |
| // |
| // Description: |
| // Cast the given pointer value into an integer. |
| // |
| Value * |
| llvm::InlineFastChecks::castToInt (Value * Pointer, BasicBlock * BB) { |
| // |
| // Assert that the caller is giving us a pointer value. |
| // |
| assert (isa<PointerType>(Pointer->getType())); |
| |
| // |
| // Get information on the size of pointers. |
| // |
| DataLayout & TD = getAnalysis<DataLayout>(); |
| |
| // |
| // Create the actual cast instrution. |
| // |
| return new PtrToIntInst (Pointer, TD.getIntPtrType(Pointer->getType()), "tmp", BB); |
| } |
| |
| // |
| // Method: addComparisons() |
| // |
| // Description: |
| // This function adds the comparisons needs for load/store checks. |
| // |
| // Return value: |
| // A pointer to an LLVM boolean value representing the logical AND of the two |
| // comparisons is returned. If the value is true, then the pointer is within |
| // bounds. Otherwise, it is out of bounds. |
| // |
| Value * |
| llvm::InlineFastChecks::addComparisons (BasicBlock * BB, |
| Value * Base, |
| Value * Result, |
| Value * Size) { |
| // |
| // Compare the base of the object to the pointer being checked. |
| // |
| ICmpInst * Compare1 = new ICmpInst (*BB, |
| CmpInst::ICMP_ULE, |
| Base, |
| Result, |
| "cmp1"); |
| |
| // |
| // Calculate the address of the first byte beyond the memory object |
| // |
| DataLayout & TD = getAnalysis<DataLayout>(); |
| Value * SizeInt = Size; |
| if (SizeInt->getType() != TD.getIntPtrType(BB->getType())) { |
| SizeInt = new ZExtInst (Size, TD.getIntPtrType(BB->getType()), "size", BB); |
| } |
| Value * LastByte = BinaryOperator::Create (Instruction::Add, |
| Base, |
| SizeInt, |
| "lastbyte", |
| BB); |
| |
| // |
| // Compare the pointer to the first byte beyond the end of the memory object |
| // |
| Value * Compare2 = new ICmpInst (*BB, |
| CmpInst::ICMP_ULT, |
| Result, |
| LastByte, |
| "cmp2"); |
| |
| // |
| // Combine the results of both comparisons. |
| // |
| return (BinaryOperator::Create (Instruction::And, |
| Compare1, |
| Compare2, |
| "and", |
| BB)); |
| } |
| |
| // |
| // Method: createBodyFor() |
| // |
| // Description: |
| // Create the function body for the fastlscheck() function. |
| // |
| // Inputs: |
| // F - A pointer to a function with no body. This pointer can be NULL. |
| // |
| bool |
| llvm::InlineFastChecks::createBodyFor (Function * F) { |
| // |
| // If the function does not exist, do nothing. |
| // |
| if (!F) return false; |
| |
| // |
| // If the function has a body, do nothing. |
| // |
| if (!(F->isDeclaration())) return false; |
| |
| // |
| // Create an entry block that will perform the comparisons and branch either |
| // to the success block or the fault block. |
| // |
| LLVMContext & Context = F->getContext(); |
| BasicBlock * entryBB = BasicBlock::Create (Context, "entry", F); |
| |
| // |
| // Create a basic block that just returns. |
| // |
| BasicBlock * goodBB = BasicBlock::Create (Context, "pass", F); |
| ReturnInst::Create (F->getContext(), goodBB); |
| |
| // |
| // Create a basic block that handles the run-time check failures. |
| // |
| BasicBlock * faultBB = createFaultBlock (*F); |
| |
| // |
| // Add instructions to the entry block to compare the first dereferenced |
| // address. |
| // |
| Function::arg_iterator arg = F->arg_begin(); |
| Value * Base = castToInt (arg++, entryBB); |
| Value * Result = castToInt (arg++, entryBB); |
| Value * Size = arg++; |
| Value * MemSize = arg++; |
| Value * Sum1 = addComparisons (entryBB, Base, Result, Size); |
| |
| // |
| // Now add instructions to compare the last byte dereferenced with the |
| // memory object's bounds. |
| // |
| DataLayout & TD = getAnalysis<DataLayout>(); |
| Value * SizeInt = MemSize; |
| if (SizeInt->getType() != TD.getIntPtrType(entryBB->getType())) { |
| SizeInt = new ZExtInst (MemSize, TD.getIntPtrType(entryBB->getType()), "size", entryBB); |
| } |
| Value * LastByte = BinaryOperator::Create (Instruction::Add, |
| Result, |
| SizeInt, |
| "lastbyte", |
| entryBB); |
| Constant * MinusOne = ConstantInt::getSigned (TD.getIntPtrType(entryBB->getType()), -1); |
| LastByte = BinaryOperator::Create (Instruction::Add, |
| LastByte, |
| MinusOne, |
| "lastbyte", |
| entryBB); |
| Value * Sum2 = addComparisons (entryBB, Base, LastByte, Size); |
| |
| // |
| // The check only passes if both the first and last byte accessed are within |
| // bounds. |
| // |
| Value * Sum = BinaryOperator::Create (Instruction::And, |
| Sum1, |
| Sum2, |
| "and", |
| entryBB); |
| |
| |
| // |
| // Create the branch instruction. |
| // |
| BranchInst::Create (goodBB, faultBB, Sum, entryBB); |
| |
| // |
| // Make the function internal. |
| // |
| F->setLinkage (GlobalValue::InternalLinkage); |
| return true; |
| } |
| |
| // |
| // Method: createDebugBodyFor() |
| // |
| // Description: |
| // Create the function body for the fastlscheck_debug() function. |
| // |
| // Inputs: |
| // F - A pointer to a function with no body. This pointer can be NULL. |
| // |
| bool |
| llvm::InlineFastChecks::createDebugBodyFor (Function * F) { |
| // |
| // If the function does not exist, do nothing. |
| // |
| if (!F) return false; |
| |
| // |
| // If the function has a body, do nothing. |
| // |
| if (!(F->isDeclaration())) return false; |
| |
| // |
| // Create an entry block that will perform the comparisons and branch either |
| // to the success block or the fault block. |
| // |
| LLVMContext & Context = F->getContext(); |
| BasicBlock * entryBB = BasicBlock::Create (Context, "entry", F); |
| |
| // |
| // Create a basic block that just returns. |
| // |
| BasicBlock * goodBB = BasicBlock::Create (Context, "pass", F); |
| ReturnInst::Create (F->getContext(), goodBB); |
| |
| // |
| // Create a basic block that handles the run-time check failures. |
| // |
| BasicBlock * faultBB = createDebugFaultBlock (*F); |
| |
| // |
| // Add instructions to the entry block to compare the first dereferenced |
| // address. |
| // |
| Function::arg_iterator arg = F->arg_begin(); |
| Value * Base = castToInt (arg++, entryBB); |
| Value * Result = castToInt (arg++, entryBB); |
| Value * Size = arg++; |
| Value * MemSize = arg++; |
| Value * Sum1 = addComparisons (entryBB, Base, Result, Size); |
| |
| // |
| // Now add instructions to compare the last byte dereferenced with the |
| // memory object's bounds. |
| // |
| DataLayout & TD = getAnalysis<DataLayout>(); |
| Value * SizeInt = MemSize; |
| if (SizeInt->getType() != TD.getIntPtrType(entryBB->getType())) { |
| SizeInt = new ZExtInst (MemSize, TD.getIntPtrType(entryBB->getType()), "size", entryBB); |
| } |
| Value * LastByte = BinaryOperator::Create (Instruction::Add, |
| Result, |
| SizeInt, |
| "lastbyte", |
| entryBB); |
| Constant * MinusOne = ConstantInt::getSigned (TD.getIntPtrType(entryBB->getType()), -1); |
| LastByte = BinaryOperator::Create (Instruction::Add, |
| LastByte, |
| MinusOne, |
| "lastbyte", |
| entryBB); |
| Value * Sum2 = addComparisons (entryBB, Base, LastByte, Size); |
| |
| // |
| // The check only passes if both the first and last byte accessed are within |
| // bounds. |
| // |
| Value * Sum = BinaryOperator::Create (Instruction::And, |
| Sum1, |
| Sum2, |
| "and", |
| entryBB); |
| |
| // |
| // Create the branch instruction. Both comparisons must return true for the |
| // pointer to be within bounds. |
| // |
| BranchInst::Create (goodBB, faultBB, Sum, entryBB); |
| |
| // |
| // Make the function internal. |
| // |
| F->setLinkage (GlobalValue::InternalLinkage); |
| return true; |
| } |
| |
| bool |
| llvm::InlineFastChecks::runOnModule (Module & M) { |
| // |
| // Create a function body for the fastlscheck call. |
| // |
| createBodyFor (M.getFunction ("fastlscheck")); |
| createDebugBodyFor (M.getFunction ("fastlscheck_debug")); |
| |
| // |
| // Search for call sites to the function and forcibly inline them. |
| // |
| inlineCheck (M.getFunction ("fastlscheck")); |
| inlineCheck (M.getFunction ("fastlscheck_debug")); |
| return true; |
| } |
| |
| namespace llvm { |
| char InlineFastChecks::ID = 0; |
| |
| static RegisterPass<InlineFastChecks> |
| X ("inline-fastchecks", "Inline fast run-time checks", true); |
| |
| ModulePass * createInlineFastChecksPass (void) { |
| return new InlineFastChecks(); |
| } |
| } |