mirror of
https://github.com/AxioDL/llvm.git
synced 2026-03-30 11:42:29 -07:00
ac8bbffa16
The translation scheme is mostly cribbed from FastISel, and it's not entirely convincing semantically. But it does seem to work in the common cases and allow variables to be printed so it can't be all wrong. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@293228 91177308-0d34-0410-b5e6-96231b3b80d8
493 lines
18 KiB
C++
493 lines
18 KiB
C++
//===-- llvm/CodeGen/GlobalISel/MachineIRBuilder.cpp - MIBuilder--*- C++ -*-==//
|
|
//
|
|
// The LLVM Compiler Infrastructure
|
|
//
|
|
// This file is distributed under the University of Illinois Open Source
|
|
// License. See LICENSE.TXT for details.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
/// \file
|
|
/// This file implements the MachineIRBuidler class.
|
|
//===----------------------------------------------------------------------===//
|
|
#include "llvm/CodeGen/GlobalISel/MachineIRBuilder.h"
|
|
|
|
#include "llvm/CodeGen/MachineFunction.h"
|
|
#include "llvm/CodeGen/MachineInstr.h"
|
|
#include "llvm/CodeGen/MachineInstrBuilder.h"
|
|
#include "llvm/CodeGen/MachineRegisterInfo.h"
|
|
#include "llvm/IR/DebugInfo.h"
|
|
#include "llvm/Target/TargetInstrInfo.h"
|
|
#include "llvm/Target/TargetOpcodes.h"
|
|
#include "llvm/Target/TargetSubtargetInfo.h"
|
|
|
|
using namespace llvm;
|
|
|
|
void MachineIRBuilder::setMF(MachineFunction &MF) {
|
|
this->MF = &MF;
|
|
this->MBB = nullptr;
|
|
this->MRI = &MF.getRegInfo();
|
|
this->TII = MF.getSubtarget().getInstrInfo();
|
|
this->DL = DebugLoc();
|
|
this->II = MachineBasicBlock::iterator();
|
|
this->InsertedInstr = nullptr;
|
|
}
|
|
|
|
void MachineIRBuilder::setMBB(MachineBasicBlock &MBB) {
|
|
this->MBB = &MBB;
|
|
this->II = MBB.end();
|
|
assert(&getMF() == MBB.getParent() &&
|
|
"Basic block is in a different function");
|
|
}
|
|
|
|
void MachineIRBuilder::setInstr(MachineInstr &MI) {
|
|
assert(MI.getParent() && "Instruction is not part of a basic block");
|
|
setMBB(*MI.getParent());
|
|
this->II = MI.getIterator();
|
|
}
|
|
|
|
void MachineIRBuilder::setInsertPt(MachineBasicBlock &MBB,
|
|
MachineBasicBlock::iterator II) {
|
|
assert(MBB.getParent() == &getMF() &&
|
|
"Basic block is in a different function");
|
|
this->MBB = &MBB;
|
|
this->II = II;
|
|
}
|
|
|
|
void MachineIRBuilder::recordInsertions(
|
|
std::function<void(MachineInstr *)> Inserted) {
|
|
InsertedInstr = std::move(Inserted);
|
|
}
|
|
|
|
void MachineIRBuilder::stopRecordingInsertions() {
|
|
InsertedInstr = nullptr;
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
// Build instruction variants.
|
|
//------------------------------------------------------------------------------
|
|
|
|
MachineInstrBuilder MachineIRBuilder::buildInstr(unsigned Opcode) {
|
|
return insertInstr(buildInstrNoInsert(Opcode));
|
|
}
|
|
|
|
MachineInstrBuilder MachineIRBuilder::buildInstrNoInsert(unsigned Opcode) {
|
|
MachineInstrBuilder MIB = BuildMI(getMF(), DL, getTII().get(Opcode));
|
|
return MIB;
|
|
}
|
|
|
|
|
|
MachineInstrBuilder MachineIRBuilder::insertInstr(MachineInstrBuilder MIB) {
|
|
getMBB().insert(getInsertPt(), MIB);
|
|
if (InsertedInstr)
|
|
InsertedInstr(MIB);
|
|
return MIB;
|
|
}
|
|
|
|
MachineInstrBuilder MachineIRBuilder::buildDirectDbgValue(
|
|
unsigned Reg, const MDNode *Variable, const MDNode *Expr) {
|
|
assert(isa<DILocalVariable>(Variable) && "not a variable");
|
|
assert(cast<DIExpression>(Expr)->isValid() && "not an expression");
|
|
assert(cast<DILocalVariable>(Variable)->isValidLocationForIntrinsic(DL) &&
|
|
"Expected inlined-at fields to agree");
|
|
return buildInstr(TargetOpcode::DBG_VALUE)
|
|
.addReg(Reg, RegState::Debug)
|
|
.addReg(0, RegState::Debug)
|
|
.addMetadata(Variable)
|
|
.addMetadata(Expr);
|
|
}
|
|
|
|
MachineInstrBuilder MachineIRBuilder::buildIndirectDbgValue(
|
|
unsigned Reg, unsigned Offset, const MDNode *Variable, const MDNode *Expr) {
|
|
assert(isa<DILocalVariable>(Variable) && "not a variable");
|
|
assert(cast<DIExpression>(Expr)->isValid() && "not an expression");
|
|
assert(cast<DILocalVariable>(Variable)->isValidLocationForIntrinsic(DL) &&
|
|
"Expected inlined-at fields to agree");
|
|
return buildInstr(TargetOpcode::DBG_VALUE)
|
|
.addReg(Reg, RegState::Debug)
|
|
.addImm(Offset)
|
|
.addMetadata(Variable)
|
|
.addMetadata(Expr);
|
|
}
|
|
|
|
MachineInstrBuilder MachineIRBuilder::buildFIDbgValue(int FI,
|
|
const MDNode *Variable,
|
|
const MDNode *Expr) {
|
|
assert(isa<DILocalVariable>(Variable) && "not a variable");
|
|
assert(cast<DIExpression>(Expr)->isValid() && "not an expression");
|
|
assert(cast<DILocalVariable>(Variable)->isValidLocationForIntrinsic(DL) &&
|
|
"Expected inlined-at fields to agree");
|
|
return buildInstr(TargetOpcode::DBG_VALUE)
|
|
.addFrameIndex(FI)
|
|
.addImm(0)
|
|
.addMetadata(Variable)
|
|
.addMetadata(Expr);
|
|
}
|
|
|
|
MachineInstrBuilder MachineIRBuilder::buildConstDbgValue(const Constant &C,
|
|
unsigned Offset,
|
|
const MDNode *Variable,
|
|
const MDNode *Expr) {
|
|
assert(isa<DILocalVariable>(Variable) && "not a variable");
|
|
assert(cast<DIExpression>(Expr)->isValid() && "not an expression");
|
|
assert(cast<DILocalVariable>(Variable)->isValidLocationForIntrinsic(DL) &&
|
|
"Expected inlined-at fields to agree");
|
|
auto MIB = buildInstr(TargetOpcode::DBG_VALUE);
|
|
if (auto *CI = dyn_cast<ConstantInt>(&C)) {
|
|
if (CI->getBitWidth() > 64)
|
|
MIB.addCImm(CI);
|
|
else
|
|
MIB.addImm(CI->getZExtValue());
|
|
} else
|
|
MIB.addFPImm(&cast<ConstantFP>(C));
|
|
|
|
return MIB.addImm(Offset).addMetadata(Variable).addMetadata(Expr);
|
|
}
|
|
|
|
MachineInstrBuilder MachineIRBuilder::buildFrameIndex(unsigned Res, int Idx) {
|
|
assert(MRI->getType(Res).isPointer() && "invalid operand type");
|
|
return buildInstr(TargetOpcode::G_FRAME_INDEX)
|
|
.addDef(Res)
|
|
.addFrameIndex(Idx);
|
|
}
|
|
|
|
MachineInstrBuilder MachineIRBuilder::buildGlobalValue(unsigned Res,
|
|
const GlobalValue *GV) {
|
|
assert(MRI->getType(Res).isPointer() && "invalid operand type");
|
|
assert(MRI->getType(Res).getAddressSpace() ==
|
|
GV->getType()->getAddressSpace() &&
|
|
"address space mismatch");
|
|
|
|
return buildInstr(TargetOpcode::G_GLOBAL_VALUE)
|
|
.addDef(Res)
|
|
.addGlobalAddress(GV);
|
|
}
|
|
|
|
MachineInstrBuilder MachineIRBuilder::buildAdd(unsigned Res, unsigned Op0,
|
|
unsigned Op1) {
|
|
assert((MRI->getType(Res).isScalar() || MRI->getType(Res).isVector()) &&
|
|
"invalid operand type");
|
|
assert(MRI->getType(Res) == MRI->getType(Op0) &&
|
|
MRI->getType(Res) == MRI->getType(Op1) && "type mismatch");
|
|
|
|
return buildInstr(TargetOpcode::G_ADD)
|
|
.addDef(Res)
|
|
.addUse(Op0)
|
|
.addUse(Op1);
|
|
}
|
|
|
|
MachineInstrBuilder MachineIRBuilder::buildGEP(unsigned Res, unsigned Op0,
|
|
unsigned Op1) {
|
|
assert(MRI->getType(Res).isPointer() &&
|
|
MRI->getType(Res) == MRI->getType(Op0) && "type mismatch");
|
|
assert(MRI->getType(Op1).isScalar() && "invalid offset type");
|
|
|
|
return buildInstr(TargetOpcode::G_GEP)
|
|
.addDef(Res)
|
|
.addUse(Op0)
|
|
.addUse(Op1);
|
|
}
|
|
|
|
MachineInstrBuilder MachineIRBuilder::buildSub(unsigned Res, unsigned Op0,
|
|
unsigned Op1) {
|
|
assert((MRI->getType(Res).isScalar() || MRI->getType(Res).isVector()) &&
|
|
"invalid operand type");
|
|
assert(MRI->getType(Res) == MRI->getType(Op0) &&
|
|
MRI->getType(Res) == MRI->getType(Op1) && "type mismatch");
|
|
|
|
return buildInstr(TargetOpcode::G_SUB)
|
|
.addDef(Res)
|
|
.addUse(Op0)
|
|
.addUse(Op1);
|
|
}
|
|
|
|
MachineInstrBuilder MachineIRBuilder::buildMul(unsigned Res, unsigned Op0,
|
|
unsigned Op1) {
|
|
assert((MRI->getType(Res).isScalar() || MRI->getType(Res).isVector()) &&
|
|
"invalid operand type");
|
|
assert(MRI->getType(Res) == MRI->getType(Op0) &&
|
|
MRI->getType(Res) == MRI->getType(Op1) && "type mismatch");
|
|
|
|
return buildInstr(TargetOpcode::G_MUL)
|
|
.addDef(Res)
|
|
.addUse(Op0)
|
|
.addUse(Op1);
|
|
}
|
|
|
|
MachineInstrBuilder MachineIRBuilder::buildBr(MachineBasicBlock &Dest) {
|
|
return buildInstr(TargetOpcode::G_BR).addMBB(&Dest);
|
|
}
|
|
|
|
MachineInstrBuilder MachineIRBuilder::buildCopy(unsigned Res, unsigned Op) {
|
|
return buildInstr(TargetOpcode::COPY).addDef(Res).addUse(Op);
|
|
}
|
|
|
|
MachineInstrBuilder MachineIRBuilder::buildConstant(unsigned Res,
|
|
const ConstantInt &Val) {
|
|
LLT Ty = MRI->getType(Res);
|
|
|
|
assert((Ty.isScalar() || Ty.isPointer()) && "invalid operand type");
|
|
|
|
const ConstantInt *NewVal = &Val;
|
|
if (Ty.getSizeInBits() != Val.getBitWidth())
|
|
NewVal = ConstantInt::get(MF->getFunction()->getContext(),
|
|
Val.getValue().sextOrTrunc(Ty.getSizeInBits()));
|
|
|
|
return buildInstr(TargetOpcode::G_CONSTANT).addDef(Res).addCImm(NewVal);
|
|
}
|
|
|
|
MachineInstrBuilder MachineIRBuilder::buildConstant(unsigned Res,
|
|
int64_t Val) {
|
|
auto IntN = IntegerType::get(MF->getFunction()->getContext(),
|
|
MRI->getType(Res).getSizeInBits());
|
|
ConstantInt *CI = ConstantInt::get(IntN, Val, true);
|
|
return buildConstant(Res, *CI);
|
|
}
|
|
|
|
MachineInstrBuilder MachineIRBuilder::buildFConstant(unsigned Res,
|
|
const ConstantFP &Val) {
|
|
assert(MRI->getType(Res).isScalar() && "invalid operand type");
|
|
|
|
return buildInstr(TargetOpcode::G_FCONSTANT).addDef(Res).addFPImm(&Val);
|
|
}
|
|
|
|
MachineInstrBuilder MachineIRBuilder::buildBrCond(unsigned Tst,
|
|
MachineBasicBlock &Dest) {
|
|
assert(MRI->getType(Tst).isScalar() && "invalid operand type");
|
|
|
|
return buildInstr(TargetOpcode::G_BRCOND).addUse(Tst).addMBB(&Dest);
|
|
}
|
|
|
|
MachineInstrBuilder MachineIRBuilder::buildLoad(unsigned Res, unsigned Addr,
|
|
MachineMemOperand &MMO) {
|
|
assert(MRI->getType(Res).isValid() && "invalid operand type");
|
|
assert(MRI->getType(Addr).isPointer() && "invalid operand type");
|
|
|
|
return buildInstr(TargetOpcode::G_LOAD)
|
|
.addDef(Res)
|
|
.addUse(Addr)
|
|
.addMemOperand(&MMO);
|
|
}
|
|
|
|
MachineInstrBuilder MachineIRBuilder::buildStore(unsigned Val, unsigned Addr,
|
|
MachineMemOperand &MMO) {
|
|
assert(MRI->getType(Val).isValid() && "invalid operand type");
|
|
assert(MRI->getType(Addr).isPointer() && "invalid operand type");
|
|
|
|
return buildInstr(TargetOpcode::G_STORE)
|
|
.addUse(Val)
|
|
.addUse(Addr)
|
|
.addMemOperand(&MMO);
|
|
}
|
|
|
|
MachineInstrBuilder MachineIRBuilder::buildUAdde(unsigned Res,
|
|
unsigned CarryOut,
|
|
unsigned Op0, unsigned Op1,
|
|
unsigned CarryIn) {
|
|
assert(MRI->getType(Res).isScalar() && "invalid operand type");
|
|
assert(MRI->getType(Res) == MRI->getType(Op0) &&
|
|
MRI->getType(Res) == MRI->getType(Op1) && "type mismatch");
|
|
assert(MRI->getType(CarryOut).isScalar() && "invalid operand type");
|
|
assert(MRI->getType(CarryOut) == MRI->getType(CarryIn) && "type mismatch");
|
|
|
|
return buildInstr(TargetOpcode::G_UADDE)
|
|
.addDef(Res)
|
|
.addDef(CarryOut)
|
|
.addUse(Op0)
|
|
.addUse(Op1)
|
|
.addUse(CarryIn);
|
|
}
|
|
|
|
MachineInstrBuilder MachineIRBuilder::buildAnyExt(unsigned Res, unsigned Op) {
|
|
validateTruncExt(Res, Op, true);
|
|
return buildInstr(TargetOpcode::G_ANYEXT).addDef(Res).addUse(Op);
|
|
}
|
|
|
|
MachineInstrBuilder MachineIRBuilder::buildSExt(unsigned Res, unsigned Op) {
|
|
validateTruncExt(Res, Op, true);
|
|
return buildInstr(TargetOpcode::G_SEXT).addDef(Res).addUse(Op);
|
|
}
|
|
|
|
MachineInstrBuilder MachineIRBuilder::buildZExt(unsigned Res, unsigned Op) {
|
|
validateTruncExt(Res, Op, true);
|
|
return buildInstr(TargetOpcode::G_ZEXT).addDef(Res).addUse(Op);
|
|
}
|
|
|
|
MachineInstrBuilder MachineIRBuilder::buildSExtOrTrunc(unsigned Res,
|
|
unsigned Op) {
|
|
unsigned Opcode = TargetOpcode::COPY;
|
|
if (MRI->getType(Res).getSizeInBits() > MRI->getType(Op).getSizeInBits())
|
|
Opcode = TargetOpcode::G_SEXT;
|
|
else if (MRI->getType(Res).getSizeInBits() < MRI->getType(Op).getSizeInBits())
|
|
Opcode = TargetOpcode::G_TRUNC;
|
|
|
|
return buildInstr(Opcode).addDef(Res).addUse(Op);
|
|
}
|
|
|
|
MachineInstrBuilder MachineIRBuilder::buildExtract(ArrayRef<unsigned> Results,
|
|
ArrayRef<uint64_t> Indices,
|
|
unsigned Src) {
|
|
#ifndef NDEBUG
|
|
assert(Results.size() == Indices.size() && "inconsistent number of regs");
|
|
assert(!Results.empty() && "invalid trivial extract");
|
|
assert(std::is_sorted(Indices.begin(), Indices.end()) &&
|
|
"extract offsets must be in ascending order");
|
|
|
|
assert(MRI->getType(Src).isValid() && "invalid operand type");
|
|
for (auto Res : Results)
|
|
assert(MRI->getType(Res).isValid() && "invalid operand type");
|
|
#endif
|
|
|
|
auto MIB = BuildMI(getMF(), DL, getTII().get(TargetOpcode::G_EXTRACT));
|
|
for (auto Res : Results)
|
|
MIB.addDef(Res);
|
|
|
|
MIB.addUse(Src);
|
|
|
|
for (auto Idx : Indices)
|
|
MIB.addImm(Idx);
|
|
|
|
getMBB().insert(getInsertPt(), MIB);
|
|
if (InsertedInstr)
|
|
InsertedInstr(MIB);
|
|
|
|
return MIB;
|
|
}
|
|
|
|
MachineInstrBuilder
|
|
MachineIRBuilder::buildSequence(unsigned Res,
|
|
ArrayRef<unsigned> Ops,
|
|
ArrayRef<uint64_t> Indices) {
|
|
#ifndef NDEBUG
|
|
assert(Ops.size() == Indices.size() && "incompatible args");
|
|
assert(!Ops.empty() && "invalid trivial sequence");
|
|
assert(std::is_sorted(Indices.begin(), Indices.end()) &&
|
|
"sequence offsets must be in ascending order");
|
|
|
|
assert(MRI->getType(Res).isValid() && "invalid operand type");
|
|
for (auto Op : Ops)
|
|
assert(MRI->getType(Op).isValid() && "invalid operand type");
|
|
#endif
|
|
|
|
MachineInstrBuilder MIB = buildInstr(TargetOpcode::G_SEQUENCE);
|
|
MIB.addDef(Res);
|
|
for (unsigned i = 0; i < Ops.size(); ++i) {
|
|
MIB.addUse(Ops[i]);
|
|
MIB.addImm(Indices[i]);
|
|
}
|
|
return MIB;
|
|
}
|
|
|
|
MachineInstrBuilder MachineIRBuilder::buildIntrinsic(Intrinsic::ID ID,
|
|
unsigned Res,
|
|
bool HasSideEffects) {
|
|
auto MIB =
|
|
buildInstr(HasSideEffects ? TargetOpcode::G_INTRINSIC_W_SIDE_EFFECTS
|
|
: TargetOpcode::G_INTRINSIC);
|
|
if (Res)
|
|
MIB.addDef(Res);
|
|
MIB.addIntrinsicID(ID);
|
|
return MIB;
|
|
}
|
|
|
|
MachineInstrBuilder MachineIRBuilder::buildTrunc(unsigned Res, unsigned Op) {
|
|
validateTruncExt(Res, Op, false);
|
|
return buildInstr(TargetOpcode::G_TRUNC).addDef(Res).addUse(Op);
|
|
}
|
|
|
|
MachineInstrBuilder MachineIRBuilder::buildFPTrunc(unsigned Res, unsigned Op) {
|
|
validateTruncExt(Res, Op, false);
|
|
return buildInstr(TargetOpcode::G_FPTRUNC).addDef(Res).addUse(Op);
|
|
}
|
|
|
|
MachineInstrBuilder MachineIRBuilder::buildICmp(CmpInst::Predicate Pred,
|
|
unsigned Res, unsigned Op0,
|
|
unsigned Op1) {
|
|
#ifndef NDEBUG
|
|
assert(MRI->getType(Op0) == MRI->getType(Op0) && "type mismatch");
|
|
assert(CmpInst::isIntPredicate(Pred) && "invalid predicate");
|
|
if (MRI->getType(Op0).isScalar() || MRI->getType(Op0).isPointer())
|
|
assert(MRI->getType(Res).isScalar() && "type mismatch");
|
|
else
|
|
assert(MRI->getType(Res).isVector() &&
|
|
MRI->getType(Res).getNumElements() ==
|
|
MRI->getType(Op0).getNumElements() &&
|
|
"type mismatch");
|
|
#endif
|
|
|
|
return buildInstr(TargetOpcode::G_ICMP)
|
|
.addDef(Res)
|
|
.addPredicate(Pred)
|
|
.addUse(Op0)
|
|
.addUse(Op1);
|
|
}
|
|
|
|
MachineInstrBuilder MachineIRBuilder::buildFCmp(CmpInst::Predicate Pred,
|
|
unsigned Res, unsigned Op0,
|
|
unsigned Op1) {
|
|
#ifndef NDEBUG
|
|
assert((MRI->getType(Op0).isScalar() || MRI->getType(Op0).isVector()) &&
|
|
"invalid operand type");
|
|
assert(MRI->getType(Op0) == MRI->getType(Op1) && "type mismatch");
|
|
assert(CmpInst::isFPPredicate(Pred) && "invalid predicate");
|
|
if (MRI->getType(Op0).isScalar())
|
|
assert(MRI->getType(Res).isScalar() && "type mismatch");
|
|
else
|
|
assert(MRI->getType(Res).isVector() &&
|
|
MRI->getType(Res).getNumElements() ==
|
|
MRI->getType(Op0).getNumElements() &&
|
|
"type mismatch");
|
|
#endif
|
|
|
|
return buildInstr(TargetOpcode::G_FCMP)
|
|
.addDef(Res)
|
|
.addPredicate(Pred)
|
|
.addUse(Op0)
|
|
.addUse(Op1);
|
|
}
|
|
|
|
MachineInstrBuilder MachineIRBuilder::buildSelect(unsigned Res, unsigned Tst,
|
|
unsigned Op0, unsigned Op1) {
|
|
#ifndef NDEBUG
|
|
LLT ResTy = MRI->getType(Res);
|
|
assert((ResTy.isScalar() || ResTy.isVector() || ResTy.isPointer()) &&
|
|
"invalid operand type");
|
|
assert(ResTy == MRI->getType(Op0) && ResTy == MRI->getType(Op1) &&
|
|
"type mismatch");
|
|
if (ResTy.isScalar() || ResTy.isPointer())
|
|
assert(MRI->getType(Tst).isScalar() && "type mismatch");
|
|
else
|
|
assert(MRI->getType(Tst).isVector() &&
|
|
MRI->getType(Tst).getNumElements() ==
|
|
MRI->getType(Op0).getNumElements() &&
|
|
"type mismatch");
|
|
#endif
|
|
|
|
return buildInstr(TargetOpcode::G_SELECT)
|
|
.addDef(Res)
|
|
.addUse(Tst)
|
|
.addUse(Op0)
|
|
.addUse(Op1);
|
|
}
|
|
|
|
void MachineIRBuilder::validateTruncExt(unsigned Dst, unsigned Src,
|
|
bool IsExtend) {
|
|
#ifndef NDEBUG
|
|
LLT SrcTy = MRI->getType(Src);
|
|
LLT DstTy = MRI->getType(Dst);
|
|
|
|
if (DstTy.isVector()) {
|
|
assert(SrcTy.isVector() && "mismatched cast between vecot and non-vector");
|
|
assert(SrcTy.getNumElements() == DstTy.getNumElements() &&
|
|
"different number of elements in a trunc/ext");
|
|
} else
|
|
assert(DstTy.isScalar() && SrcTy.isScalar() && "invalid extend/trunc");
|
|
|
|
if (IsExtend)
|
|
assert(DstTy.getSizeInBits() > SrcTy.getSizeInBits() &&
|
|
"invalid narrowing extend");
|
|
else
|
|
assert(DstTy.getSizeInBits() < SrcTy.getSizeInBits() &&
|
|
"invalid widening trunc");
|
|
#endif
|
|
}
|