//===----------------- QtmInst.cpp ----------------------===// // This file implements the Scaffold Quantum Instruction Class // // // // This file was created by Scaffold Compiler Working Group // // // // //===----------------------------------------------------------------------===// #define DEBUG_TYPE "QtmInst" #include #include "llvm/Pass.h" #include "llvm/Function.h" #include "llvm/Module.h" #include "llvm/BasicBlock.h" #include "llvm/Instruction.h" #include "llvm/Instructions.h" #include "llvm/Support/raw_ostream.h" #include "llvm/ADT/Statistic.h" #include "llvm/Support/InstIterator.h" #include "llvm/PassAnalysisSupport.h" #include "llvm/Analysis/CallGraph.h" #include "llvm/Support/CFG.h" #include "llvm/ADT/SCCIterator.h" #include "llvm/Argument.h" #include "llvm/ADT/ilist.h" #include "llvm/Constants.h" #include "llvm/IntrinsicInst.h" #include "scaffold/QtmGateArg.h" using namespace llvm; using namespace std; #define MAX_GATE_ARGS 30 #define MAX_BT_COUNT 15 //max backtrace allowed - to avoid infinite recursive loops bool debugQtmInst = false; namespace { struct qArgInfo{ string name; int index; qArgInfo(): name("none"), index(-1){ } }; struct qGate{ Function* qFunc; int numArgs; qArgInfo args[MAX_GATE_ARGS]; double angle; qGate():qFunc(NULL), numArgs(0), angle(0.0) { } }; struct QtmInst : public ModulePass { static char ID; // Pass identification vector tmpDepQbit; int btCount; //backtrace count QtmInst() : ModulePass(ID) {} bool checkIfQbitOrCbit(Type* varType); bool backtraceOperand(Value* opd, int opOrIndex); void analyzeCallInst(Function* F,Instruction* pinst); void print_qgate(qGate qg); bool runOnModule (Module &M); virtual void getAnalysisUsage(AnalysisUsage &AU) const { AU.setPreservesAll(); AU.addRequired(); } }; // End of struct QtmInst } // End of anonymous namespace char QtmInst::ID = 0; static RegisterPass X("QtmInst", "Get gate and operands for a Qtm Inst"); bool QtmInst::checkIfQbitOrCbit(Type* varType) { if(varType->isPointerTy()){ Type *elementType = varType->getPointerElementType(); if (elementType->isIntegerTy(16) || elementType->isIntegerTy(1)){ //qbit* or cbit* return true; } } else if (varType->isIntegerTy(16) || varType->isIntegerTy(1)){ //qbit or cbit return true; } return false; } bool QtmInst::backtraceOperand(Value* opd, int opOrIndex) { if(opOrIndex == 0) //backtrace for operand { if(Argument *fArg = dyn_cast(opd)) { Type* argType = fArg->getType(); bool isQtm = checkIfQbitOrCbit(argType); if(isQtm){ tmpDepQbit[0].argPtr = opd; return true; } } if (AllocaInst *AI = dyn_cast(opd)) { Type *allocatedType = AI->getAllocatedType(); if(ArrayType *arrayType = dyn_cast(allocatedType)) { Type *elementType = arrayType->getElementType(); bool isQtm = checkIfQbitOrCbit(elementType); if(isQtm){ tmpDepQbit[0].argPtr = opd; return true; } } } if(btCount>MAX_BT_COUNT) return false; if(isa(opd)) { Instruction* pInst = dyn_cast(opd); backtraceOperand(pInst->getOperand(0),0); unsigned numOps = pInst->getNumOperands(); //NOTE: getelemptr instruction can have multiple indices. Currently considering last operand as desired index for qubit. This may not be true for multi-dimensional qubit arrays if(ConstantInt *CI = dyn_cast(pInst->getOperand(numOps-1))){ if(tmpDepQbit.size()==1){ tmpDepQbit[0].valOrIndex = CI->getZExtValue(); } } else{ if(tmpDepQbit[0].isQbit && !(tmpDepQbit[0].isPtr)){ //NOTE: getelemptr instruction can have multiple indices. consider last operand as desired index for qubit. This may not be true for multi-dimensional qubit arrays backtraceOperand(pInst->getOperand(numOps-1),1); } } /* //For multi-dimensional qubit array, we may need to backtrace multiple pointer values for(unsigned iop=1;iopgetOperand(iop),0); }*/ return true; } if(Instruction* pInst = dyn_cast(opd)){ unsigned numOps = pInst->getNumOperands(); for(unsigned iop=0;iopgetOperand(iop),0); btCount--; } return true; } else{ return true; } } else if(opOrIndex == 0){ //opOrIndex == 1; i.e. Backtracing for Index if(btCount>MAX_BT_COUNT) //prevent infinite backtracing return true; if(ConstantInt *CI = dyn_cast(opd)){ tmpDepQbit[0].valOrIndex = CI->getZExtValue(); return true; } if(Instruction* pInst = dyn_cast(opd)){ unsigned numOps = pInst->getNumOperands(); for(unsigned iop=0;iopgetOperand(iop),1); btCount--; } } } else{ //opOrIndex == 2: backtracing to call inst MeasZ if(CallInst *endCI = dyn_cast(opd)){ if(endCI->getCalledFunction()->getName().find("llvm.Meas") != string::npos){ tmpDepQbit[0].argPtr = opd; return true; } else{ if(Instruction* pInst = dyn_cast(opd)){ unsigned numOps = pInst->getNumOperands(); bool foundOne=false; for(unsigned iop=0;(iopgetOperand(iop),2); btCount--; } return foundOne; } } } else{ if(Instruction* pInst = dyn_cast(opd)){ unsigned numOps = pInst->getNumOperands(); bool foundOne=false; for(unsigned iop=0;(iopgetOperand(iop),2); btCount--; } return foundOne; } } } return false; } void QtmInst::print_qgate(qGate qg){ errs() << qg.qFunc->getName() << " : "; for(int i=0;i(pInst)) { if(debugQtmInst) errs() << "Call inst: " << CI->getCalledFunction()->getName() << "\n"; if(CI->getCalledFunction()->getName() == "store_cbit"){ //trace return values return; } vector allDepQbit; bool tracked_operand = false; int myPrepState = -1; double myRotationAngle = 0.0; for(unsigned iop=0;iopgetNumArgOperands();iop++){ tmpDepQbit.clear(); QtmGateArg tmpQGateArg; btCount=0; tmpQGateArg.argNum = iop; if(isa(CI->getArgOperand(iop))){ errs() << "WARNING: LLVM IR code has UNDEF values. \n"; tmpQGateArg.isUndef = true; //exit(1); } Type* argType = CI->getArgOperand(iop)->getType(); if(argType->isPointerTy()){ tmpQGateArg.isPtr = true; Type *argElemType = argType->getPointerElementType(); if(argElemType->isIntegerTy(16)) tmpQGateArg.isQbit = true; if(argElemType->isIntegerTy(1)) tmpQGateArg.isCbit = true; } else if(argType->isIntegerTy(16)){ tmpQGateArg.isQbit = true; tmpQGateArg.valOrIndex = 0; } else if(argType->isIntegerTy(1)){ tmpQGateArg.isCbit = true; tmpQGateArg.valOrIndex = 0; } //check if argument is constant int if(ConstantInt *CInt = dyn_cast(CI->getArgOperand(iop))){ myPrepState = CInt->getZExtValue(); } //check if argument is constant float if(ConstantFP *CFP = dyn_cast(CI->getArgOperand(iop))){ myRotationAngle = CFP->getValueAPF().convertToDouble(); } //if(tmpQGateArg.isQbit || tmpQGateArg.isCbit){ if(tmpQGateArg.isQbit){ tmpDepQbit.push_back(tmpQGateArg); tracked_operand = backtraceOperand(CI->getArgOperand(iop),0); } if(tmpDepQbit.size()>0){ allDepQbit.push_back(tmpDepQbit[0]); assert(tmpDepQbit.size() == 1 && "tmpDepQbit SIZE GT 1"); tmpDepQbit.clear(); } } if(allDepQbit.size() > 0){ if(debugQtmInst) { errs() << "\nCall inst: " << CI->getCalledFunction()->getName(); errs() << ": Found all arguments: "; for(unsigned int vb=0; vbgetName() <<" Index: "; //else errs() << allDepQbit[vb].valOrIndex <<" "; } errs()<<"\n"; } string fname = CI->getCalledFunction()->getName(); qGate thisGate; thisGate.qFunc = CI->getCalledFunction(); if(myPrepState!=-1) thisGate.angle = (float)myPrepState; if(myRotationAngle!=0.0) thisGate.angle = myRotationAngle; for(unsigned int vb=0; vbgetName() <<" Index: "; //errs() << allDepQbit[vb].valOrIndex <<"\n"; QtmGateArg param = allDepQbit[vb]; thisGate.args[thisGate.numArgs].name = param.argPtr->getName(); if(!param.isPtr) thisGate.args[thisGate.numArgs].index = param.valOrIndex; thisGate.numArgs++; } } print_qgate(thisGate); } allDepQbit.erase(allDepQbit.begin(),allDepQbit.end()); } } bool QtmInst::runOnModule (Module &M) { // iterate over all functions, and over all instructions in those functions CallGraphNode* rootNode = getAnalysis().getRoot(); //Post-order for (scc_iterator sccIb = scc_begin(rootNode), E = scc_end(rootNode); sccIb != E; ++sccIb) { const std::vector &nextSCC = *sccIb; for (std::vector::const_iterator nsccI = nextSCC.begin(), E = nextSCC.end(); nsccI != E; ++nsccI) { Function *F = (*nsccI)->getFunction(); if(F && !F->isDeclaration()){ errs() << "\n#Function " << F->getName() << "\n"; for (inst_iterator I = inst_begin(*F), E = inst_end(*F); I != E; ++I) { Instruction *Inst = &*I; // Grab pointer to instruction reference if(isa(Inst)) analyzeCallInst(F,Inst); } } else{ if(debugQtmInst) errs() << "WARNING: Ignoring external node or dummy function.\n"; } } } return false; } // End runOnModule