Пример #1
0
Instructions Bytecode::parser(const Tokens& tokens) const {
    Tokens tokens_group;
    // Abstract syntax tree.
    Instructions ast;
    int funcs = 0, params = 0, specs = 0;
    for (int i = 0; i < tokens.size(); i++) {
        if (tokens[i].type == DELIMITER) {
            checkFunctions(tokens_group[0], funcs);
            checkById(tokens_group[0].function_id, params, specs);
            Instruction inst =
                makeInstruction(params, specs, tokens_group);
            ast.push_back(inst);
            funcs = 0, params = 0, specs = 0;
            tokens_group.clear();
        } else {
            if (tokens[i].type == FUNCTION) {
                funcs++;
            } else if (tokens[i].type == PARAMETER) {
                params++;
            } else {
                specs++;
            }
            tokens_group.push_back(tokens[i]);
        }
    }
    return ast;
}
Пример #2
0
void constructBlocks(Blocks &blocks, Instructions &instructions) {
	/* Create the first block containing the very first instruction in this script.
	 * Then follow the complete code flow from this instruction onwards. */

	assert(blocks.empty());
	if (instructions.empty())
		return;

	blocks.push_back(Block(instructions.front().address));
	constructBlocks(blocks, blocks.back(), instructions.front());
}
void ConstantInsertExtractElementIndex::fixOutOfRangeConstantIndices(
    BasicBlock &BB, const Instructions &Instrs) const {
  for (Instructions::const_iterator IB = Instrs.begin(), IE = Instrs.end();
       IB != IE; ++IB) {
    Instruction *I = *IB;
    const APInt &Idx =
        cast<ConstantInt>(getInsertExtractElementIdx(I))->getValue();
    APInt NumElements = APInt(Idx.getBitWidth(), vectorNumElements(I));
    APInt NewIdx = Idx.urem(NumElements);
    setInsertExtractElementIdx(I, ConstantInt::get(M->getContext(), NewIdx));
  }
}
void ConstantInsertExtractElementIndex::findNonConstantInsertExtractElements(
    const BasicBlock &BB, Instructions &OutOfRangeConstantIndices,
    Instructions &NonConstantVectorIndices) const {
  for (BasicBlock::const_iterator BBI = BB.begin(), BBE = BB.end(); BBI != BBE;
       ++BBI) {
    const Instruction *I = &*BBI;
    if (Value *Idx = getInsertExtractElementIdx(I)) {
      if (ConstantInt *CI = dyn_cast<ConstantInt>(Idx)) {
        if (!CI->getValue().ult(vectorNumElements(I)))
          OutOfRangeConstantIndices.push_back(const_cast<Instruction *>(I));
      } else
        NonConstantVectorIndices.push_back(const_cast<Instruction *>(I));
    }
  }
}
bool ConstantInsertExtractElementIndex::runOnBasicBlock(BasicBlock &BB) {
  bool Changed = false;
  if (!DL)
    DL = &getAnalysis<DataLayoutPass>().getDataLayout();
  Instructions OutOfRangeConstantIndices;
  Instructions NonConstantVectorIndices;

  findNonConstantInsertExtractElements(BB, OutOfRangeConstantIndices,
                                       NonConstantVectorIndices);
  if (!OutOfRangeConstantIndices.empty()) {
    Changed = true;
    fixOutOfRangeConstantIndices(BB, OutOfRangeConstantIndices);
  }
  if (!NonConstantVectorIndices.empty()) {
    Changed = true;
    fixNonConstantVectorIndices(BB, NonConstantVectorIndices);
  }
  return Changed;
}
Пример #6
0
void Bytecode::compile(const Instructions& instructions) {
    for (int i = 0; i < instructions.size(); i++) {
        int func_id = instructions[i].function.function_id;
        int p1 = instructions[i].p1.parameter;
        int p2 = instructions[i].p2.parameter;
        bool spec = instructions[i].spec.spec;
        PackedInstruction packed_inst(func_id, p1, p2, spec);
        bytecode_.push_back(packed_inst);
    }
}
Пример #7
0
ClobFile::ClobFile(std::string _path, Instructions _instructions, strings_t _data) {
    path = _path;
    instructions = _instructions;

    header = {0, _instructions.size(), _data.size()};

    for (auto _d : _data) {
        DataEntry_t entry;
        entry.string = _d;
        entry.length = entry.string.size();
        data.push_back(entry);
    }
}
void ConstantInsertExtractElementIndex::fixNonConstantVectorIndices(
    BasicBlock &BB, const Instructions &Instrs) const {
  for (Instructions::const_iterator IB = Instrs.begin(), IE = Instrs.end();
       IB != IE; ++IB) {
    Instruction *I = *IB;
    Value *Vec = I->getOperand(0);
    Value *Idx = getInsertExtractElementIdx(I);
    VectorType *VecTy = cast<VectorType>(Vec->getType());
    Type *ElemTy = VecTy->getElementType();
    unsigned ElemAlign = DL->getPrefTypeAlignment(ElemTy);
    unsigned VecAlign = std::max(ElemAlign, DL->getPrefTypeAlignment(VecTy));

    IRBuilder<> IRB(I);
    AllocaInst *Alloca = IRB.CreateAlloca(
        ElemTy, ConstantInt::get(Type::getInt32Ty(M->getContext()),
                                 vectorNumElements(I)));
    Alloca->setAlignment(VecAlign);
    Value *AllocaAsVec = IRB.CreateBitCast(Alloca, VecTy->getPointerTo());
    IRB.CreateAlignedStore(Vec, AllocaAsVec, Alloca->getAlignment());
    Value *GEP = IRB.CreateGEP(Alloca, Idx);

    Value *Res;
    switch (I->getOpcode()) {
    default:
      llvm_unreachable("expected InsertElement or ExtractElement");
    case Instruction::InsertElement:
      IRB.CreateAlignedStore(I->getOperand(1), GEP, ElemAlign);
      Res = IRB.CreateAlignedLoad(AllocaAsVec, Alloca->getAlignment());
      break;
    case Instruction::ExtractElement:
      Res = IRB.CreateAlignedLoad(GEP, ElemAlign);
      break;
    }

    I->replaceAllUsesWith(Res);
    I->eraseFromParent();
  }
}
void AArch64AddressTypePromotion::mergeSExts(ValueToInsts &ValToSExtendedUses,
                                             SetOfInstructions &ToRemove) {
  DominatorTree &DT = getAnalysis<DominatorTreeWrapperPass>().getDomTree();

  for (auto &Entry : ValToSExtendedUses) {
    Instructions &Insts = Entry.second;
    Instructions CurPts;
    for (Instruction *Inst : Insts) {
      if (ToRemove.count(Inst))
        continue;
      bool inserted = false;
      for (auto &Pt : CurPts) {
        if (DT.dominates(Inst, Pt)) {
          DEBUG(dbgs() << "Replace all uses of:\n" << *Pt << "\nwith:\n"
                       << *Inst << '\n');
          Pt->replaceAllUsesWith(Inst);
          ToRemove.insert(Pt);
          Pt = Inst;
          inserted = true;
          break;
        }
        if (!DT.dominates(Pt, Inst))
          // Give up if we need to merge in a common dominator as the
          // expermients show it is not profitable.
          continue;

        DEBUG(dbgs() << "Replace all uses of:\n" << *Inst << "\nwith:\n"
                     << *Pt << '\n');
        Inst->replaceAllUsesWith(Pt);
        ToRemove.insert(Inst);
        inserted = true;
        break;
      }
      if (!inserted)
        CurPts.push_back(Inst);
    }
  }
}
Пример #10
0
/**
  @brief opens instructions window after pushing button
  */
