forked from OSchip/llvm-project
GlobalISel: support same ConstantExprs as Instructions.
It's more than just inttoptr, but the others can't be tested until we have support for non-trivial constants (they currently get unavoidably folded to a ConstantInt). llvm-svn: 278303
This commit is contained in:
parent
1ae68cdee7
commit
357f1be2ca
|
@ -109,47 +109,128 @@ private:
|
|||
|
||||
/// Translate an LLVM bitcast into generic IR. Either a COPY or a G_BITCAST is
|
||||
/// emitted.
|
||||
bool translateBitCast(const CastInst &CI);
|
||||
bool translateBitCast(const User &U);
|
||||
|
||||
/// Translate an LLVM load instruction into generic IR.
|
||||
bool translateLoad(const LoadInst &LI);
|
||||
bool translateLoad(const User &U);
|
||||
|
||||
/// Translate an LLVM store instruction into generic IR.
|
||||
bool translateStore(const StoreInst &SI);
|
||||
bool translateStore(const User &U);
|
||||
|
||||
/// Translate call instruction.
|
||||
/// \pre \p Inst is a call instruction.
|
||||
bool translateCall(const CallInst &Inst);
|
||||
/// \pre \p U is a call instruction.
|
||||
bool translateCall(const User &U);
|
||||
|
||||
/// Translate one of LLVM's cast instructions into MachineInstrs, with the
|
||||
/// given generic Opcode.
|
||||
bool translateCast(unsigned Opcode, const CastInst &CI);
|
||||
bool translateCast(unsigned Opcode, const User &U);
|
||||
|
||||
/// Translate static alloca instruction (i.e. one of constant size and in the
|
||||
/// first basic block).
|
||||
bool translateStaticAlloca(const AllocaInst &Inst);
|
||||
|
||||
/// Translate a phi instruction.
|
||||
bool translatePhi(const PHINode &PI);
|
||||
bool translatePHI(const User &U);
|
||||
|
||||
/// Add remaining operands onto phis we've translated. Executed after all
|
||||
/// MachineBasicBlocks for the function have been created.
|
||||
void finishPendingPhis();
|
||||
|
||||
/// Translate \p Inst into a binary operation \p Opcode.
|
||||
/// \pre \p Inst is a binary operation.
|
||||
bool translateBinaryOp(unsigned Opcode, const BinaryOperator &Inst);
|
||||
/// \pre \p U is a binary operation.
|
||||
bool translateBinaryOp(unsigned Opcode, const User &U);
|
||||
|
||||
/// Translate branch (br) instruction.
|
||||
/// \pre \p Inst is a branch instruction.
|
||||
bool translateBr(const BranchInst &Inst);
|
||||
/// \pre \p U is a branch instruction.
|
||||
bool translateBr(const User &U);
|
||||
|
||||
bool translateAdd(const User &U) {
|
||||
return translateBinaryOp(TargetOpcode::G_ADD, U);
|
||||
}
|
||||
bool translateSub(const User &U) {
|
||||
return translateBinaryOp(TargetOpcode::G_SUB, U);
|
||||
}
|
||||
bool translateAnd(const User &U) {
|
||||
return translateBinaryOp(TargetOpcode::G_AND, U);
|
||||
}
|
||||
bool translateMul(const User &U) {
|
||||
return translateBinaryOp(TargetOpcode::G_MUL, U);
|
||||
}
|
||||
bool translateOr(const User &U) {
|
||||
return translateBinaryOp(TargetOpcode::G_OR, U);
|
||||
}
|
||||
bool translateXor(const User &U) {
|
||||
return translateBinaryOp(TargetOpcode::G_XOR, U);
|
||||
}
|
||||
bool translateAlloca(const User &U) {
|
||||
return translateStaticAlloca(cast<AllocaInst>(U));
|
||||
}
|
||||
bool translateIntToPtr(const User &U) {
|
||||
return translateCast(TargetOpcode::G_INTTOPTR, U);
|
||||
}
|
||||
bool translatePtrToInt(const User &U) {
|
||||
return translateCast(TargetOpcode::G_PTRTOINT, U);
|
||||
}
|
||||
bool translateTrunc(const User &U) {
|
||||
return translateCast(TargetOpcode::G_TRUNC, U);
|
||||
}
|
||||
bool translateUnreachable(const User &U) { return true; }
|
||||
|
||||
/// Translate return (ret) instruction.
|
||||
/// The target needs to implement CallLowering::lowerReturn for
|
||||
/// this to succeed.
|
||||
/// \pre \p Inst is a return instruction.
|
||||
bool translateReturn(const ReturnInst &Inst);
|
||||
/// \pre \p U is a return instruction.
|
||||
bool translateRet(const User &U);
|
||||
|
||||
// Stubs to keep the compiler happy while we implement the rest of the
|
||||
// translation.
|
||||
bool translateSwitch(const User &U) { return false; }
|
||||
bool translateIndirectBr(const User &U) { return false; }
|
||||
bool translateInvoke(const User &U) { return false; }
|
||||
bool translateResume(const User &U) { return false; }
|
||||
bool translateCleanupRet(const User &U) { return false; }
|
||||
bool translateCatchRet(const User &U) { return false; }
|
||||
bool translateCatchSwitch(const User &U) { return false; }
|
||||
bool translateFAdd(const User &U) { return false; }
|
||||
bool translateFSub(const User &U) { return false; }
|
||||
bool translateFMul(const User &U) { return false; }
|
||||
bool translateUDiv(const User &U) { return false; }
|
||||
bool translateSDiv(const User &U) { return false; }
|
||||
bool translateFDiv(const User &U) { return false; }
|
||||
bool translateURem(const User &U) { return false; }
|
||||
bool translateSRem(const User &U) { return false; }
|
||||
bool translateFRem(const User &U) { return false; }
|
||||
bool translateShl(const User &U) { return false; }
|
||||
bool translateLShr(const User &U) { return false; }
|
||||
bool translateAShr(const User &U) { return false; }
|
||||
bool translateGetElementPtr(const User &U) { return false; }
|
||||
bool translateFence(const User &U) { return false; }
|
||||
bool translateAtomicCmpXchg(const User &U) { return false; }
|
||||
bool translateAtomicRMW(const User &U) { return false; }
|
||||
bool translateSExt(const User &U) { return false; }
|
||||
bool translateZExt(const User &U) { return false; }
|
||||
bool translateFPToUI(const User &U) { return false; }
|
||||
bool translateFPToSI(const User &U) { return false; }
|
||||
bool translateUIToFP(const User &U) { return false; }
|
||||
bool translateSIToFP(const User &U) { return false; }
|
||||
bool translateFPTrunc(const User &U) { return false; }
|
||||
bool translateFPExt(const User &U) { return false; }
|
||||
bool translateAddrSpaceCast(const User &U) { return false; }
|
||||
bool translateCleanupPad(const User &U) { return false; }
|
||||
bool translateCatchPad(const User &U) { return false; }
|
||||
bool translateICmp(const User &U) { return false; }
|
||||
bool translateFCmp(const User &U) { return false; }
|
||||
bool translateSelect(const User &U) { return false; }
|
||||
bool translateUserOp1(const User &U) { return false; }
|
||||
bool translateUserOp2(const User &U) { return false; }
|
||||
bool translateVAArg(const User &U) { return false; }
|
||||
bool translateExtractElement(const User &U) { return false; }
|
||||
bool translateInsertElement(const User &U) { return false; }
|
||||
bool translateShuffleVector(const User &U) { return false; }
|
||||
bool translateExtractValue(const User &U) { return false; }
|
||||
bool translateInsertValue(const User &U) { return false; }
|
||||
bool translateLandingPad(const User &U) { return false; }
|
||||
|
||||
/// @}
|
||||
|
||||
// Builder for machine instruction a la IRBuilder.
|
||||
|
|
|
@ -84,25 +84,25 @@ MachineBasicBlock &IRTranslator::getOrCreateBB(const BasicBlock &BB) {
|
|||
return *MBB;
|
||||
}
|
||||
|
||||
bool IRTranslator::translateBinaryOp(unsigned Opcode,
|
||||
const BinaryOperator &Inst) {
|
||||
bool IRTranslator::translateBinaryOp(unsigned Opcode, const User &U) {
|
||||
// FIXME: handle signed/unsigned wrapping flags.
|
||||
|
||||
// Get or create a virtual register for each value.
|
||||
// Unless the value is a Constant => loadimm cst?
|
||||
// or inline constant each time?
|
||||
// Creation of a virtual register needs to have a size.
|
||||
unsigned Op0 = getOrCreateVReg(*Inst.getOperand(0));
|
||||
unsigned Op1 = getOrCreateVReg(*Inst.getOperand(1));
|
||||
unsigned Res = getOrCreateVReg(Inst);
|
||||
MIRBuilder.buildInstr(Opcode, LLT{*Inst.getType()})
|
||||
unsigned Op0 = getOrCreateVReg(*U.getOperand(0));
|
||||
unsigned Op1 = getOrCreateVReg(*U.getOperand(1));
|
||||
unsigned Res = getOrCreateVReg(U);
|
||||
MIRBuilder.buildInstr(Opcode, LLT{*U.getType()})
|
||||
.addDef(Res)
|
||||
.addUse(Op0)
|
||||
.addUse(Op1);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool IRTranslator::translateReturn(const ReturnInst &RI) {
|
||||
bool IRTranslator::translateRet(const User &U) {
|
||||
const ReturnInst &RI = cast<ReturnInst>(U);
|
||||
const Value *Ret = RI.getReturnValue();
|
||||
// The target may mess up with the insertion point, but
|
||||
// this is not important as a return is the last instruction
|
||||
|
@ -110,7 +110,8 @@ bool IRTranslator::translateReturn(const ReturnInst &RI) {
|
|||
return CLI->lowerReturn(MIRBuilder, Ret, !Ret ? 0 : getOrCreateVReg(*Ret));
|
||||
}
|
||||
|
||||
bool IRTranslator::translateBr(const BranchInst &BrInst) {
|
||||
bool IRTranslator::translateBr(const User &U) {
|
||||
const BranchInst &BrInst = cast<BranchInst>(U);
|
||||
unsigned Succ = 0;
|
||||
if (!BrInst.isUnconditional()) {
|
||||
// We want a G_BRCOND to the true BB followed by an unconditional branch.
|
||||
|
@ -131,7 +132,8 @@ bool IRTranslator::translateBr(const BranchInst &BrInst) {
|
|||
return true;
|
||||
}
|
||||
|
||||
bool IRTranslator::translateLoad(const LoadInst &LI) {
|
||||
bool IRTranslator::translateLoad(const User &U) {
|
||||
const LoadInst &LI = cast<LoadInst>(U);
|
||||
assert(LI.isSimple() && "only simple loads are supported at the moment");
|
||||
|
||||
MachineFunction &MF = MIRBuilder.getMF();
|
||||
|
@ -147,7 +149,8 @@ bool IRTranslator::translateLoad(const LoadInst &LI) {
|
|||
return true;
|
||||
}
|
||||
|
||||
bool IRTranslator::translateStore(const StoreInst &SI) {
|
||||
bool IRTranslator::translateStore(const User &U) {
|
||||
const StoreInst &SI = cast<StoreInst>(U);
|
||||
assert(SI.isSimple() && "only simple loads are supported at the moment");
|
||||
|
||||
MachineFunction &MF = MIRBuilder.getMF();
|
||||
|
@ -164,28 +167,30 @@ bool IRTranslator::translateStore(const StoreInst &SI) {
|
|||
return true;
|
||||
}
|
||||
|
||||
bool IRTranslator::translateBitCast(const CastInst &CI) {
|
||||
if (LLT{*CI.getDestTy()} == LLT{*CI.getSrcTy()}) {
|
||||
unsigned &Reg = ValToVReg[&CI];
|
||||
bool IRTranslator::translateBitCast(const User &U) {
|
||||
if (LLT{*U.getOperand(0)->getType()} == LLT{*U.getType()}) {
|
||||
unsigned &Reg = ValToVReg[&U];
|
||||
if (Reg)
|
||||
MIRBuilder.buildCopy(Reg, getOrCreateVReg(*CI.getOperand(0)));
|
||||
MIRBuilder.buildCopy(Reg, getOrCreateVReg(*U.getOperand(0)));
|
||||
else
|
||||
Reg = getOrCreateVReg(*CI.getOperand(0));
|
||||
Reg = getOrCreateVReg(*U.getOperand(0));
|
||||
return true;
|
||||
}
|
||||
return translateCast(TargetOpcode::G_BITCAST, CI);
|
||||
return translateCast(TargetOpcode::G_BITCAST, U);
|
||||
}
|
||||
|
||||
bool IRTranslator::translateCast(unsigned Opcode, const CastInst &CI) {
|
||||
unsigned Op = getOrCreateVReg(*CI.getOperand(0));
|
||||
unsigned Res = getOrCreateVReg(CI);
|
||||
MIRBuilder.buildInstr(Opcode, {LLT{*CI.getDestTy()}, LLT{*CI.getSrcTy()}})
|
||||
bool IRTranslator::translateCast(unsigned Opcode, const User &U) {
|
||||
unsigned Op = getOrCreateVReg(*U.getOperand(0));
|
||||
unsigned Res = getOrCreateVReg(U);
|
||||
MIRBuilder
|
||||
.buildInstr(Opcode, {LLT{*U.getType()}, LLT{*U.getOperand(0)->getType()}})
|
||||
.addDef(Res)
|
||||
.addUse(Op);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool IRTranslator::translateCall(const CallInst &CI) {
|
||||
bool IRTranslator::translateCall(const User &U) {
|
||||
const CallInst &CI = cast<CallInst>(U);
|
||||
auto TII = MIRBuilder.getMF().getTarget().getIntrinsicInfo();
|
||||
const Function *F = CI.getCalledFunction();
|
||||
|
||||
|
@ -246,7 +251,8 @@ bool IRTranslator::translateStaticAlloca(const AllocaInst &AI) {
|
|||
return true;
|
||||
}
|
||||
|
||||
bool IRTranslator::translatePhi(const PHINode &PI) {
|
||||
bool IRTranslator::translatePHI(const User &U) {
|
||||
const PHINode &PI = cast<PHINode>(U);
|
||||
MachineInstrBuilder MIB = MIRBuilder.buildInstr(TargetOpcode::PHI);
|
||||
MIB.addDef(getOrCreateVReg(PI));
|
||||
|
||||
|
@ -277,59 +283,11 @@ void IRTranslator::finishPendingPhis() {
|
|||
bool IRTranslator::translate(const Instruction &Inst) {
|
||||
MIRBuilder.setDebugLoc(Inst.getDebugLoc());
|
||||
switch(Inst.getOpcode()) {
|
||||
// Arithmetic operations.
|
||||
case Instruction::Add:
|
||||
return translateBinaryOp(TargetOpcode::G_ADD, cast<BinaryOperator>(Inst));
|
||||
case Instruction::Sub:
|
||||
return translateBinaryOp(TargetOpcode::G_SUB, cast<BinaryOperator>(Inst));
|
||||
|
||||
// Bitwise operations.
|
||||
case Instruction::And:
|
||||
return translateBinaryOp(TargetOpcode::G_AND, cast<BinaryOperator>(Inst));
|
||||
case Instruction::Mul:
|
||||
return translateBinaryOp(TargetOpcode::G_MUL, cast<BinaryOperator>(Inst));
|
||||
case Instruction::Or:
|
||||
return translateBinaryOp(TargetOpcode::G_OR, cast<BinaryOperator>(Inst));
|
||||
case Instruction::Xor:
|
||||
return translateBinaryOp(TargetOpcode::G_XOR, cast<BinaryOperator>(Inst));
|
||||
|
||||
// Branch operations.
|
||||
case Instruction::Br:
|
||||
return translateBr(cast<BranchInst>(Inst));
|
||||
case Instruction::Ret:
|
||||
return translateReturn(cast<ReturnInst>(Inst));
|
||||
|
||||
// Calls
|
||||
case Instruction::Call:
|
||||
return translateCall(cast<CallInst>(Inst));
|
||||
|
||||
// Casts and allied operations
|
||||
case Instruction::BitCast:
|
||||
return translateBitCast(cast<CastInst>(Inst));
|
||||
case Instruction::IntToPtr:
|
||||
return translateCast(TargetOpcode::G_INTTOPTR, cast<CastInst>(Inst));
|
||||
case Instruction::PtrToInt:
|
||||
return translateCast(TargetOpcode::G_PTRTOINT, cast<CastInst>(Inst));
|
||||
case Instruction::Trunc:
|
||||
return translateCast(TargetOpcode::G_TRUNC, cast<CastInst>(Inst));
|
||||
|
||||
// Memory ops.
|
||||
case Instruction::Load:
|
||||
return translateLoad(cast<LoadInst>(Inst));
|
||||
case Instruction::Store:
|
||||
return translateStore(cast<StoreInst>(Inst));
|
||||
|
||||
case Instruction::Alloca:
|
||||
return translateStaticAlloca(cast<AllocaInst>(Inst));
|
||||
|
||||
case Instruction::PHI:
|
||||
return translatePhi(cast<PHINode>(Inst));
|
||||
|
||||
case Instruction::Unreachable:
|
||||
return true;
|
||||
|
||||
#define HANDLE_INST(NUM, OPCODE, CLASS) \
|
||||
case Instruction::OPCODE: return translate##OPCODE(Inst);
|
||||
#include "llvm/IR/Instruction.def"
|
||||
default:
|
||||
llvm_unreachable("Opcode not supported");
|
||||
llvm_unreachable("unknown opcode");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -338,7 +296,15 @@ bool IRTranslator::translate(const Constant &C, unsigned Reg) {
|
|||
EntryBuilder.buildConstant(LLT{*CI->getType()}, Reg, CI->getZExtValue());
|
||||
else if (isa<UndefValue>(C))
|
||||
EntryBuilder.buildInstr(TargetOpcode::IMPLICIT_DEF).addDef(Reg);
|
||||
else
|
||||
else if (auto CE = dyn_cast<ConstantExpr>(&C)) {
|
||||
switch(CE->getOpcode()) {
|
||||
#define HANDLE_INST(NUM, OPCODE, CLASS) \
|
||||
case Instruction::OPCODE: return translate##OPCODE(*CE);
|
||||
#include "llvm/IR/Instruction.def"
|
||||
default:
|
||||
llvm_unreachable("unknown opcode");
|
||||
}
|
||||
} else
|
||||
llvm_unreachable("unhandled constant kind");
|
||||
|
||||
return true;
|
||||
|
|
|
@ -389,3 +389,11 @@ define i32 @constant_int_start() {
|
|||
define i32 @test_undef() {
|
||||
ret i32 undef
|
||||
}
|
||||
|
||||
; CHECK-LABEL: name: test_constant_inttoptr
|
||||
; CHECK: [[ONE:%[0-9]+]](64) = G_CONSTANT s64 1
|
||||
; CHECK: [[PTR:%[0-9]+]](64) = G_INTTOPTR { p0, s64 } [[ONE]]
|
||||
; CHECK: %x0 = COPY [[PTR]]
|
||||
define i8* @test_constant_inttoptr() {
|
||||
ret i8* inttoptr(i64 1 to i8*)
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue