diff options
author | Cristian Cadar <c.cadar@imperial.ac.uk> | 2017-07-20 14:16:39 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2017-07-20 14:16:39 +0100 |
commit | 051e44e59cc5260324667d3fd8a8d46d54c3e72e (patch) | |
tree | 34fdea2badf338c2f6d78185cc5e03cea19cab9b /lib/Module/InstructionOperandTypeCheckPass.cpp | |
parent | 99a1e3a25cd1405a15112a85de1ff5fc714e7be1 (diff) | |
parent | ffe695c29915cf8605b2fb807cd083cdcc769d47 (diff) | |
download | klee-051e44e59cc5260324667d3fd8a8d46d54c3e72e.tar.gz |
Merge pull request #657 from delcypher/vectorized_instructions
Implement basic support for vectorized instructions.
Diffstat (limited to 'lib/Module/InstructionOperandTypeCheckPass.cpp')
-rw-r--r-- | lib/Module/InstructionOperandTypeCheckPass.cpp | 184 |
1 files changed, 184 insertions, 0 deletions
diff --git a/lib/Module/InstructionOperandTypeCheckPass.cpp b/lib/Module/InstructionOperandTypeCheckPass.cpp new file mode 100644 index 00000000..449eea48 --- /dev/null +++ b/lib/Module/InstructionOperandTypeCheckPass.cpp @@ -0,0 +1,184 @@ +//===-- InstructionOperandTypeCheckPass.cpp ---------------------*- C++ -*-===// +// +// The KLEE Symbolic Virtual Machine +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +#include "Passes.h" +#include "klee/Config/Version.h" +#include "klee/Internal/Support/ErrorHandling.h" +#include "llvm/Support/raw_ostream.h" + +using namespace llvm; + +namespace { + +void printOperandWarning(const char *expected, const Instruction *i, + LLVM_TYPE_Q Type *ty, unsigned opNum) { + std::string msg; + llvm::raw_string_ostream ss(msg); + ss << "Found unexpected type (" << *ty << ") at operand " << opNum + << ". Expected " << expected << " in " << *i; + i->print(ss); + ss.flush(); + klee::klee_warning("%s", msg.c_str()); +} + +bool checkOperandTypeIsScalarInt(const Instruction *i, unsigned opNum) { + assert(opNum < i->getNumOperands()); + LLVM_TYPE_Q llvm::Type *ty = i->getOperand(opNum)->getType(); + if (!(ty->isIntegerTy())) { + printOperandWarning("scalar integer", i, ty, opNum); + return false; + } + return true; +} + +bool checkOperandTypeIsScalarIntOrPointer(const Instruction *i, + unsigned opNum) { + assert(opNum < i->getNumOperands()); + LLVM_TYPE_Q llvm::Type *ty = i->getOperand(opNum)->getType(); + if (!(ty->isIntegerTy() || ty->isPointerTy())) { + printOperandWarning("scalar integer or pointer", i, ty, opNum); + return false; + } + return true; +} + +bool checkOperandTypeIsScalarPointer(const Instruction *i, unsigned opNum) { + assert(opNum < i->getNumOperands()); + LLVM_TYPE_Q llvm::Type *ty = i->getOperand(opNum)->getType(); + if (!(ty->isPointerTy())) { + printOperandWarning("scalar pointer", i, ty, opNum); + return false; + } + return true; +} + +bool checkOperandTypeIsScalarFloat(const Instruction *i, unsigned opNum) { + assert(opNum < i->getNumOperands()); + LLVM_TYPE_Q llvm::Type *ty = i->getOperand(opNum)->getType(); + if (!(ty->isFloatingPointTy())) { + printOperandWarning("scalar float", i, ty, opNum); + return false; + } + return true; +} + +bool checkOperandsHaveSameType(const Instruction *i, unsigned opNum0, + unsigned opNum1) { + assert(opNum0 < i->getNumOperands()); + assert(opNum1 < i->getNumOperands()); + LLVM_TYPE_Q llvm::Type *ty0 = i->getOperand(opNum0)->getType(); + LLVM_TYPE_Q llvm::Type *ty1 = i->getOperand(opNum1)->getType(); + if (!(ty0 == ty1)) { + std::string msg; + llvm::raw_string_ostream ss(msg); + ss << "Found mismatched type (" << *ty0 << " != " << *ty1 + << ") for operands" << opNum0 << " and " << opNum1 + << ". Expected operand types to match in " << *i; + i->print(ss); + ss.flush(); + klee::klee_warning("%s", msg.c_str()); + return false; + } + return true; +} + +bool checkInstruction(const Instruction *i) { + switch (i->getOpcode()) { + case Instruction::Select: { + // Note we do not enforce that operand 1 and 2 are scalar because the + // scalarizer pass might not remove these. This could be selecting which + // vector operand to feed to another instruction. The Executor can handle + // this so case so this is not a problem + return checkOperandTypeIsScalarInt(i, 0) & + checkOperandsHaveSameType(i, 1, 2); + } + // Integer arithmetic, logical and shifting + // TODO: When we upgrade to newer LLVM use LLVM_FALLTHROUGH + case Instruction::Add: + case Instruction::Sub: + case Instruction::Mul: + case Instruction::UDiv: + case Instruction::SDiv: + case Instruction::URem: + case Instruction::SRem: + case Instruction::And: + case Instruction::Or: + case Instruction::Xor: + case Instruction::Shl: + case Instruction::LShr: + case Instruction::AShr: { + return checkOperandTypeIsScalarInt(i, 0) & + checkOperandTypeIsScalarInt(i, 1); + } + // Integer comparison + case Instruction::ICmp: { + return checkOperandTypeIsScalarIntOrPointer(i, 0) & + checkOperandTypeIsScalarIntOrPointer(i, 1); + } + // Integer Conversion + case Instruction::Trunc: + case Instruction::ZExt: + case Instruction::SExt: + case Instruction::IntToPtr: { + return checkOperandTypeIsScalarInt(i, 0); + } + case Instruction::PtrToInt: { + return checkOperandTypeIsScalarPointer(i, 0); + } + // TODO: Figure out if Instruction::BitCast needs checking + // Floating point arithmetic + case Instruction::FAdd: + case Instruction::FSub: + case Instruction::FMul: + case Instruction::FDiv: + case Instruction::FRem: { + return checkOperandTypeIsScalarFloat(i, 0) & + checkOperandTypeIsScalarFloat(i, 1); + } + // Floating point conversion + case Instruction::FPTrunc: + case Instruction::FPExt: + case Instruction::FPToUI: + case Instruction::FPToSI: { + return checkOperandTypeIsScalarFloat(i, 0); + } + case Instruction::UIToFP: + case Instruction::SIToFP: { + return checkOperandTypeIsScalarInt(i, 0); + } + // Floating point comparison + case Instruction::FCmp: { + return checkOperandTypeIsScalarFloat(i, 0) & + checkOperandTypeIsScalarFloat(i, 1); + } + default: + // Treat all other instructions as conforming + return true; + } +} +} + +namespace klee { + +char InstructionOperandTypeCheckPass::ID = 0; + +bool InstructionOperandTypeCheckPass::runOnModule(Module &M) { + instructionOperandsConform = true; + for (Module::iterator fi = M.begin(), fe = M.end(); fi != fe; ++fi) { + for (Function::iterator bi = fi->begin(), be = fi->end(); bi != be; ++bi) { + for (BasicBlock::iterator ii = bi->begin(), ie = bi->end(); ii != ie; + ++ii) { + Instruction *i = static_cast<Instruction *>(ii); + instructionOperandsConform &= checkInstruction(i); + } + } + } + + return false; +} +} |