bool X86MachineInstructionRaiser::raiseCallMachineInstr()

in X86/X86MachineInstructionRaiser.cpp [4619:5062]


bool X86MachineInstructionRaiser::raiseCallMachineInstr(
    const MachineInstr &MI) {
  unsigned int Opcode = MI.getOpcode();

  // Get the BasicBlock corresponding to MachineBasicBlock of MI.
  // Raised instruction is added to this BasicBlock.
  BasicBlock *RaisedBB = getRaisedBasicBlock(MI.getParent());

  bool Success = false;
  switch (Opcode) {
    // case X86::CALLpcrel16   :
    // case X86::CALLpcrel32   :
  case X86::CALL64pcrel32:
  case X86::JMP_1:
  case X86::JMP_4: {
    Function *CalledFunc = getCalledFunction(MI);
    LLVMContext &Ctx(MF.getFunction().getContext());

    assert(CalledFunc != nullptr && "Failed to detect call target");
    std::vector<Value *> CallInstFuncArgs;
    unsigned NumGPArgs = CalledFunc->arg_size();
    Argument *CalledFuncArgs = CalledFunc->arg_begin();

    // check number of floating point args
    unsigned NumSSEArgs = 0;
    for (unsigned i = 0; i < NumGPArgs; ++i) {
      if (CalledFunc->getArg(i)->getType()->isFloatingPointTy()) {
        ++NumSSEArgs;
      }
    }
    // NumGPArgs refers to just general purpose registers
    NumGPArgs -= NumSSEArgs;

    if (CalledFunc->isVarArg()) {
      // Discover argument registers that are live just before the CallMI.
      // Liveness of the blocks is already computed in
      // getRaisedFunctionPrototype(). So no need to run it again since no
      // MBB would be modified.
      // MachineBasicBlock::const_reverse_iterator CallInstIter(MI);
      // Find the highest argument register that is defined in the block
      // before the CallMI. NOTE : We assume that all arguments are setup
      // prior to the call. This argument setup manifests as defines in the
      // block or a combination of argument registers that are live-in and
      // defines in the block. Additionally, if the block has more than one
      // calls, it is assumed that call setup for all calls other than the
      // first is done entirely in the block after the preceding call. In
      // such a situation, there is no need to look for argument registers
      // in the live-ins of the block.

      // Bit mask to keep track of argument register positions already
      // discovered.
      uint8_t PositionMask = 0;

      const MachineBasicBlock *CurMBB = MI.getParent();
      // If an argument register does not have a definition in a block that
      // has a call instruction between block entry and MI, there is no need
      // (and is not correct) to look for a reaching definition in its
      // predecessors.
      bool HasCallInst = false;
      unsigned int ArgNo = 1;
      // Find if CurMBB has call between block entry and MI

      for (auto ArgReg : GPR64ArgRegs64Bit) {
        if (getPhysRegDefiningInstInBlock(ArgReg, &MI, CurMBB, MCID::Call,
                                          HasCallInst) != nullptr)
          PositionMask |= (1 << ArgNo);
        else if (!HasCallInst) {
          // Look to see if the argument register has a reaching definition in
          // the predecessors of CurMBB.
          unsigned int ReachDefPredEdgeCount = 0;

          for (auto P : CurMBB->predecessors()) {
            SmallVector<MachineBasicBlock *, 8> WorkList;
            // No blocks visited in this walk up the predecessor P
            BitVector BlockVisited(MF.getNumBlockIDs(), false);

            // CurMBB has already been visited. Mark it so.
            BlockVisited.set(CurMBB->getNumber());
            // Start at predecessor P
            WorkList.push_back(P);

            while (!WorkList.empty()) {
              MachineBasicBlock *PredMBB = WorkList.pop_back_val();
              if (!BlockVisited[PredMBB->getNumber()]) {
                // Mark block as visited
                BlockVisited.set(PredMBB->getNumber());
                // Need to consider definitions after any call instructions in
                // the block. This is the reason we can not use
                // getReachingDefs() which does not consider the position
                // where the register is defined.
                bool Ignored;
                if (getPhysRegDefiningInstInBlock(ArgReg, nullptr, PredMBB,
                                                  MCID::Call,
                                                  Ignored) != nullptr)
                  ReachDefPredEdgeCount++;
                else {
                  // Reach info not found, continue walking the predecessors
                  // of CurBB.
                  for (auto P : PredMBB->predecessors()) {
                    // push_back the block which was not visited.
                    if (!BlockVisited[P->getNumber()])
                      WorkList.push_back(P);
                  }
                }
              }
            }
          }
          // If there is a reaching def on all predecessor edges then consider
          // it as an argument used by the variadic function.
          if ((ReachDefPredEdgeCount > (unsigned)0) &&
              (ReachDefPredEdgeCount == CurMBB->pred_size()))
            PositionMask |= (1 << ArgNo);
        }
        ArgNo++;
      }

      // Find the number of arguments
      // NOTE: Handling register arguments - 6 in number. Need to handle
      // arguments passed on stack make sure bit 8 and bit 0 are not set
      assert(!(PositionMask & 1) && !(PositionMask & (1 << 7)) &&
             "Invalid number of arguments discovered");
      uint8_t ShftPositionMask = PositionMask >> 1;
      uint8_t NumGPArgsDiscovered = 0;
      // Consider only consecutive argument registers.
      while (ShftPositionMask & 1) {
        ShftPositionMask = ShftPositionMask >> 1;
        NumGPArgsDiscovered++;
      }
      // If number of arguments discovered is greater than CalledFunc
      // arguments use that as the number of arguments of the called
      // function.
      if (NumGPArgsDiscovered > NumGPArgs) {
        NumGPArgs = NumGPArgsDiscovered;
      }

      uint8_t NumSSEArgsDiscovered = 0;
      // Get the number of vector registers used
      // When using the x86_64 System V ABI, RAX holds the number of vector
      // registers used
      bool Ignored;
      auto Instr = getPhysRegDefiningInstInBlock(X86::AL, &MI, CurMBB,
                                                 MCID::Call, Ignored);
      if (Instr != nullptr && Instr->getNumOperands() > 0) {
        // With the System V X86_64 ABI the compiler generates a instruction
        // like mov al, 1 with the number of vector arguments for the varargs
        // call
        const MachineOperand &SrcOp = Instr->getOperand(1);
        if (SrcOp.isImm()) {
          NumSSEArgsDiscovered = (uint8_t)SrcOp.getImm();
        }
      }
      // If number of vector args discovered is greater than CalledFunc
      // arguments, but still in the range of allowed number of vector
      // argument registers, use that as the number of vector args
      if (NumSSEArgsDiscovered > NumSSEArgs &&
          NumGPArgsDiscovered <= SSEArgRegs64Bit.size()) {
        NumSSEArgs = NumSSEArgsDiscovered;
      }
    }
    // Construct the argument list with values to be used to construct a new
    // CallInst. These values are those of the physical registers as defined
    // in C calling convention (the calling convention currently supported).
    for (unsigned i = 0; i < NumGPArgs + NumSSEArgs; i++) {
      // First check all GP registers, then FP registers
      MCPhysReg ArgReg =
          i < NumGPArgs ? GPR64ArgRegs64Bit[i] : SSEArgRegs64Bit[i - NumGPArgs];
      // Get the values of argument registers
      // Do not match types since we are explicitly using 64-bit GPR array.
      // Any necessary casting will be done later in this function.
      Value *ArgVal = getRegOrArgValue(ArgReg, MI.getParent()->getNumber());
      // This condition will not be true for varargs of a variadic function.
      // In that case just add the value.
      if (i < CalledFunc->arg_size()) {
        // If the ConstantInt value is being treated as a pointer (i.e., is
        // an address, try to construct the associated global read-only data
        // value.
        Argument &FuncArg = CalledFuncArgs[i];
        if (ArgVal == nullptr) {
          // Most likely the argument register corresponds to an argument value
          // that is not used in the function body. Just initialize it to 0.
          if (FuncArg.getType()->isIntOrPtrTy()) {
            ArgVal =
                ConstantInt::get(FuncArg.getType(), 0, false /* isSigned */);
          } else if (FuncArg.getType()->isFloatingPointTy()) {
            ArgVal = ConstantFP::get(FuncArg.getType(), 0.0);
          } else {
            FuncArg.getType()->dump();
            llvm_unreachable("Unsupported argument type");
          }
        } else if (isa<ConstantInt>(ArgVal)) {
          ConstantInt *Address = dyn_cast<ConstantInt>(ArgVal);
          if (!Address->isNegative()) {
            Value *RefVal = getOrCreateGlobalRODataValueAtOffset(
                Address->getSExtValue(), RaisedBB);
            if (RefVal != nullptr) {
              assert(RefVal->getType()->isPointerTy() &&
                     "Non-pointer type of global value abstracted from "
                     "address");
              ArgVal = RefVal;
            }
          }
        }
        if (FuncArg.getType()->isFloatingPointTy() ||
            FuncArg.getType()->isVectorTy()) {
          ArgVal = getRaisedValues()->reinterpretSSERegValue(
              ArgVal, FuncArg.getType(), RaisedBB);
        } else {
          ArgVal =
              getRaisedValues()->castValue(ArgVal, FuncArg.getType(), RaisedBB);
        }
      } else {
        // for varadic arguments, reinterpret vectors as doubles
        if (ArgVal->getType()->isVectorTy()) {
          ArgVal = getRaisedValues()->reinterpretSSERegValue(
              ArgVal, Type::getDoubleTy(Ctx), RaisedBB);
        }
      }
      assert(ArgVal != nullptr && "Unexpected null argument value");
      CallInstFuncArgs.push_back(ArgVal);
    }

    // Construct call inst.
    Instruction *callInst =
        CallInst::Create(CalledFunc, ArrayRef<Value *>(CallInstFuncArgs));

    // If this is a branch being turned to a tail call set the flag
    // accordingly.
    if (MI.isBranch())
      dyn_cast<CallInst>(callInst)->setTailCall(true);

    RaisedBB->getInstList().push_back(callInst);
    // A function call with a non-void return will modify
    // RAX (or its sub-register).
    Type *RetType = CalledFunc->getReturnType();
    if (!RetType->isVoidTy()) {
      unsigned int RetReg = X86::NoRegister;
      if (RetType->isPointerTy()) {
        // Cast pointer return type to 64-bit type
        Type *CastTy = Type::getInt64Ty(Ctx);
        Instruction *castInst = CastInst::Create(
            CastInst::getCastOpcode(callInst, false, CastTy, false), callInst,
            CastTy, "", RaisedBB);
        callInst = castInst;
        RetReg = X86::RAX;
      } else if (RetType->isIntegerTy()) {
        switch (RetType->getScalarSizeInBits()) {
        case 64:
          RetReg = X86::RAX;
          break;
        case 32:
          RetReg = X86::EAX;
          break;
        case 16:
          RetReg = X86::AX;
          break;
        case 8:
          RetReg = X86::AL;
          break;
        default:
          assert(false && "Unhandled return value size");
        }
      } else if (RetType->isFloatingPointTy() || RetType->isVectorTy()) {
        switch (RetType->getPrimitiveSizeInBits()) {
        case 128:
        case 64:
        case 32:
          RetReg = X86::XMM0;
          break;
        default:
          llvm_unreachable("Unhandled return value size");
        }
      } else {
        llvm_unreachable_internal("Unhandled return type");
      }
      raisedValues->setPhysRegSSAValue(RetReg, MI.getParent()->getNumber(),
                                       callInst);
    }
    if (MI.isBranch()) {
      // Emit appropriate ret instruction. There will be no ret instruction
      // in the binary since this is a tail call.
      ReturnInst *RetInstr;
      if (RetType->isVoidTy())
        RetInstr = ReturnInst::Create(Ctx);
      else {
        RetInstr = ReturnInst::Create(Ctx, callInst);
        ModuleRaiser *NonConstMR = const_cast<ModuleRaiser *>(MR);
        NonConstMR->changeRaisedFunctionReturnType(raisedFunction,
                                                   callInst->getType());
      }
      RaisedBB->getInstList().push_back(RetInstr);
    }
    // Add 'unreachable' instruction after callInst if it is a call to glibc
    // function 'void exit(int)'
    // 'void __assert_fail(char *, char *, unsigned int, char *)'
    if (CalledFunc->getName().equals("exit")) {
      FunctionType *FT = CalledFunc->getFunctionType();
      if (FT->getReturnType()->isVoidTy() && (FT->getNumParams() == 1) &&
          FT->getParamType(0)->isIntegerTy(32)) {
        Instruction *UR = new UnreachableInst(Ctx);
        RaisedBB->getInstList().push_back(UR);
        // Mark callInst as tail call
        dyn_cast<CallInst>(callInst)->setTailCall(true);
      }
    } else if (CalledFunc->getName().equals("__assert_fail")) {
      FunctionType *FT = CalledFunc->getFunctionType();
      if (FT->getReturnType()->isVoidTy() && FT->getNumParams() == 4 &&
          FT->getParamType(0)->isPointerTy() &&
          FT->getParamType(1)->isPointerTy() &&
          FT->getParamType(2)->isIntegerTy() &&
          FT->getParamType(3)->isPointerTy()) {
        Instruction *UR = new UnreachableInst(Ctx);
        RaisedBB->getInstList().push_back(UR);
        // Mark callInst as tail call
        dyn_cast<CallInst>(callInst)->setTailCall(true);
      }
    }
    Success = true;
  } break;
  case X86::CALL64m:
  case X86::CALL64r: {
    LLVMContext &Ctxt(MF.getFunction().getContext());
    BasicBlock *RaisedBB = getRaisedBasicBlock(MI.getParent());
    const MachineBasicBlock *MBB = MI.getParent();
    int MBBNo = MBB->getNumber();

    std::vector<Type *> ArgTypeVector;
    std::vector<Value *> ArgValueVector;

    // Find all sequentially reachable argument register defintions at call site
    for (auto Reg : GPR64ArgRegs64Bit) {
      Value *RD = // getRegOrArgValue(Reg, MBBNo);
          raisedValues->getReachingDef(Reg, MBBNo, true /* on all preds */,
                                       true /* any subreg */);
      if (RD == nullptr)
        break;
      else {
        ArgTypeVector.push_back(RD->getType());
        ArgValueVector.push_back(RD);
      }
    }
    for (auto Reg : SSEArgRegs64Bit) {
      Value *RD = raisedValues->getReachingDef(Reg, MBBNo, true, true);
      if (RD == nullptr) {
        break;
      } else {
        if (RD->getType()->isVectorTy()) {
          RD = raisedValues->reinterpretSSERegValue(RD, Type::getDoubleTy(Ctxt), RaisedBB);
        }
        ArgTypeVector.push_back(RD->getType());
        ArgValueVector.push_back(RD);
      }
    }

    // Find if return register is used before the end of the block with call
    // instruction. If so, consider that to indicate the return value of the
    // called function.
    bool BlockHasCall;
    Type *ReturnType = getReturnTypeFromMBB(*MBB, BlockHasCall /* ignored*/);

    // If return type not found, consider it to be void type
    if (ReturnType == nullptr) {
      ReturnType = Type::getVoidTy(MF.getFunction().getContext());
    }

    // Build Function type.
    auto FT = FunctionType::get(ReturnType, ArgTypeVector, false);

    Value *Func;
    // Get function pointer address.
    if (Opcode == X86::CALL64r) {
      unsigned int CallReg = MI.getOperand(0).getReg();
      Func = getRegOrArgValue(CallReg, MBBNo);
    } else {
      Value *MemRefValue = getMemoryRefValue(MI);

      unsigned LoadOpIndex = 0;
      // Get index of memory reference in the instruction.

      // Load the value from memory location of memRefValue.
      // memRefVal is either an AllocaInst (stack access), GlobalValue (global
      // data access), an effective address value, element pointer or select
      // instruction.
      assert((isa<AllocaInst>(MemRefValue) ||
              isEffectiveAddrValue(MemRefValue) ||
              isa<GlobalValue>(MemRefValue) || isa<SelectInst>(MemRefValue) ||
              isa<GetElementPtrInst>(MemRefValue) ||
              MemRefValue->getType()->isPointerTy()) &&
             "Unexpected type of memory reference in CALL64m instruction");

      PointerType *PtrTy =
          PointerType::get(getPhysRegOperandType(MI, LoadOpIndex), 0);
      if ((isEffectiveAddrValue(MemRefValue)) || isa<SelectInst>(MemRefValue)) {
        IntToPtrInst *ConvIntToPtr = new IntToPtrInst(MemRefValue, PtrTy);
        // Set or copy rodata metadata, if any
        getRaisedValues()->setInstMetadataRODataIndex(MemRefValue,
                                                      ConvIntToPtr);
        RaisedBB->getInstList().push_back(ConvIntToPtr);
        MemRefValue = ConvIntToPtr;
      }
      assert(MemRefValue->getType()->isPointerTy() &&
             "Pointer type expected in load instruction");
      // Cast the pointer to match the size of memory being accessed by the
      // instruction, as needed.
      MemRefValue = getRaisedValues()->castValue(MemRefValue, PtrTy, RaisedBB);

      // Load the value from memory location
      Type *LdTy = MemRefValue->getType()->getPointerElementType();
      LoadInst *LdInst =
          new LoadInst(LdTy, MemRefValue, "memload", false, Align());
      LdInst = getRaisedValues()->setInstMetadataRODataContent(LdInst);
      RaisedBB->getInstList().push_back(LdInst);
      MemRefValue = LdInst;

      Func = MemRefValue;
    }

    // Cast the function pointer address to function type pointer.
    Type *FuncTy = FT->getPointerTo();
    if (Func->getType() != FuncTy) {
      CastInst *CInst = CastInst::Create(
          CastInst::getCastOpcode(Func, false, FuncTy, false), Func, FuncTy);
      RaisedBB->getInstList().push_back(CInst);
      Func = CInst;
    }

    // Construct call instruction.
    CallInst *CallInst = CallInst::Create(
        cast<FunctionType>(
            cast<PointerType>(Func->getType())->getElementType()),
        Func, ArrayRef<Value *>(ArgValueVector));
    RaisedBB->getInstList().push_back(CallInst);

    // A function call with a non-void return will modify RAX.
    if (ReturnType && !ReturnType->isVoidTy())
      raisedValues->setPhysRegSSAValue(X86::RAX, MBBNo, CallInst);
    Success = true;
  } break;
  default: {
    assert(false && "Unhandled call instruction");
  } break;
  }

  return Success;
}