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;
}