void MainWindow::help() {
    //open new window
    Instructions* instruct = new Instructions(this);
    instruct->show();
}
void AArch64AddressTypePromotion::analyzeSExtension(Instructions &SExtInsts) {
  DEBUG(dbgs() << "*** Analyze Sign Extensions ***\n");

  DenseMap<Value *, Instruction *> SeenChains;

  for (auto &BB : *Func) {
    for (auto &II : BB) {
      Instruction *SExt = &II;

      // Collect all sext operation per type.
      if (!isa<SExtInst>(SExt) || !shouldConsiderSExt(SExt))
        continue;

      DEBUG(dbgs() << "Found:\n" << (*SExt) << '\n');

      // Cases where we actually perform the optimization:
      // 1. SExt is used in a getelementptr with more than 2 operand =>
      //    likely we can merge some computation if they are done on 64 bits.
      // 2. The beginning of the SExt chain is SExt several time. =>
      //    code sharing is possible.

      bool insert = false;
      // #1.
      for (const User *U : SExt->users()) {
        const Instruction *Inst = dyn_cast<GetElementPtrInst>(U);
        if (Inst && Inst->getNumOperands() > 2) {
          DEBUG(dbgs() << "Interesting use in GetElementPtrInst\n" << *Inst
                       << '\n');
          insert = true;
          break;
        }
      }

      // #2.
      // Check the head of the chain.
      Instruction *Inst = SExt;
      Value *Last;
      do {
        int OpdIdx = 0;
        const BinaryOperator *BinOp = dyn_cast<BinaryOperator>(Inst);
        if (BinOp && isa<ConstantInt>(BinOp->getOperand(0)))
          OpdIdx = 1;
        Last = Inst->getOperand(OpdIdx);
        Inst = dyn_cast<Instruction>(Last);
      } while (Inst && canGetThrough(Inst) && shouldGetThrough(Inst));

      DEBUG(dbgs() << "Head of the chain:\n" << *Last << '\n');
      DenseMap<Value *, Instruction *>::iterator AlreadySeen =
          SeenChains.find(Last);
      if (insert || AlreadySeen != SeenChains.end()) {
        DEBUG(dbgs() << "Insert\n");
        SExtInsts.push_back(SExt);
        if (AlreadySeen != SeenChains.end() && AlreadySeen->second != nullptr) {
          DEBUG(dbgs() << "Insert chain member\n");
          SExtInsts.push_back(AlreadySeen->second);
          SeenChains[Last] = nullptr;
        }
      } else {
        DEBUG(dbgs() << "Record its chain membership\n");
        SeenChains[Last] = SExt;
      }
    }
  }
}
// Input:
// - SExtInsts contains all the sext instructions that are used directly in
//   GetElementPtrInst, i.e., access to memory.
// Algorithm:
// - For each sext operation in SExtInsts:
//   Let var be the operand of sext.
//   while it is profitable (see shouldGetThrough), legal, and safe
//   (see canGetThrough) to move sext through var's definition:
//   * promote the type of var's definition.
//   * fold var into sext uses.
//   * move sext above var's definition.
//   * update sext operand to use the operand of var that should be sign
//     extended (by construction there is only one).
//
//   E.g.,
//   a = ... i32 c, 3
//   b = sext i32 a to i64 <- is it legal/safe/profitable to get through 'a'
//   ...
//   = b
// => Yes, update the code
//   b = sext i32 c to i64
//   a = ... i64 b, 3
//   ...
//   = a
// Iterate on 'c'.
bool
AArch64AddressTypePromotion::propagateSignExtension(Instructions &SExtInsts) {
  DEBUG(dbgs() << "*** Propagate Sign Extension ***\n");

  bool LocalChange = false;
  SetOfInstructions ToRemove;
  ValueToInsts ValToSExtendedUses;
  while (!SExtInsts.empty()) {
    // Get through simple chain.
    Instruction *SExt = SExtInsts.pop_back_val();

    DEBUG(dbgs() << "Consider:\n" << *SExt << '\n');

    // If this SExt has already been merged continue.
    if (SExt->use_empty() && ToRemove.count(SExt)) {
      DEBUG(dbgs() << "No uses => marked as delete\n");
      continue;
    }

    // Now try to get through the chain of definitions.
    while (auto *Inst = dyn_cast<Instruction>(SExt->getOperand(0))) {
      DEBUG(dbgs() << "Try to get through:\n" << *Inst << '\n');
      if (!canGetThrough(Inst) || !shouldGetThrough(Inst)) {
        // We cannot get through something that is not an Instruction
        // or not safe to SExt.
        DEBUG(dbgs() << "Cannot get through\n");
        break;
      }

      LocalChange = true;
      // If this is a sign extend, it becomes useless.
      if (isa<SExtInst>(Inst) || isa<TruncInst>(Inst)) {
        DEBUG(dbgs() << "SExt or trunc, mark it as to remove\n");
        // We cannot use replaceAllUsesWith here because we may trigger some
        // assertion on the type as all involved sext operation may have not
        // been moved yet.
        while (!Inst->use_empty()) {
          Use &U = *Inst->use_begin();
          Instruction *User = dyn_cast<Instruction>(U.getUser());
          assert(User && "User of sext is not an Instruction!");
          User->setOperand(U.getOperandNo(), SExt);
        }
        ToRemove.insert(Inst);
        SExt->setOperand(0, Inst->getOperand(0));
        SExt->moveBefore(Inst);
        continue;
      }

      // Get through the Instruction:
      // 1. Update its type.
      // 2. Replace the uses of SExt by Inst.
      // 3. Sign extend each operand that needs to be sign extended.

      // Step #1.
      Inst->mutateType(SExt->getType());
      // Step #2.
      SExt->replaceAllUsesWith(Inst);
      // Step #3.
      Instruction *SExtForOpnd = SExt;

      DEBUG(dbgs() << "Propagate SExt to operands\n");
      for (int OpIdx = 0, EndOpIdx = Inst->getNumOperands(); OpIdx != EndOpIdx;
           ++OpIdx) {
        DEBUG(dbgs() << "Operand:\n" << *(Inst->getOperand(OpIdx)) << '\n');
        if (Inst->getOperand(OpIdx)->getType() == SExt->getType() ||
            !shouldSExtOperand(Inst, OpIdx)) {
          DEBUG(dbgs() << "No need to propagate\n");
          continue;
        }
        // Check if we can statically sign extend the operand.
        Value *Opnd = Inst->getOperand(OpIdx);
        if (const ConstantInt *Cst = dyn_cast<ConstantInt>(Opnd)) {
          DEBUG(dbgs() << "Statically sign extend\n");
          Inst->setOperand(OpIdx, ConstantInt::getSigned(SExt->getType(),
                                                         Cst->getSExtValue()));
          continue;
        }
        // UndefValue are typed, so we have to statically sign extend them.
        if (isa<UndefValue>(Opnd)) {
          DEBUG(dbgs() << "Statically sign extend\n");
          Inst->setOperand(OpIdx, UndefValue::get(SExt->getType()));
          continue;
        }

        // Otherwise we have to explicity sign extend it.
        assert(SExtForOpnd &&
               "Only one operand should have been sign extended");

        SExtForOpnd->setOperand(0, Opnd);

        DEBUG(dbgs() << "Move before:\n" << *Inst << "\nSign extend\n");
        // Move the sign extension before the insertion point.
        SExtForOpnd->moveBefore(Inst);
        Inst->setOperand(OpIdx, SExtForOpnd);
        // If more sext are required, new instructions will have to be created.
        SExtForOpnd = nullptr;
      }
      if (SExtForOpnd == SExt) {
        DEBUG(dbgs() << "Sign extension is useless now\n");
        ToRemove.insert(SExt);
        break;
      }
    }

    // If the use is already of the right type, connect its uses to its argument
    // and delete it.
    // This can happen for an Instruction all uses of which are sign extended.
    if (!ToRemove.count(SExt) &&
        SExt->getType() == SExt->getOperand(0)->getType()) {
      DEBUG(dbgs() << "Sign extension is useless, attach its use to "
                      "its argument\n");
      SExt->replaceAllUsesWith(SExt->getOperand(0));
      ToRemove.insert(SExt);
    } else
      ValToSExtendedUses[SExt->getOperand(0)].push_back(SExt);
  }

  if (EnableMerge)
    mergeSExts(ValToSExtendedUses, ToRemove);

  // Remove all instructions marked as ToRemove.
  for (Instruction *I: ToRemove)
    I->eraseFromParent();
  return LocalChange;
}
Пример #13
0
// Pre-Processamento:
// Remove os comentarios e linhas em branco
// E coloca o codigo numa estrutura do tipo CodeLines
// Tambem verifica os labels e equs e ifs
void readAndPreProcess (const char* fileName) {

    ifstream infile(fileName);
    string line;
    int textMemAddr = textStartAddress;
    int dataMemAddr = 0;
    int BSSMemAddr = 0;
    stringstream tempSS;
    CodeSection codeSection = NONE;

    // Le linha a linha
	for (int lineCount = 1; getline(infile, line); ++lineCount) {

        // Troca virgulas por espaco
        strReplace(line, ",", " ");

        // Ignora linhas em branco
        if (line.empty()) continue;

        // Pega palavra a palavra de acordo com os espacos
        istringstream iss(line);
        string tempStr;
        while (iss >> tempStr) {

            if ("SECTION" == tempStr) {

                string tempStr2;
                iss >> tempStr2;

                if ("TEXT" == tempStr2)
                    codeSection = TEXT;
                else if ("DATA" == tempStr2)
                    codeSection = DATA;

                codeLines[lineCount].push_back(tempStr);
                codeLines[lineCount].push_back(tempStr2);

                continue;

            }

            // Ignora comentarios
            if (";" == tempStr.substr(0,1)) break;

            // Desconsidera o caso (maiusculas/minusculas)
            transform(tempStr.begin(), tempStr.end(), tempStr.begin(), ::toupper);

            // Ve se eh um label / define
            if (":" == tempStr.substr(tempStr.length() - 1, 1)) {

                // Ve se ainda restam tokens na linha
                if (iss.rdbuf()->in_avail() != 0) {

                    // Remove o ':'
                    tempStr = tempStr.substr(0, tempStr.length() - 1);

                    string tempStr2;
                    iss >> tempStr2;

                    // Ve se o proximo token eh EQU
                    if ("EQU" == tempStr2) {

                        string tempStr3;
                        iss >> tempStr3;

                        // Se define já existe
                        if (defines.find(tempStr3) != defines.end()){
                            tempSS << lineCount;
                            errors.push("ERRO NA LINHA " + tempSS.str() + ": EQU ja declarado.");
                            tempSS.str("");
                        } else {
                            // Coloca o valor do EQU na tabela de defines
                            defines[tempStr] = tempStr3;
                        }

                    // Se nao eh so um label
                    // Com algo a mais na mesma linha
                    } else {

                        if ( (labels.find(tempStr) != labels.end()) ||
                             (dataLabels.find(tempStr) != dataLabels.end())  ){
                            tempSS << lineCount;
                            errors.push("ERRO NA LINHA " + tempSS.str() + ": Label ja declarado.");
                            tempSS.str("");
                        } else {
                            // Adiciona na tabela de labels
                            if(codeSection == TEXT){
                                labels[tempStr] = textMemAddr;
                            } else if (codeSection == DATA) {

                                dataLabels[tempStr] = dataMemAddr;
                                dataMemAddr += 4;
                            }
                        }
                        
                        // Adiciona endereco de memoria
                        if (instructions.find(tempStr2) != instructions.end())
                            textMemAddr += get<3>(instructions[tempStr2]);

                        // Adiciona os tokens ao vetor
                        codeLines[lineCount].push_back(tempStr+":");
                        codeLines[lineCount].push_back(tempStr2);

                    }

                // Se nao eh um label "sozinho"
                // Adiciona no vetor
                } else {
Пример #14
0
// Syntax of instruction
//
// mnemonic {op} '|' ( prefix )* opcode args
//
// mnemonic = Intel instruction lexium
// 
// op = sr          %es, ..., %gs
//      xb          %al, .., %bh
//      xd          %ax, .., %dil
//      xw          %eax, ..., %edi
//      xq          %rax, ..., %rdi
//      rb          %rNb
//      rd          %rNd
//      rw          %rNw
//      rq          %rN
//      st          %stN
//      mm          %mmN
//      xmm         %xmmN
//      ymm         %ymmN
//      zmm         %zmmN
//      cr          %crN
//      dr          %drN
//      k           %kN
//      addr.disp.rq,     10(%r10)
//      addr.disp.xq,     20(%rdx)
//      addr.disp.rq.rq,  30(%r10,%r11,2)
//      addr.disp.rq.xq,  40(%r10,%rdx,2)
//      addr.disp.xq.rq,  50(%rdx,%r11,2)
//      addr.disp.xq.xq,  60(%rdx,%rax,2)
//      addr.disp.rd,    70(%r10d)
//      addr.disp.xd,    80(%dx)
//      addr.disp.rd.rd, 90(%r10d,%r11d,2)
//      addr.disp.rd.xd, 10(%r10d,%dx,2)
//      addr.disp.xd.rd, 11(%dx,%r11d,2)
//      addr.disp.xd.xd, 12(%dx,%ax,2)
//      addr.disp.rw,    13(%r10w)
//      addr.disp.xw,    14(%edx)
//      addr.disp.rw.rw, 15(%r10w,%r11w,1)
//      addr.disp.rw.xw, 16(%r10w,%edx,2)
//      addr.disp.xw.rw, 17(%edx,%r11w,4)
//      addr.disp.xw.xw, 18(%edx,%eax,8)
//      addr.rq,    (%r10)
//      addr.xq,    (%rdx)
//      addr.rq.rq, (%r10,%r11,2)
//      addr.rq.xq, (%r10,%rdx,2)
//      addr.xq.rq, (%rdx,%r11,2)
//      addr.xq.xq, (%rdx,%rax,2)
//      addr.rd,    (%r10d)
//      addr.xd,    (%dx)
//      addr.rd.rd, (%r10d,%r11d,2)
//      addr.rd.xd, (%r10d,%dx,2)
//      addr.xd.rd, (%dx,%r11d,2)
//      addr.xd.xd, (%dx,%ax,2)
//      addr.rw,    (%r10w)
//      addr.xw,    (%edx)
//      addr.rw.rw, (%r10w,%r11w,1)
//      addr.rw.xw, (%r10w,%edx,2)
//      addr.xw.rw, (%edx,%r11w,4)
//      addr.xw.xw, (%edx,%eax,8)
//
//      imm8   Immediate value
//      imm32  Immediate value
//      disp   Memory addressing displayment as the exponent of power of 2
//
// prefix = rex:BRWX
//          vex2:R:vvvv:L:pp
//          vex3:RXB:mmmm:W:vvvv:L:pp
//			evex:RXB:R':mm:W:vvvv:pp:z:L':L:b:V':aaa
//			es
//			cs
//			ss
//			ds
//			os   
//			as   
//			rep  
//			ne   
//			lock 
//			bhnt 
//			bnht 
//
// opcode = one or more bytes 
// args = reg:<len>:<n> | imm:<len>:<n> | scale:<len>:<n>
//
bool loadDef( FILE * fh, Instructions & insts )
{
	const int BUF_SIZE = 256;

	char buff[BUF_SIZE];

	enum Pstate
	{
		start,
		nmemonicSeen,
		operandSeen,
		sepSeen,
		opcodeSeen,
		argsSeen,
	};

	static const char * opTypes[] =
	{
		"addr.disp32.rd",
		"addr.disp32.rd.rd",
		"addr.disp32.rd.rd.scale",
		"addr.disp32.rd.xd",
		"addr.disp32.rd.xd.scale",
		"addr.disp32.rq",
		"addr.disp32.rq.rq",
		"addr.disp32.rq.rq.scale",
		"addr.disp32.rq.xq",
		"addr.disp32.rq.xq.scale",
		"addr.disp32.xd",
		"addr.disp32.xd.rd",
		"addr.disp32.xd.rd.scale",
		"addr.disp32.xd.xd",
		"addr.disp32.xd.xd.scale",
		"addr.disp32.xq",
		"addr.disp32.xq.rq",
		"addr.disp32.xq.rq.scale",
		"addr.disp32.xq.xq",
		"addr.disp32.xq.xq.scale",

		"addr.disp8.rd",
		"addr.disp8.rd.rd",
		"addr.disp8.rd.rd.scale",
		"addr.disp8.rd.xd",
		"addr.disp8.rd.xd.scale",
		"addr.disp8.rq",
		"addr.disp8.rq.rq",
		"addr.disp8.rq.rq.scale",
		"addr.disp8.rq.xq",
		"addr.disp8.rq.xq.scale",
		"addr.disp8.xd",
		"addr.disp8.xd.rd",
		"addr.disp8.xd.rd.scale",
		"addr.disp8.xd.xd",
		"addr.disp8.xd.xd.scale",
		"addr.disp8.xq",
		"addr.disp8.xq.rq",
		"addr.disp8.xq.rq.scale",
		"addr.disp8.xq.xq",
		"addr.disp8.xq.xq.scale",

		"addr.rd",
		"addr.rd.rd",
		"addr.rd.rd.scale",
		"addr.rd.xd",
		"addr.rd.xd.scale",
		"addr.rq",
		"addr.rq.rq",
		"addr.rq.rq.scale",
		"addr.rq.xq",
		"addr.rq.xq.scale",
		"addr.xd",
		"addr.xd.rd",
		"addr.xd.rd.scale",
		"addr.xd.xd",
		"addr.xd.xd.scale",
		"addr.xq",
		"addr.xq.rq",
		"addr.xq.rq.scale",
		"addr.xq.xq",
		"addr.xq.xq.scale",

		"cr",
		"dr",
		"imm32",
		"imm8",
		"k",
		"mm",
		"rb",
		"rd",
		"rq",
		"rw",
		"sr",
		"st",
		"xb",
		"xb64",
		"xd",
		"xmm",
		"xq",
		"xw",
		"ymm",
		"zmm",
	};

	while( fgets( buff, BUF_SIZE, fh ) )
	{
		vector<string> tokens = split(buff);

		if( tokens.size() > 0 )
		{
			if( tokens.size() > 1 )
			{
				try
				{
					Pstate state = start;		
				
					Nmemonic nm;
	                vector<Otype> 	operands;
	                vector<unique_ptr<Prefix>> 	prefixes;
	                vector<uint8_t> opcode;
	                set<MC_Comp,Instruction::Comp>args;
					int offset = 0;
	
					for( auto & token:tokens)
					{
						switch(state)
						{
						case start:
							nm = Instruction::nmemonic(token);
							state = nmemonicSeen;
							break;
						case nmemonicSeen:
						{
							static auto end = opTypes + sizeof(opTypes)/sizeof(char *);
							auto p = equal_range( opTypes, end, token.c_str(), 
								[]( const char * a, const char * b){ return strcmp(a,b) < 0; } );
							if(p.first < end && token == opTypes[p.first-opTypes])
								operands.push_back(static_cast<Otype>(p.first-opTypes));
							else if( token == "|" )
								state = sepSeen;
							else
								throw "Invalid instruction: Expected operand or separator";
							break;
						}
						case sepSeen:
						{
							unique_ptr<Prefix> prefix;
							if( createPrefix( prefix, token, offset ))
								prefixes.push_back(move(prefix));
							else 
							{
								offset += 8;
								opcode.push_back(strtol( token.c_str(), nullptr, 16 ));
								state = opcodeSeen;
							}
							break;
						}
						case opcodeSeen:
							if(isArgOrConst(token))
							{
								args.insert(MC_Comp(token, offset ));
								state = argsSeen;
							}
							else if(isOpcodeByte(token))
							{
								opcode.push_back(strtol( token.c_str(), nullptr, 16 ));
								offset += 8;
							}
							else
								throw "Invalid instruction: Expected opcode or separator ";
							break;
						case argsSeen:
							if(isArgOrConst(token))
							{
								args.insert(MC_Comp(token, offset ));
							}
							else
								throw "Invalid instruction";
							break;
						}
					}
	
					if( opcode.size() == 0 )
						fprintf( stderr, "%s missing opcode. Ignored\n", Instruction::lexium(nm) );
					else
						insts.insert(
							Instruction(nm,move(operands),move(prefixes),move(opcode), move(args)));
				}
				catch( ... )
				{
					fprintf( stderr, "Failed to parse instruction on %s\n", buff );
					return false;
				}
			}
		}
	}

	return true;
}
Пример #15
0
/**
 * Compiles a brainfreeze program. It converts the program's
 * textual representation into a program containing only the
 * brainfreeze vm instructions.
 *
 * Additionally, it performs several compile time optimizations in order to
 * speed up execution time. These optimizations include pre-calculating
 * jump offsets and fusing sequential identical instructions.
 *
 * \return Returns true if the program was succesfully compiled, otherwise
 *         it will return false to indicate the presence of errors
 */
bool BFProgram::compile()
{
    Instructions temp;
    Instruction  last = Instruction( OP_EOF, 0 );
    std::stack<int> jumps;  // record positions for [

    //
    // Scan the code string. Replace each BF instruction 
    // with its symbolic equivilant.
    //
    int icount = 0;
    for( std::string::iterator itr  = m_codestr.begin();
                               itr != m_codestr.end();
                             ++itr )
    {
        if( BF::isInstruction( *itr ) )
        {
            // Convert the character into an instruction
            Instruction instr = BF::convert( *itr );

            //
            // Is this a jump instruction?
            //
            if ( instr.opcode() == OP_JMP_FWD )
            {
                // This is a forward jump. Record its position
                jumps.push(icount);
            }
            else if ( instr.opcode() == OP_JMP_BAC )
            {
                // This is a backward jump. Pop the corresponding
                // forward jump marker off the stack, and update both
                // of the instructions with the location of their 
                // corresponding targets.
                int backpos = jumps.top(); jumps.pop();
                int dist    = icount - backpos;

                assert( dist > 0 );

                // Update the [ character
                temp[backpos].setParam( dist );

                // Update the ] (current) character
                instr.setParam( dist );
            }

            //
            // Was the last character a repeat of +, -, >, <
            //
            if ( ( instr.opcode() == last.opcode() ) &&
                 ( instr.opcode() == OP_PTR_INC || 
                   instr.opcode() == OP_PTR_DEC ||
                   instr.opcode() == OP_MEM_INC ||
                   instr.opcode() == OP_MEM_DEC ) )
            {
                // Get the last character, and update its occurrence
                temp[icount-1].setParam( temp[icount-1].param() + 1 );
            }
            else
            {
                // Add the instruction to the instruction stream
                temp.push_back( instr );

                // Remember last instruction
                last = instr;

                // Increment instruction counter
                icount += 1;
            }

            // Remember the last instruction
            last = instr;
        }
    }

    // Verify the jump stack is empty. If not, then there is a
    // mismatched jump somewhere!
    if (! jumps.empty() )
    {
        raiseError( "Mismatched jump detected when compiling" );
        return false;
    }

    // Insert end of program instruction
    temp.push_back( Instruction( OP_EOF, 0 ) );
    
    // Save it to m_instructions
    m_instructions.swap( temp );
    m_ip = m_instructions.begin();

    return true;
}
Пример #16
0
void LowerEmAsyncify::transformAsyncFunction(Function &F, Instructions const& AsyncCalls) {
  assert(!AsyncCalls.empty());

  // Pass 0
  // collect all the return instructions from the original function
  // will use later
  std::vector<ReturnInst*> OrigReturns;
  for (inst_iterator I = inst_begin(&F), E = inst_end(&F); I != E; ++I) {
    if (ReturnInst *RI = dyn_cast<ReturnInst>(&*I)) {
      OrigReturns.push_back(RI);
    }
  }

  // Pass 1
  // Scan each async call and make the basic structure:
  // All these will be cloned into the callback functions
  // - allocate the async context before calling an async function
  // - check async right after calling an async function, save context & return if async, continue if not
  // - retrieve the async return value and free the async context if the called function turns out to be sync
  std::vector<AsyncCallEntry> AsyncCallEntries;
  AsyncCallEntries.reserve(AsyncCalls.size());
  for (Instructions::const_iterator I = AsyncCalls.begin(), E = AsyncCalls.end(); I != E; ++I) {
    // prepare blocks
    Instruction *CurAsyncCall = *I;

    // The block containing the async call
    BasicBlock *CurBlock = CurAsyncCall->getParent();
    // The block should run after the async call
    BasicBlock *AfterCallBlock = SplitBlock(CurBlock, CurAsyncCall->getNextNode());
    // The block where we store the context and return
    BasicBlock *SaveAsyncCtxBlock = BasicBlock::Create(TheModule->getContext(), "SaveAsyncCtx", &F, AfterCallBlock);
    // return a dummy value at the end, to make the block valid
    new UnreachableInst(TheModule->getContext(), SaveAsyncCtxBlock);

    // allocate the context before making the call
    // we don't know the size yet, will fix it later
    // we cannot insert the instruction later because,
    // we need to make sure that all the instructions and blocks are fixed before we can generate DT and find context variables
    // In CallHandler.h `sp` will be put as the second parameter
    // such that we can take a note of the original sp 
    CallInst *AllocAsyncCtxInst = CallInst::Create(AllocAsyncCtxFunction, Constant::getNullValue(I32), "AsyncCtx", CurAsyncCall);

    // Right after the call
    // check async and return if so
    // TODO: we can define truly async functions and partial async functions
    {
      // remove old terminator, which came from SplitBlock
      CurBlock->getTerminator()->eraseFromParent();
      // go to SaveAsyncCtxBlock if the previous call is async
      // otherwise just continue to AfterCallBlock
      CallInst *CheckAsync = CallInst::Create(CheckAsyncFunction, "IsAsync", CurBlock);
      BranchInst::Create(SaveAsyncCtxBlock, AfterCallBlock, CheckAsync, CurBlock);
    }

    // take a note of this async call
    AsyncCallEntry CurAsyncCallEntry;
    CurAsyncCallEntry.AsyncCallInst = CurAsyncCall;
    CurAsyncCallEntry.AfterCallBlock = AfterCallBlock;
    CurAsyncCallEntry.AllocAsyncCtxInst = AllocAsyncCtxInst;
    CurAsyncCallEntry.SaveAsyncCtxBlock = SaveAsyncCtxBlock;
    // create an empty function for the callback, which will be constructed later
    CurAsyncCallEntry.CallbackFunc = Function::Create(CallbackFunctionType, F.getLinkage(), F.getName() + "__async_cb", TheModule);
    AsyncCallEntries.push_back(CurAsyncCallEntry);
  }


  // Pass 2
  // analyze the context variables and construct SaveAsyncCtxBlock for each async call
  // also calculate the size of the context and allocate the async context accordingly
  for (std::vector<AsyncCallEntry>::iterator EI = AsyncCallEntries.begin(), EE = AsyncCallEntries.end();  EI != EE; ++EI) {
    AsyncCallEntry & CurEntry = *EI;

    // Collect everything to be saved
    FindContextVariables(CurEntry);

    // Pack the variables as a struct
    {
      // TODO: sort them from large memeber to small ones, in order to make the struct compact even when aligned
      SmallVector<Type*, 8> Types;
      Types.push_back(CallbackFunctionType->getPointerTo());
      for (Values::iterator VI = CurEntry.ContextVariables.begin(), VE = CurEntry.ContextVariables.end(); VI != VE; ++VI) {
        Types.push_back((*VI)->getType());
      }
      CurEntry.ContextStructType = StructType::get(TheModule->getContext(), Types);
    }

    // fix the size of allocation
    CurEntry.AllocAsyncCtxInst->setOperand(0, 
        ConstantInt::get(I32, DL->getTypeStoreSize(CurEntry.ContextStructType)));

    // construct SaveAsyncCtxBlock
    {
      // fill in SaveAsyncCtxBlock
      // temporarily remove the terminator for convenience
      CurEntry.SaveAsyncCtxBlock->getTerminator()->eraseFromParent();
      assert(CurEntry.SaveAsyncCtxBlock->empty());

      Type *AsyncCtxAddrTy = CurEntry.ContextStructType->getPointerTo();
      BitCastInst *AsyncCtxAddr = new BitCastInst(CurEntry.AllocAsyncCtxInst, AsyncCtxAddrTy, "AsyncCtxAddr", CurEntry.SaveAsyncCtxBlock);
      SmallVector<Value*, 2> Indices;
      // store the callback
      {
        Indices.push_back(ConstantInt::get(I32, 0));
        Indices.push_back(ConstantInt::get(I32, 0));
        GetElementPtrInst *AsyncVarAddr = GetElementPtrInst::Create(AsyncCtxAddrTy, AsyncCtxAddr, Indices, "", CurEntry.SaveAsyncCtxBlock);
        new StoreInst(CurEntry.CallbackFunc, AsyncVarAddr, CurEntry.SaveAsyncCtxBlock);
      }
      // store the context variables
      for (size_t i = 0; i < CurEntry.ContextVariables.size(); ++i) {
        Indices.clear();
        Indices.push_back(ConstantInt::get(I32, 0));
        Indices.push_back(ConstantInt::get(I32, i + 1)); // the 0th element is the callback function
        GetElementPtrInst *AsyncVarAddr = GetElementPtrInst::Create(AsyncCtxAddrTy, AsyncCtxAddr, Indices, "", CurEntry.SaveAsyncCtxBlock);
        new StoreInst(CurEntry.ContextVariables[i], AsyncVarAddr, CurEntry.SaveAsyncCtxBlock);
      }
      // to exit the block, we want to return without unwinding the stack frame
      CallInst::Create(DoNotUnwindFunction, "", CurEntry.SaveAsyncCtxBlock);
      ReturnInst::Create(TheModule->getContext(), 
          (F.getReturnType()->isVoidTy() ? 0 : Constant::getNullValue(F.getReturnType())),
          CurEntry.SaveAsyncCtxBlock);
    }
  }

  // Pass 3
  // now all the SaveAsyncCtxBlock's have been constructed
  // we can clone F and construct callback functions 
  // we could not construct the callbacks in Pass 2 because we need _all_ those SaveAsyncCtxBlock's appear in _each_ callback
  for (std::vector<AsyncCallEntry>::iterator EI = AsyncCallEntries.begin(), EE = AsyncCallEntries.end();  EI != EE; ++EI) {
    AsyncCallEntry & CurEntry = *EI;

    Function *CurCallbackFunc = CurEntry.CallbackFunc;
    ValueToValueMapTy VMap;

    // Add the entry block
    // load variables from the context
    // also update VMap for CloneFunction
    BasicBlock *EntryBlock = BasicBlock::Create(TheModule->getContext(), "AsyncCallbackEntry", CurCallbackFunc);
    std::vector<LoadInst *> LoadedAsyncVars;
    {
      Type *AsyncCtxAddrTy = CurEntry.ContextStructType->getPointerTo();
      BitCastInst *AsyncCtxAddr = new BitCastInst(CurCallbackFunc->arg_begin(), AsyncCtxAddrTy, "AsyncCtx", EntryBlock);
      SmallVector<Value*, 2> Indices;
      for (size_t i = 0; i < CurEntry.ContextVariables.size(); ++i) {
        Indices.clear();
        Indices.push_back(ConstantInt::get(I32, 0));
        Indices.push_back(ConstantInt::get(I32, i + 1)); // the 0th element of AsyncCtx is the callback function
        GetElementPtrInst *AsyncVarAddr = GetElementPtrInst::Create(AsyncCtxAddrTy, AsyncCtxAddr, Indices, "", EntryBlock);
        LoadedAsyncVars.push_back(new LoadInst(AsyncVarAddr, "", EntryBlock));
        // we want the argument to be replaced by the loaded value
        if (isa<Argument>(CurEntry.ContextVariables[i]))
          VMap[CurEntry.ContextVariables[i]] = LoadedAsyncVars.back();
      }
    }

    // we don't need any argument, just leave dummy entries there to cheat CloneFunctionInto
    for (Function::const_arg_iterator AI = F.arg_begin(), AE = F.arg_end(); AI != AE; ++AI) {
      if (VMap.count(AI) == 0)
        VMap[AI] = Constant::getNullValue(AI->getType());
    }

    // Clone the function
    {
      SmallVector<ReturnInst*, 8> Returns;
      CloneFunctionInto(CurCallbackFunc, &F, VMap, false, Returns);
      
      // return type of the callback functions is always void
      // need to fix the return type
      if (!F.getReturnType()->isVoidTy()) {
        // for those return instructions that are from the original function
        // it means we are 'truly' leaving this function
        // need to store the return value right before ruturn
        for (size_t i = 0; i < OrigReturns.size(); ++i) {
          ReturnInst *RI = cast<ReturnInst>(VMap[OrigReturns[i]]);
          // Need to store the return value into the global area
          CallInst *RawRetValAddr = CallInst::Create(GetAsyncReturnValueAddrFunction, "", RI);
          BitCastInst *RetValAddr = new BitCastInst(RawRetValAddr, F.getReturnType()->getPointerTo(), "AsyncRetValAddr", RI);
          new StoreInst(RI->getOperand(0), RetValAddr, RI);
        }
        // we want to unwind the stack back to where it was before the original function as called
        // but we don't actually need to do this here
        // at this point it must be true that no callback is pended
        // so the scheduler will correct the stack pointer and pop the frame
        // here we just fix the return type
        for (size_t i = 0; i < Returns.size(); ++i) {
          ReplaceInstWithInst(Returns[i], ReturnInst::Create(TheModule->getContext()));
        }
      }
    }

    // the callback function does not have any return value
    // so clear all the attributes for return
    {
      AttributeSet Attrs = CurCallbackFunc->getAttributes();
      CurCallbackFunc->setAttributes(
        Attrs.removeAttributes(TheModule->getContext(), AttributeSet::ReturnIndex, Attrs.getRetAttributes())
      );
    }

    // in the callback function, we never allocate a new async frame
    // instead we reuse the existing one
    for (std::vector<AsyncCallEntry>::iterator EI = AsyncCallEntries.begin(), EE = AsyncCallEntries.end();  EI != EE; ++EI) {
      Instruction *I = cast<Instruction>(VMap[EI->AllocAsyncCtxInst]);
      ReplaceInstWithInst(I, CallInst::Create(ReallocAsyncCtxFunction, I->getOperand(0), "ReallocAsyncCtx"));
    }

    // mapped entry point & async call
    BasicBlock *ResumeBlock = cast<BasicBlock>(VMap[CurEntry.AfterCallBlock]);
    Instruction *MappedAsyncCall = cast<Instruction>(VMap[CurEntry.AsyncCallInst]);
   
    // To save space, for each async call in the callback function, we just ignore the sync case, and leave it to the scheduler
    // TODO need an option for this
    {
      for (std::vector<AsyncCallEntry>::iterator EI = AsyncCallEntries.begin(), EE = AsyncCallEntries.end();  EI != EE; ++EI) {
        AsyncCallEntry & CurEntry = *EI;
        Instruction *MappedAsyncCallInst = cast<Instruction>(VMap[CurEntry.AsyncCallInst]);
        BasicBlock *MappedAsyncCallBlock = MappedAsyncCallInst->getParent();
        BasicBlock *MappedAfterCallBlock = cast<BasicBlock>(VMap[CurEntry.AfterCallBlock]);

        // for the sync case of the call, go to NewBlock (instead of MappedAfterCallBlock)
        BasicBlock *NewBlock = BasicBlock::Create(TheModule->getContext(), "", CurCallbackFunc, MappedAfterCallBlock);
        MappedAsyncCallBlock->getTerminator()->setSuccessor(1, NewBlock);
        // store the return value
        if (!MappedAsyncCallInst->use_empty()) {
          CallInst *RawRetValAddr = CallInst::Create(GetAsyncReturnValueAddrFunction, "", NewBlock);
          BitCastInst *RetValAddr = new BitCastInst(RawRetValAddr, MappedAsyncCallInst->getType()->getPointerTo(), "AsyncRetValAddr", NewBlock);
          new StoreInst(MappedAsyncCallInst, RetValAddr, NewBlock);
        }
        // tell the scheduler that we want to keep the current async stack frame
        CallInst::Create(DoNotUnwindAsyncFunction, "", NewBlock);
        // finally we go to the SaveAsyncCtxBlock, to register the callbac, save the local variables and leave
        BasicBlock *MappedSaveAsyncCtxBlock = cast<BasicBlock>(VMap[CurEntry.SaveAsyncCtxBlock]);
        BranchInst::Create(MappedSaveAsyncCtxBlock, NewBlock);
      }
    }

    std::vector<AllocaInst*> ToPromote;
    // applying loaded variables in the entry block
    {
      BasicBlockSet ReachableBlocks = FindReachableBlocksFrom(ResumeBlock);
      for (size_t i = 0; i < CurEntry.ContextVariables.size(); ++i) {
        Value *OrigVar = CurEntry.ContextVariables[i];
        if (isa<Argument>(OrigVar)) continue; // already processed
        Value *CurVar = VMap[OrigVar];
        assert(CurVar != MappedAsyncCall);
        if (Instruction *Inst = dyn_cast<Instruction>(CurVar)) {
          if (ReachableBlocks.count(Inst->getParent())) {
            // Inst could be either defined or loaded from the async context
            // Do the dirty works in memory
            // TODO: might need to check the safety first
            // TODO: can we create phi directly?
            AllocaInst *Addr = DemoteRegToStack(*Inst, false);
            new StoreInst(LoadedAsyncVars[i], Addr, EntryBlock);
            ToPromote.push_back(Addr);
          } else {
            // The parent block is not reachable, which means there is no confliction
            // it's safe to replace Inst with the loaded value
            assert(Inst != LoadedAsyncVars[i]); // this should only happen when OrigVar is an Argument
            Inst->replaceAllUsesWith(LoadedAsyncVars[i]); 
          }
        }
      }
    }

    // resolve the return value of the previous async function
    // it could be the value just loaded from the global area
    // or directly returned by the function (in its sync case)
    if (!CurEntry.AsyncCallInst->use_empty()) {
      // load the async return value
      CallInst *RawRetValAddr = CallInst::Create(GetAsyncReturnValueAddrFunction, "", EntryBlock);
      BitCastInst *RetValAddr = new BitCastInst(RawRetValAddr, MappedAsyncCall->getType()->getPointerTo(), "AsyncRetValAddr", EntryBlock);
      LoadInst *RetVal = new LoadInst(RetValAddr, "AsyncRetVal", EntryBlock);

      AllocaInst *Addr = DemoteRegToStack(*MappedAsyncCall, false);
      new StoreInst(RetVal, Addr, EntryBlock);
      ToPromote.push_back(Addr);
    }

    // TODO remove unreachable blocks before creating phi
   
    // We go right to ResumeBlock from the EntryBlock
    BranchInst::Create(ResumeBlock, EntryBlock);
   
    /*
     * Creating phi's
     * Normal stack frames and async stack frames are interleaving with each other.
     * In a callback function, if we call an async function, we might need to realloc the async ctx.
     * at this point we don't want anything stored after the ctx, 
     * such that we can free and extend the ctx by simply update STACKTOP.
     * Therefore we don't want any alloca's in callback functions.
     *
     */
    if (!ToPromote.empty()) {
      DominatorTreeWrapperPass DTW;
      DTW.runOnFunction(*CurCallbackFunc);
      PromoteMemToReg(ToPromote, DTW.getDomTree());
    }

    removeUnreachableBlocks(*CurCallbackFunc);
  }

  // Pass 4
  // Here are modifications to the original function, which we won't want to be cloned into the callback functions
  for (std::vector<AsyncCallEntry>::iterator EI = AsyncCallEntries.begin(), EE = AsyncCallEntries.end();  EI != EE; ++EI) {
    AsyncCallEntry & CurEntry = *EI;
    // remove the frame if no async functinon has been called
    CallInst::Create(FreeAsyncCtxFunction, CurEntry.AllocAsyncCtxInst, "", CurEntry.AfterCallBlock->getFirstNonPHI());
  }
}
Пример #17
0
void linkInstructionBranches(Instructions &instructions) {
	/* Go through all instructions and link them according to the flow graph.
	 *
	 * In specifics, link each instruction's follower, the instruction that
	 * naturally follows if no branches are taken. Also fill in the branches
	 * array, which contains all branches an instruction can take. This
	 * directly creates an address type for each instruction: does it start
	 * a subroutine, is it a jump destination, is it a tail of a jump or none
	 * of these?
	 */

	for (Instructions::iterator i = instructions.begin(); i != instructions.end(); ++i) {
		// If this is an instruction that has a natural follower, link it
		if ((i->opcode != kOpcodeJMP) && (i->opcode != kOpcodeRETN)) {
			Instructions::iterator follower = i + 1;

			i->follower = (follower != instructions.end()) ? &*follower : 0;

			if (follower != instructions.end())
				follower->predecessors.push_back(&*i);
		}

		// Link destinations of unconditional branches
		if ((i->opcode == kOpcodeJMP) || (i->opcode == kOpcodeJSR) || (i->opcode == kOpcodeSTORESTATE)) {
			assert(((i->opcode == kOpcodeSTORESTATE) && (i->argCount == 3)) || (i->argCount == 1));

			Instruction *branch = findInstruction(instructions, i->address + i->args[0]);
			if (!branch)
				throw Common::Exception("Can't find destination of unconditional branch");

			i->branches.push_back(branch);

			if      (i->opcode == kOpcodeJSR)
				setAddressType(branch, kAddressTypeSubRoutine);
			else if (i->opcode == kOpcodeSTORESTATE)
				setAddressType(branch, kAddressTypeStoreState);
			else {
				setAddressType(branch, kAddressTypeJumpLabel);
				branch->predecessors.push_back(&*i);
			}

			setAddressType(const_cast<Instruction *>(i->follower), kAddressTypeTail);
		}

		// Link destinations of conditional branches
		if ((i->opcode == kOpcodeJZ) || (i->opcode == kOpcodeJNZ)) {
			assert(i->argCount == 1);

			if (!i->follower)
				throw Common::Exception("Conditional branch has no false destination");

			Instruction *branch = findInstruction(instructions, i->address + i->args[0]);
			if (!branch)
				throw Common::Exception("Can't find destination of conditional branch");

			setAddressType(branch, kAddressTypeJumpLabel);

			setAddressType(const_cast<Instruction *>(i->follower), kAddressTypeTail);

			i->branches.push_back(branch);      // True branch
			i->branches.push_back(i->follower); // False branch

			branch->predecessors.push_back(&*i);
		}
	}
}