aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTim Northover <tnorthover@apple.com>2017-03-03 22:46:09 +0000
committerTim Northover <tnorthover@apple.com>2017-03-03 22:46:09 +0000
commitbf017293af6e0f91a3ff7f173521abf66a32a18b (patch)
tree7e50c84787444bba6b8a2e40e1cc15931ce91168
parent5013eb9e1acb16b81a3a16dbd47353cf3ce4a22b (diff)
downloadllvm-bf017293af6e0f91a3ff7f173521abf66a32a18b.zip
llvm-bf017293af6e0f91a3ff7f173521abf66a32a18b.tar.gz
llvm-bf017293af6e0f91a3ff7f173521abf66a32a18b.tar.bz2
GlobalISel: add merge/unmerge nodes for legalization.
These are simplified variants of the current G_SEQUENCE and G_EXTRACT, which assume the individual parts will be contiguous, homogeneous, and occupy the entirity of the larger register. This makes reasoning about them much easer since you only have to look at the first register being merged and the result to know what the instruction is doing. I intend to gradually replace all uses of the more complicated sequence/extract with these (or single-element insert/extracts), and then remove the older variants. For now we start with legalization. llvm-svn: 296921
-rw-r--r--llvm/include/llvm/CodeGen/GlobalISel/Legalizer.h3
-rw-r--r--llvm/include/llvm/CodeGen/GlobalISel/MachineIRBuilder.h25
-rw-r--r--llvm/include/llvm/Target/GenericOpcodes.td15
-rw-r--r--llvm/include/llvm/Target/TargetOpcodes.def4
-rw-r--r--llvm/lib/CodeGen/GlobalISel/Legalizer.cpp31
-rw-r--r--llvm/lib/CodeGen/GlobalISel/LegalizerHelper.cpp24
-rw-r--r--llvm/lib/CodeGen/GlobalISel/LegalizerInfo.cpp4
-rw-r--r--llvm/lib/CodeGen/GlobalISel/MachineIRBuilder.cpp40
-rw-r--r--llvm/test/CodeGen/AArch64/GlobalISel/legalize-add.mir20
-rw-r--r--llvm/test/CodeGen/AArch64/GlobalISel/legalize-load-store.mir4
10 files changed, 139 insertions, 31 deletions
diff --git a/llvm/include/llvm/CodeGen/GlobalISel/Legalizer.h b/llvm/include/llvm/CodeGen/GlobalISel/Legalizer.h
index 8284ab6..bed7230 100644
--- a/llvm/include/llvm/CodeGen/GlobalISel/Legalizer.h
+++ b/llvm/include/llvm/CodeGen/GlobalISel/Legalizer.h
@@ -58,6 +58,9 @@ public:
bool combineExtracts(MachineInstr &MI, MachineRegisterInfo &MRI,
const TargetInstrInfo &TII);
+ bool combineMerges(MachineInstr &MI, MachineRegisterInfo &MRI,
+ const TargetInstrInfo &TII);
+
bool runOnMachineFunction(MachineFunction &MF) override;
};
} // End namespace llvm.
diff --git a/llvm/include/llvm/CodeGen/GlobalISel/MachineIRBuilder.h b/llvm/include/llvm/CodeGen/GlobalISel/MachineIRBuilder.h
index a3fa6c2..d7fe1c4 100644
--- a/llvm/include/llvm/CodeGen/GlobalISel/MachineIRBuilder.h
+++ b/llvm/include/llvm/CodeGen/GlobalISel/MachineIRBuilder.h
@@ -468,6 +468,31 @@ public:
ArrayRef<unsigned> Ops,
ArrayRef<uint64_t> Indices);
+ /// Build and insert \p Res<def> = G_MERGE_VALUES \p Op0, ...
+ ///
+ /// G_MERGE_VALUES combines the input elements contiguously into a larger
+ /// register.
+ ///
+ /// \pre setBasicBlock or setMI must have been called.
+ /// \pre The entire register \p Res (and no more) must be covered by the input
+ /// registers.
+ /// \pre The type of all \p Ops registers must be identical.
+ ///
+ /// \return a MachineInstrBuilder for the newly created instruction.
+ MachineInstrBuilder buildMerge(unsigned Res, ArrayRef<unsigned> Ops);
+
+ /// Build and insert \p Res0<def>, ... = G_UNMERGE_VALUES \p Op
+ ///
+ /// G_UNMERGE_VALUES splits contiguous bits of the input into multiple
+ ///
+ /// \pre setBasicBlock or setMI must have been called.
+ /// \pre The entire register \p Res (and no more) must be covered by the input
+ /// registers.
+ /// \pre The type of all \p Res registers must be identical.
+ ///
+ /// \return a MachineInstrBuilder for the newly created instruction.
+ MachineInstrBuilder buildUnmerge(ArrayRef<unsigned> Res, unsigned Op);
+
void addUsesWithIndices(MachineInstrBuilder MIB) {}
template <typename... ArgTys>
diff --git a/llvm/include/llvm/Target/GenericOpcodes.td b/llvm/include/llvm/Target/GenericOpcodes.td
index 880fbc4..fecdd72 100644
--- a/llvm/include/llvm/Target/GenericOpcodes.td
+++ b/llvm/include/llvm/Target/GenericOpcodes.td
@@ -434,6 +434,15 @@ def G_EXTRACT : Instruction {
let hasSideEffects = 0;
}
+// Extract multiple registers specified size, starting from blocks given by
+// indexes. This will almost certainly be mapped to sub-register COPYs after
+// register banks have been selected.
+def G_UNMERGE_VALUES : Instruction {
+ let OutOperandList = (outs);
+ let InOperandList = (ins variable_ops);
+ let hasSideEffects = 0;
+}
+
// Insert a sequence of smaller registers into a larger one at the specified
// indices (interleaved with the values in the operand list "op0, bit0, op1,
// bit1, ...")).
@@ -452,6 +461,12 @@ def G_SEQUENCE : Instruction {
let hasSideEffects = 0;
}
+def G_MERGE_VALUES : Instruction {
+ let OutOperandList = (outs type0:$dst);
+ let InOperandList = (ins variable_ops);
+ let hasSideEffects = 0;
+}
+
// Intrinsic without side effects.
def G_INTRINSIC : Instruction {
let OutOperandList = (outs);
diff --git a/llvm/include/llvm/Target/TargetOpcodes.def b/llvm/include/llvm/Target/TargetOpcodes.def
index 2d1ff50..58e6157 100644
--- a/llvm/include/llvm/Target/TargetOpcodes.def
+++ b/llvm/include/llvm/Target/TargetOpcodes.def
@@ -229,6 +229,8 @@ HANDLE_TARGET_OPCODE(G_GLOBAL_VALUE)
/// (typically a sub-register COPY after instruction selection).
HANDLE_TARGET_OPCODE(G_EXTRACT)
+HANDLE_TARGET_OPCODE(G_UNMERGE_VALUES)
+
/// Generic instruction to insert blocks of bits from the registers given into
/// the source.
HANDLE_TARGET_OPCODE(G_INSERT)
@@ -237,6 +239,8 @@ HANDLE_TARGET_OPCODE(G_INSERT)
/// larger register.
HANDLE_TARGET_OPCODE(G_SEQUENCE)
+HANDLE_TARGET_OPCODE(G_MERGE_VALUES)
+
/// Generic pointer to int conversion.
HANDLE_TARGET_OPCODE(G_PTRTOINT)
diff --git a/llvm/lib/CodeGen/GlobalISel/Legalizer.cpp b/llvm/lib/CodeGen/GlobalISel/Legalizer.cpp
index 8f3d341..a849346 100644
--- a/llvm/lib/CodeGen/GlobalISel/Legalizer.cpp
+++ b/llvm/lib/CodeGen/GlobalISel/Legalizer.cpp
@@ -113,6 +113,36 @@ bool Legalizer::combineExtracts(MachineInstr &MI, MachineRegisterInfo &MRI,
return Changed;
}
+bool Legalizer::combineMerges(MachineInstr &MI, MachineRegisterInfo &MRI,
+ const TargetInstrInfo &TII) {
+ if (MI.getOpcode() != TargetOpcode::G_UNMERGE_VALUES)
+ return false;
+
+ unsigned NumDefs = MI.getNumOperands() - 1;
+ unsigned SrcReg = MI.getOperand(NumDefs).getReg();
+ MachineInstr &MergeI = *MRI.def_instr_begin(SrcReg);
+ if (MergeI.getOpcode() != TargetOpcode::G_MERGE_VALUES)
+ return false;
+
+ if (MergeI.getNumOperands() - 1 != NumDefs)
+ return false;
+
+ // FIXME: is a COPY appropriate if the types mismatch? We know both registers
+ // are allocatable by now.
+ if (MRI.getType(MI.getOperand(0).getReg()) !=
+ MRI.getType(MergeI.getOperand(1).getReg()))
+ return false;
+
+ for (unsigned Idx = 0; Idx < NumDefs; ++Idx)
+ MRI.replaceRegWith(MI.getOperand(Idx).getReg(),
+ MergeI.getOperand(Idx + 1).getReg());
+
+ MI.eraseFromParent();
+ if (MRI.use_empty(MergeI.getOperand(0).getReg()))
+ MergeI.eraseFromParent();
+ return true;
+}
+
bool Legalizer::runOnMachineFunction(MachineFunction &MF) {
// If the ISel pipeline failed, do not bother running that pass.
if (MF.getProperties().hasProperty(
@@ -166,6 +196,7 @@ bool Legalizer::runOnMachineFunction(MachineFunction &MF) {
NextMI = std::next(MI);
Changed |= combineExtracts(*MI, MRI, TII);
+ Changed |= combineMerges(*MI, MRI, TII);
}
}
diff --git a/llvm/lib/CodeGen/GlobalISel/LegalizerHelper.cpp b/llvm/lib/CodeGen/GlobalISel/LegalizerHelper.cpp
index 6bb64e068..2d28a42 100644
--- a/llvm/lib/CodeGen/GlobalISel/LegalizerHelper.cpp
+++ b/llvm/lib/CodeGen/GlobalISel/LegalizerHelper.cpp
@@ -86,13 +86,9 @@ LegalizerHelper::legalizeInstr(MachineInstr &MI,
void LegalizerHelper::extractParts(unsigned Reg, LLT Ty, int NumParts,
SmallVectorImpl<unsigned> &VRegs) {
- unsigned Size = Ty.getSizeInBits();
- SmallVector<uint64_t, 4> Indexes;
- for (int i = 0; i < NumParts; ++i) {
+ for (int i = 0; i < NumParts; ++i)
VRegs.push_back(MRI.createGenericVirtualRegister(Ty));
- Indexes.push_back(i * Size);
- }
- MIRBuilder.buildExtract(VRegs, Indexes, Reg);
+ MIRBuilder.buildUnmerge(VRegs, Reg);
}
static RTLIB::Libcall getRTLibDesc(unsigned Opcode, unsigned Size) {
@@ -156,12 +152,10 @@ LegalizerHelper::LegalizeResult LegalizerHelper::narrowScalar(MachineInstr &MI,
return UnableToLegalize;
case TargetOpcode::G_ADD: {
// Expand in terms of carry-setting/consuming G_ADDE instructions.
- unsigned NarrowSize = NarrowTy.getSizeInBits();
int NumParts = MRI.getType(MI.getOperand(0).getReg()).getSizeInBits() /
NarrowTy.getSizeInBits();
SmallVector<unsigned, 2> Src1Regs, Src2Regs, DstRegs;
- SmallVector<uint64_t, 2> Indexes;
extractParts(MI.getOperand(1).getReg(), NarrowTy, NumParts, Src1Regs);
extractParts(MI.getOperand(2).getReg(), NarrowTy, NumParts, Src2Regs);
@@ -176,11 +170,10 @@ LegalizerHelper::LegalizeResult LegalizerHelper::narrowScalar(MachineInstr &MI,
Src2Regs[i], CarryIn);
DstRegs.push_back(DstReg);
- Indexes.push_back(i * NarrowSize);
CarryIn = CarryOut;
}
unsigned DstReg = MI.getOperand(0).getReg();
- MIRBuilder.buildSequence(DstReg, DstRegs, Indexes);
+ MIRBuilder.buildMerge(DstReg, DstRegs);
MI.eraseFromParent();
return Legalized;
}
@@ -200,7 +193,6 @@ LegalizerHelper::LegalizeResult LegalizerHelper::narrowScalar(MachineInstr &MI,
for (int i = 0; i < NumParts; ++i) {
unsigned DstStart = i * NarrowSize;
unsigned DstReg = MRI.createGenericVirtualRegister(NarrowTy);
- Indexes.push_back(DstStart);
findInsertionsForRange(DstStart, DstStart + NarrowSize, CurOp, EndOp, MI);
@@ -239,7 +231,7 @@ LegalizerHelper::LegalizeResult LegalizerHelper::narrowScalar(MachineInstr &MI,
}
assert(DstRegs.size() == (unsigned)NumParts && "not all parts covered");
- MIRBuilder.buildSequence(MI.getOperand(0).getReg(), DstRegs, Indexes);
+ MIRBuilder.buildMerge(MI.getOperand(0).getReg(), DstRegs);
MI.eraseFromParent();
return Legalized;
}
@@ -251,7 +243,6 @@ LegalizerHelper::LegalizeResult LegalizerHelper::narrowScalar(MachineInstr &MI,
MRI.getType(MI.getOperand(1).getReg()).getAddressSpace(), NarrowSize);
SmallVector<unsigned, 2> DstRegs;
- SmallVector<uint64_t, 2> Indexes;
for (int i = 0; i < NumParts; ++i) {
unsigned DstReg = MRI.createGenericVirtualRegister(NarrowTy);
unsigned SrcReg = MRI.createGenericVirtualRegister(NarrowPtrTy);
@@ -264,10 +255,9 @@ LegalizerHelper::LegalizeResult LegalizerHelper::narrowScalar(MachineInstr &MI,
MIRBuilder.buildLoad(DstReg, SrcReg, **MI.memoperands_begin());
DstRegs.push_back(DstReg);
- Indexes.push_back(i * NarrowSize);
}
unsigned DstReg = MI.getOperand(0).getReg();
- MIRBuilder.buildSequence(DstReg, DstRegs, Indexes);
+ MIRBuilder.buildMerge(DstReg, DstRegs);
MI.eraseFromParent();
return Legalized;
}
@@ -578,7 +568,6 @@ LegalizerHelper::fewerElementsVector(MachineInstr &MI, unsigned TypeIdx,
MIRBuilder.setInstr(MI);
SmallVector<unsigned, 2> Src1Regs, Src2Regs, DstRegs;
- SmallVector<uint64_t, 2> Indexes;
extractParts(MI.getOperand(1).getReg(), NarrowTy, NumParts, Src1Regs);
extractParts(MI.getOperand(2).getReg(), NarrowTy, NumParts, Src2Regs);
@@ -586,10 +575,9 @@ LegalizerHelper::fewerElementsVector(MachineInstr &MI, unsigned TypeIdx,
unsigned DstReg = MRI.createGenericVirtualRegister(NarrowTy);
MIRBuilder.buildAdd(DstReg, Src1Regs[i], Src2Regs[i]);
DstRegs.push_back(DstReg);
- Indexes.push_back(i * NarrowSize);
}
- MIRBuilder.buildSequence(DstReg, DstRegs, Indexes);
+ MIRBuilder.buildMerge(DstReg, DstRegs);
MI.eraseFromParent();
return Legalized;
}
diff --git a/llvm/lib/CodeGen/GlobalISel/LegalizerInfo.cpp b/llvm/lib/CodeGen/GlobalISel/LegalizerInfo.cpp
index 75c54c2..d9e4f84 100644
--- a/llvm/lib/CodeGen/GlobalISel/LegalizerInfo.cpp
+++ b/llvm/lib/CodeGen/GlobalISel/LegalizerInfo.cpp
@@ -80,7 +80,9 @@ LegalizerInfo::getAction(const InstrAspect &Aspect) const {
// FIXME: the long-term plan calls for expansion in terms of load/store (if
// they're not legal).
if (Aspect.Opcode == TargetOpcode::G_SEQUENCE ||
- Aspect.Opcode == TargetOpcode::G_EXTRACT)
+ Aspect.Opcode == TargetOpcode::G_EXTRACT ||
+ Aspect.Opcode == TargetOpcode::G_MERGE_VALUES ||
+ Aspect.Opcode == TargetOpcode::G_UNMERGE_VALUES)
return std::make_pair(Legal, Aspect.Type);
LegalizeAction Action = findInActions(Aspect);
diff --git a/llvm/lib/CodeGen/GlobalISel/MachineIRBuilder.cpp b/llvm/lib/CodeGen/GlobalISel/MachineIRBuilder.cpp
index d92bbc1c..41985e3 100644
--- a/llvm/lib/CodeGen/GlobalISel/MachineIRBuilder.cpp
+++ b/llvm/lib/CodeGen/GlobalISel/MachineIRBuilder.cpp
@@ -416,6 +416,46 @@ MachineIRBuilder::buildSequence(unsigned Res,
return MIB;
}
+MachineInstrBuilder MachineIRBuilder::buildMerge(unsigned Res,
+ ArrayRef<unsigned> Ops) {
+
+#ifndef NDEBUG
+ assert(!Ops.empty() && "invalid trivial sequence");
+ LLT Ty = MRI->getType(Ops[0]);
+ for (auto Reg : Ops)
+ assert(MRI->getType(Reg) == Ty && "type mismatch in input list");
+ assert(Ops.size() * MRI->getType(Ops[0]).getSizeInBits() ==
+ MRI->getType(Res).getSizeInBits() &&
+ "input operands do not cover output register");
+#endif
+
+ MachineInstrBuilder MIB = buildInstr(TargetOpcode::G_MERGE_VALUES);
+ MIB.addDef(Res);
+ for (unsigned i = 0; i < Ops.size(); ++i)
+ MIB.addUse(Ops[i]);
+ return MIB;
+}
+
+MachineInstrBuilder MachineIRBuilder::buildUnmerge(ArrayRef<unsigned> Res,
+ unsigned Op) {
+
+#ifndef NDEBUG
+ assert(!Res.empty() && "invalid trivial sequence");
+ LLT Ty = MRI->getType(Res[0]);
+ for (auto Reg : Res)
+ assert(MRI->getType(Reg) == Ty && "type mismatch in input list");
+ assert(Res.size() * MRI->getType(Res[0]).getSizeInBits() ==
+ MRI->getType(Op).getSizeInBits() &&
+ "input operands do not cover output register");
+#endif
+
+ MachineInstrBuilder MIB = buildInstr(TargetOpcode::G_UNMERGE_VALUES);
+ for (unsigned i = 0; i < Res.size(); ++i)
+ MIB.addDef(Res[i]);
+ MIB.addUse(Op);
+ return MIB;
+}
+
MachineInstrBuilder MachineIRBuilder::buildIntrinsic(Intrinsic::ID ID,
unsigned Res,
bool HasSideEffects) {
diff --git a/llvm/test/CodeGen/AArch64/GlobalISel/legalize-add.mir b/llvm/test/CodeGen/AArch64/GlobalISel/legalize-add.mir
index 63f8520..9b27198b 100644
--- a/llvm/test/CodeGen/AArch64/GlobalISel/legalize-add.mir
+++ b/llvm/test/CodeGen/AArch64/GlobalISel/legalize-add.mir
@@ -33,14 +33,14 @@ body: |
bb.0.entry:
liveins: %x0, %x1, %x2, %x3
; CHECK-LABEL: name: test_scalar_add_big
- ; CHECK-NOT: G_EXTRACT
- ; CHECK-NOT: G_SEQUENCE
+ ; CHECK-NOT: G_MERGE_VALUES
+ ; CHECK-NOT: G_UNMERGE_VALUES
; CHECK-DAG: [[CARRY0_32:%.*]](s32) = G_CONSTANT i32 0
; CHECK-DAG: [[CARRY0:%[0-9]+]](s1) = G_TRUNC [[CARRY0_32]]
; CHECK: [[RES_LO:%.*]](s64), [[CARRY:%.*]](s1) = G_UADDE %0, %2, [[CARRY0]]
; CHECK: [[RES_HI:%.*]](s64), {{%.*}}(s1) = G_UADDE %1, %3, [[CARRY]]
- ; CHECK-NOT: G_EXTRACT
- ; CHECK-NOT: G_SEQUENCE
+ ; CHECK-NOT: G_MERGE_VALUES
+ ; CHECK-NOT: G_UNMERGE_VALUES
; CHECK: %x0 = COPY [[RES_LO]]
; CHECK: %x1 = COPY [[RES_HI]]
@@ -48,10 +48,10 @@ body: |
%1(s64) = COPY %x1
%2(s64) = COPY %x2
%3(s64) = COPY %x3
- %4(s128) = G_SEQUENCE %0, 0, %1, 64
- %5(s128) = G_SEQUENCE %2, 0, %3, 64
+ %4(s128) = G_MERGE_VALUES %0, %1
+ %5(s128) = G_MERGE_VALUES %2, %3
%6(s128) = G_ADD %4, %5
- %7(s64), %8(s64) = G_EXTRACT %6, 0, 64
+ %7(s64), %8(s64) = G_UNMERGE_VALUES %6
%x0 = COPY %7
%x1 = COPY %8
...
@@ -112,10 +112,10 @@ body: |
%1(<2 x s64>) = COPY %q1
%2(<2 x s64>) = COPY %q2
%3(<2 x s64>) = COPY %q3
- %4(<4 x s64>) = G_SEQUENCE %0, 0, %1, 128
- %5(<4 x s64>) = G_SEQUENCE %2, 0, %3, 128
+ %4(<4 x s64>) = G_MERGE_VALUES %0, %1
+ %5(<4 x s64>) = G_MERGE_VALUES %2, %3
%6(<4 x s64>) = G_ADD %4, %5
- %7(<2 x s64>), %8(<2 x s64>) = G_EXTRACT %6, 0, 128
+ %7(<2 x s64>), %8(<2 x s64>) = G_UNMERGE_VALUES %6
%q0 = COPY %7
%q1 = COPY %8
...
diff --git a/llvm/test/CodeGen/AArch64/GlobalISel/legalize-load-store.mir b/llvm/test/CodeGen/AArch64/GlobalISel/legalize-load-store.mir
index 2955113..e7983af2 100644
--- a/llvm/test/CodeGen/AArch64/GlobalISel/legalize-load-store.mir
+++ b/llvm/test/CodeGen/AArch64/GlobalISel/legalize-load-store.mir
@@ -59,7 +59,7 @@ body: |
; CHECK: [[OFFSET1:%[0-9]+]](s64) = G_CONSTANT i64 8
; CHECK: [[GEP1:%[0-9]+]](p0) = G_GEP %0, [[OFFSET1]](s64)
; CHECK: [[LOAD1:%[0-9]+]](s64) = G_LOAD [[GEP1]](p0) :: (load 16 from %ir.addr)
- ; CHECK: %8(s128) = G_SEQUENCE [[LOAD0]](s64), 0, [[LOAD1]](s64), 64
+ ; CHECK: %8(s128) = G_MERGE_VALUES [[LOAD0]](s64), [[LOAD1]](s64)
%8(s128) = G_LOAD %0(p0) :: (load 16 from %ir.addr)
...
@@ -112,6 +112,6 @@ body: |
; CHECK: [[GEP1:%[0-9]+]](p0) = G_GEP %0, [[OFFSET1]](s64)
; CHECK: G_STORE %6(s64), [[GEP1]](p0) :: (store 16 into %ir.addr)
%6(s64) = G_PTRTOINT %0(p0)
- %7(s128) = G_SEQUENCE %5, 0, %6, 64
+ %7(s128) = G_MERGE_VALUES %5, %6
G_STORE %7, %0 :: (store 16 into %ir.addr)
...