Skip to content

Commit

Permalink
GlobalISel: restrict G_EXTRACT instruction to just one operand.
Browse files Browse the repository at this point in the history
A bit more painful than G_INSERT because it was more widely used, but this
should simplify the handling of extract operations in most locations.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@297100 91177308-0d34-0410-b5e6-96231b3b80d8
  • Loading branch information
TNorthover committed Mar 6, 2017
1 parent a5015a4 commit 2c87ca8
Show file tree
Hide file tree
Showing 21 changed files with 151 additions and 115 deletions.
12 changes: 3 additions & 9 deletions include/llvm/CodeGen/GlobalISel/MachineIRBuilder.h
Original file line number Diff line number Diff line change
Expand Up @@ -440,19 +440,13 @@ class MachineIRBuilder {
MachineInstrBuilder buildStore(unsigned Val, unsigned Addr,
MachineMemOperand &MMO);

/// Build and insert `Res0<def>, ... = G_EXTRACT Src, Idx0, ...`.
///
/// If \p Res[i] has size N bits, G_EXTRACT sets \p Res[i] to bits `[Idxs[i],
/// Idxs[i] + N)` of \p Src.
/// Build and insert `Res0<def>, ... = G_EXTRACT Src, Idx0`.
///
/// \pre setBasicBlock or setMI must have been called.
/// \pre Indices must be in ascending order of bit position.
/// \pre Each member of \p Results and \p Src must be a generic
/// virtual register.
/// \pre \p Res and \p Src must be generic virtual registers.
///
/// \return a MachineInstrBuilder for the newly created instruction.
MachineInstrBuilder buildExtract(ArrayRef<unsigned> Results,
ArrayRef<uint64_t> Indices, unsigned Src);
MachineInstrBuilder buildExtract(unsigned Res, unsigned Src, uint64_t Index);

/// Build and insert \p Res = IMPLICIT_DEF.
MachineInstrBuilder buildUndef(unsigned Dst);
Expand Down
4 changes: 2 additions & 2 deletions include/llvm/Target/GenericOpcodes.td
Original file line number Diff line number Diff line change
Expand Up @@ -429,8 +429,8 @@ def G_STORE : Instruction {
// indexes. This will almost certainly be mapped to sub-register COPYs after
// register banks have been selected.
def G_EXTRACT : Instruction {
let OutOperandList = (outs);
let InOperandList = (ins variable_ops);
let OutOperandList = (outs type0:$res);
let InOperandList = (ins type1:$src, unknown:$offset);
let hasSideEffects = 0;
}

Expand Down
2 changes: 1 addition & 1 deletion lib/CodeGen/GlobalISel/IRTranslator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -341,7 +341,7 @@ bool IRTranslator::translateExtractValue(const User &U,
uint64_t Offset = 8 * DL->getIndexedOffsetInType(Src->getType(), Indices);

unsigned Res = getOrCreateVReg(U);
MIRBuilder.buildExtract(Res, Offset, getOrCreateVReg(*Src));
MIRBuilder.buildExtract(Res, getOrCreateVReg(*Src), Offset);

return true;
}
Expand Down
4 changes: 2 additions & 2 deletions lib/CodeGen/GlobalISel/LegalizerHelper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -202,8 +202,8 @@ LegalizerHelper::LegalizeResult LegalizerHelper::narrowScalar(MachineInstr &MI,
if (OpSegSize != OpSize) {
// A genuine extract is needed.
OpSegReg = MRI.createGenericVirtualRegister(LLT::scalar(OpSegSize));
MIRBuilder.buildExtract(OpSegReg, std::max(OpSegStart, (int64_t)0),
OpReg);
MIRBuilder.buildExtract(OpSegReg, OpReg,
std::max(OpSegStart, (int64_t)0));
}

unsigned DstReg = MRI.createGenericVirtualRegister(NarrowTy);
Expand Down
37 changes: 14 additions & 23 deletions lib/CodeGen/GlobalISel/MachineIRBuilder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -382,34 +382,25 @@ MachineInstrBuilder MachineIRBuilder::buildCast(unsigned Dst, unsigned Src) {
return buildInstr(Opcode).addDef(Dst).addUse(Src);
}

MachineInstrBuilder MachineIRBuilder::buildExtract(ArrayRef<unsigned> Results,
ArrayRef<uint64_t> Indices,
unsigned Src) {
MachineInstrBuilder MachineIRBuilder::buildExtract(unsigned Res, unsigned Src,
uint64_t Index) {
#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");
assert(MRI->getType(Res).isValid() && "invalid operand type");
assert(Index + MRI->getType(Res).getSizeInBits() <=
MRI->getType(Src).getSizeInBits() &&
"extracting off end of register");
#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);
if (MRI->getType(Res).getSizeInBits() == MRI->getType(Src).getSizeInBits()) {
assert(Index == 0 && "insertion past the end of a register");
return buildCast(Res, Src);
}

return MIB;
return buildInstr(TargetOpcode::G_EXTRACT)
.addDef(Res)
.addUse(Src)
.addImm(Index);
}

MachineInstrBuilder
Expand Down
45 changes: 25 additions & 20 deletions lib/Target/AArch64/AArch64CallLowering.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -200,15 +200,8 @@ void AArch64CallLowering::splitToValueTypes(
OrigArg.Flags, OrigArg.IsFixed});
}

SmallVector<uint64_t, 4> BitOffsets;
for (auto Offset : Offsets)
BitOffsets.push_back(Offset * 8);

SmallVector<unsigned, 8> SplitRegs;
for (auto I = &SplitArgs[FirstRegIdx]; I != SplitArgs.end(); ++I)
SplitRegs.push_back(I->Reg);

PerformArgSplit(SplitRegs, BitOffsets);
for (unsigned i = 0; i < Offsets.size(); ++i)
PerformArgSplit(SplitArgs[FirstRegIdx + i].Reg, Offsets[i] * 8);
}

bool AArch64CallLowering::lowerReturn(MachineIRBuilder &MIRBuilder,
Expand All @@ -230,8 +223,8 @@ bool AArch64CallLowering::lowerReturn(MachineIRBuilder &MIRBuilder,

SmallVector<ArgInfo, 8> SplitArgs;
splitToValueTypes(OrigArg, SplitArgs, DL, MRI,
[&](ArrayRef<unsigned> Regs, ArrayRef<uint64_t> Offsets) {
MIRBuilder.buildExtract(Regs, Offsets, VReg);
[&](unsigned Reg, uint64_t Offset) {
MIRBuilder.buildExtract(Reg, VReg, Offset);
});

OutgoingArgHandler Handler(MIRBuilder, MRI, MIB, AssignFn, AssignFn);
Expand All @@ -256,10 +249,24 @@ bool AArch64CallLowering::lowerFormalArguments(MachineIRBuilder &MIRBuilder,
for (auto &Arg : Args) {
ArgInfo OrigArg{VRegs[i], Arg.getType()};
setArgFlags(OrigArg, i + 1, DL, F);
bool Split = false;
LLT Ty = MRI.getType(VRegs[i]);
unsigned Dst = VRegs[i];

splitToValueTypes(OrigArg, SplitArgs, DL, MRI,
[&](ArrayRef<unsigned> Regs, ArrayRef<uint64_t> Offsets) {
MIRBuilder.buildSequence(VRegs[i], Regs, Offsets);
[&](unsigned Reg, uint64_t Offset) {
if (!Split) {
Split = true;
Dst = MRI.createGenericVirtualRegister(Ty);
MIRBuilder.buildUndef(Dst);
}
unsigned Tmp = MRI.createGenericVirtualRegister(Ty);
MIRBuilder.buildInsert(Tmp, Dst, Reg, Offset);
Dst = Tmp;
});

if (Dst != VRegs[i])
MIRBuilder.buildCopy(VRegs[i], Dst);
++i;
}

Expand Down Expand Up @@ -307,8 +314,8 @@ bool AArch64CallLowering::lowerCall(MachineIRBuilder &MIRBuilder,
SmallVector<ArgInfo, 8> SplitArgs;
for (auto &OrigArg : OrigArgs) {
splitToValueTypes(OrigArg, SplitArgs, DL, MRI,
[&](ArrayRef<unsigned> Regs, ArrayRef<uint64_t> Offsets) {
MIRBuilder.buildExtract(Regs, Offsets, OrigArg.Reg);
[&](unsigned Reg, uint64_t Offset) {
MIRBuilder.buildExtract(Reg, OrigArg.Reg, Offset);
});
}

Expand Down Expand Up @@ -360,11 +367,9 @@ bool AArch64CallLowering::lowerCall(MachineIRBuilder &MIRBuilder,
SmallVector<uint64_t, 8> RegOffsets;
SmallVector<unsigned, 8> SplitRegs;
splitToValueTypes(OrigRet, SplitArgs, DL, MRI,
[&](ArrayRef<unsigned> Regs, ArrayRef<uint64_t> Offsets) {
std::copy(Offsets.begin(), Offsets.end(),
std::back_inserter(RegOffsets));
std::copy(Regs.begin(), Regs.end(),
std::back_inserter(SplitRegs));
[&](unsigned Reg, uint64_t Offset) {
RegOffsets.push_back(Offset);
SplitRegs.push_back(Reg);
});

CallReturnHandler Handler(MIRBuilder, MRI, MIB, RetAssignFn);
Expand Down
3 changes: 1 addition & 2 deletions lib/Target/AArch64/AArch64CallLowering.h
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,7 @@ class AArch64CallLowering: public CallLowering {
typedef std::function<void(MachineIRBuilder &, int, CCValAssign &)>
MemHandler;

typedef std::function<void(ArrayRef<unsigned>, ArrayRef<uint64_t>)>
SplitArgTy;
typedef std::function<void(unsigned, uint64_t)> SplitArgTy;

void splitToValueTypes(const ArgInfo &OrigArgInfo,
SmallVectorImpl<ArgInfo> &SplitArgs,
Expand Down
4 changes: 2 additions & 2 deletions lib/Target/ARM/ARMCallLowering.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -118,8 +118,8 @@ struct OutgoingValueHandler : public CallLowering::ValueHandler {

unsigned NewRegs[] = {MRI.createGenericVirtualRegister(LLT::scalar(32)),
MRI.createGenericVirtualRegister(LLT::scalar(32))};

MIRBuilder.buildExtract(NewRegs, {0, 32}, Arg.Reg);
MIRBuilder.buildExtract(NewRegs[0], Arg.Reg, 0);
MIRBuilder.buildExtract(NewRegs[1], Arg.Reg, 32);

bool IsLittle = MIRBuilder.getMF().getSubtarget<ARMSubtarget>().isLittle();
if (!IsLittle)
Expand Down
20 changes: 8 additions & 12 deletions lib/Target/ARM/ARMInstructionSelector.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -148,23 +148,19 @@ static bool selectExtract(MachineInstrBuilder &MIB, const ARMBaseInstrInfo &TII,
(void)VReg0;
assert(MRI.getType(VReg0).getSizeInBits() == 32 &&
RBI.getRegBank(VReg0, MRI, TRI)->getID() == ARM::GPRRegBankID &&
"Unsupported operand for G_SEQUENCE");
"Unsupported operand for G_EXTRACT");
unsigned VReg1 = MIB->getOperand(1).getReg();
(void)VReg1;
assert(MRI.getType(VReg1).getSizeInBits() == 32 &&
RBI.getRegBank(VReg1, MRI, TRI)->getID() == ARM::GPRRegBankID &&
"Unsupported operand for G_SEQUENCE");
unsigned VReg2 = MIB->getOperand(2).getReg();
(void)VReg2;
assert(MRI.getType(VReg2).getSizeInBits() == 64 &&
RBI.getRegBank(VReg2, MRI, TRI)->getID() == ARM::FPRRegBankID &&
"Unsupported operand for G_SEQUENCE");
assert(MRI.getType(VReg1).getSizeInBits() == 64 &&
RBI.getRegBank(VReg1, MRI, TRI)->getID() == ARM::FPRRegBankID &&
"Unsupported operand for G_EXTRACT");
assert(MIB->getOperand(2).getImm() % 32 == 0 &&
"Unsupported operand for G_EXTRACT");

// Remove the operands corresponding to the offsets.
MIB->RemoveOperand(4);
MIB->RemoveOperand(3);
MIB->getOperand(2).setImm(MIB->getOperand(2).getImm() / 32);

MIB->setDesc(TII.get(ARM::VMOVRRD));
MIB->setDesc(TII.get(ARM::VGETLNi32));
MIB.add(predOps(ARMCC::AL));

return true;
Expand Down
6 changes: 2 additions & 4 deletions lib/Target/ARM/ARMRegisterBankInfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -263,12 +263,10 @@ ARMRegisterBankInfo::getInstrMapping(const MachineInstr &MI) const {
// We only support G_EXTRACT for splitting a double precision floating point
// value into two GPRs.
LLT Ty1 = MRI.getType(MI.getOperand(1).getReg());
LLT Ty2 = MRI.getType(MI.getOperand(2).getReg());
if (Ty.getSizeInBits() != 32 || Ty1.getSizeInBits() != 32 ||
Ty2.getSizeInBits() != 64)
if (Ty.getSizeInBits() != 32 || Ty1.getSizeInBits() != 64 ||
MI.getOperand(2).getImm() % 32 != 0)
return InstructionMapping{};
OperandsMapping = getOperandsMapping({&ARM::ValueMappings[ARM::GPR3OpsIdx],
&ARM::ValueMappings[ARM::GPR3OpsIdx],
&ARM::ValueMappings[ARM::DPR3OpsIdx],
nullptr, nullptr});
break;
Expand Down
25 changes: 17 additions & 8 deletions lib/Target/X86/X86CallLowering.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -61,11 +61,8 @@ void X86CallLowering::splitToValueTypes(const ArgInfo &OrigArg,
ArgInfo Info = ArgInfo{MRI.createGenericVirtualRegister(LLT{*PartTy, DL}),
PartTy, OrigArg.Flags};
SplitArgs.push_back(Info);
BitOffsets.push_back(PartVT.getSizeInBits() * i);
SplitRegs.push_back(Info.Reg);
PerformArgSplit(Info.Reg, PartVT.getSizeInBits() * i);
}

PerformArgSplit(SplitRegs, BitOffsets);
}

namespace {
Expand Down Expand Up @@ -113,8 +110,8 @@ bool X86CallLowering::lowerReturn(MachineIRBuilder &MIRBuilder,

SmallVector<ArgInfo, 8> SplitArgs;
splitToValueTypes(OrigArg, SplitArgs, DL, MRI,
[&](ArrayRef<unsigned> Regs, ArrayRef<uint64_t> Offsets) {
MIRBuilder.buildExtract(Regs, Offsets, VReg);
[&](unsigned Reg, uint64_t Offset) {
MIRBuilder.buildExtract(Reg, VReg, Offset);
});

FuncReturnHandler Handler(MIRBuilder, MRI, MIB, RetCC_X86);
Expand Down Expand Up @@ -184,10 +181,22 @@ bool X86CallLowering::lowerFormalArguments(MachineIRBuilder &MIRBuilder,
for (auto &Arg : F.getArgumentList()) {
ArgInfo OrigArg(VRegs[Idx], Arg.getType());
setArgFlags(OrigArg, Idx + 1, DL, F);
LLT Ty = MRI.getType(VRegs[Idx]);
unsigned Dst = VRegs[Idx];
bool Split = false;
splitToValueTypes(OrigArg, SplitArgs, DL, MRI,
[&](ArrayRef<unsigned> Regs, ArrayRef<uint64_t> Offsets) {
MIRBuilder.buildSequence(VRegs[Idx], Regs, Offsets);
[&](unsigned Reg, uint64_t Offset) {
if (!Split) {
Split = true;
Dst = MRI.createGenericVirtualRegister(Ty);
MIRBuilder.buildUndef(Dst);
}
unsigned Tmp = MRI.createGenericVirtualRegister(Ty);
MIRBuilder.buildInsert(Tmp, Dst, Reg, Offset);
Dst = Tmp;
});
if (Dst != VRegs[Idx])
MIRBuilder.buildCopy(VRegs[Idx], Dst);
Idx++;
}

Expand Down
3 changes: 1 addition & 2 deletions lib/Target/X86/X86CallLowering.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,7 @@ class X86CallLowering : public CallLowering {
ArrayRef<unsigned> VRegs) const override;
private:
/// A function of this type is used to perform value split action.
typedef std::function<void(ArrayRef<unsigned>, ArrayRef<uint64_t>)>
SplitArgTy;
typedef std::function<void(unsigned, uint64_t)> SplitArgTy;

void splitToValueTypes(const ArgInfo &OrigArgInfo,
SmallVectorImpl<ArgInfo> &SplitArgs,
Expand Down
21 changes: 18 additions & 3 deletions test/CodeGen/AArch64/GlobalISel/call-translator.ll
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,13 @@ define void @test_multiple_args(i64 %in) {
; CHECK: [[I64:%[0-9]+]](s64) = COPY %x0
; CHECK: [[I8:%[0-9]+]](s8) = COPY %w1
; CHECK: [[ADDR:%[0-9]+]](p0) = COPY %x2
; CHECK: [[ARG:%[0-9]+]](s192) = G_SEQUENCE [[DBL]](s64), 0, [[I64]](s64), 64, [[I8]](s8), 128

; CHECK: [[UNDEF:%[0-9]+]](s192) = IMPLICIT_DEF
; CHECK: [[ARG0:%[0-9]+]](s192) = G_INSERT [[UNDEF]], [[DBL]](s64), 0
; CHECK: [[ARG1:%[0-9]+]](s192) = G_INSERT [[ARG0]], [[I64]](s64), 64
; CHECK: [[ARG2:%[0-9]+]](s192) = G_INSERT [[ARG1]], [[I8]](s8), 128
; CHECK: [[ARG:%[0-9]+]](s192) = COPY [[ARG2]]

; CHECK: G_STORE [[ARG]](s192), [[ADDR]](p0)
; CHECK: RET_ReallyLR
define void @test_struct_formal({double, i64, i8} %in, {double, i64, i8}* %addr) {
Expand All @@ -75,7 +81,11 @@ define void @test_struct_formal({double, i64, i8} %in, {double, i64, i8}* %addr)
; CHECK-LABEL: name: test_struct_return
; CHECK: [[ADDR:%[0-9]+]](p0) = COPY %x0
; CHECK: [[VAL:%[0-9]+]](s192) = G_LOAD [[ADDR]](p0)
; CHECK: [[DBL:%[0-9]+]](s64), [[I64:%[0-9]+]](s64), [[I32:%[0-9]+]](s32) = G_EXTRACT [[VAL]](s192), 0, 64, 128

; CHECK: [[DBL:%[0-9]+]](s64) = G_EXTRACT [[VAL]](s192), 0
; CHECK: [[I64:%[0-9]+]](s64) = G_EXTRACT [[VAL]](s192), 64
; CHECK: [[I32:%[0-9]+]](s32) = G_EXTRACT [[VAL]](s192), 128

; CHECK: %d0 = COPY [[DBL]](s64)
; CHECK: %x0 = COPY [[I64]](s64)
; CHECK: %w1 = COPY [[I32]](s32)
Expand All @@ -87,7 +97,12 @@ define {double, i64, i32} @test_struct_return({double, i64, i32}* %addr) {

; CHECK-LABEL: name: test_arr_call
; CHECK: [[ARG:%[0-9]+]](s256) = G_LOAD
; CHECK: [[E0:%[0-9]+]](s64), [[E1:%[0-9]+]](s64), [[E2:%[0-9]+]](s64), [[E3:%[0-9]+]](s64) = G_EXTRACT [[ARG]](s256), 0, 64, 128, 192

; CHECK: [[E0:%[0-9]+]](s64) = G_EXTRACT [[ARG]](s256), 0
; CHECK: [[E1:%[0-9]+]](s64) = G_EXTRACT [[ARG]](s256), 64
; CHECK: [[E2:%[0-9]+]](s64) = G_EXTRACT [[ARG]](s256), 128
; CHECK: [[E3:%[0-9]+]](s64) = G_EXTRACT [[ARG]](s256), 192

; CHECK: %x0 = COPY [[E0]](s64)
; CHECK: %x1 = COPY [[E1]](s64)
; CHECK: %x2 = COPY [[E2]](s64)
Expand Down
3 changes: 2 additions & 1 deletion test/CodeGen/AArch64/GlobalISel/irtranslator-exceptions.ll
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,8 @@ declare i32 @llvm.eh.typeid.for(i8*)
; CHECK: [[SEL_PTR:%[0-9]+]](p0) = COPY %x1
; CHECK: [[SEL:%[0-9]+]](s32) = G_PTRTOINT [[SEL_PTR]]
; CHECK: [[PTR_SEL:%[0-9]+]](s128) = G_SEQUENCE [[PTR]](p0), 0, [[SEL]](s32), 64
; CHECK: [[PTR_RET:%[0-9]+]](s64), [[SEL_RET:%[0-9]+]](s32) = G_EXTRACT [[PTR_SEL]](s128), 0, 64
; CHECK: [[PTR_RET:%[0-9]+]](s64) = G_EXTRACT [[PTR_SEL]](s128), 0
; CHECK: [[SEL_RET:%[0-9]+]](s32) = G_EXTRACT [[PTR_SEL]](s128), 64
; CHECK: %x0 = COPY [[PTR_RET]]
; CHECK: %w1 = COPY [[SEL_RET]]

Expand Down
3 changes: 2 additions & 1 deletion test/CodeGen/AArch64/GlobalISel/legalize-combines.mir
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,8 @@ body: |
; CHECK: %5(s32) = G_ADD %0, %1
%1:_(s32) = G_ADD %0, %0
%2:_(s64) = G_SEQUENCE %0, 0, %1, 32
%3:_(s32), %4:_(s32) = G_EXTRACT %2, 0, 32
%3:_(s32) = G_EXTRACT %2, 0
%4:_(s32) = G_EXTRACT %2, 32
%5:_(s32) = G_ADD %3, %4
...

Expand Down
6 changes: 4 additions & 2 deletions test/CodeGen/ARM/GlobalISel/arm-instruction-select.mir
Original file line number Diff line number Diff line change
Expand Up @@ -515,8 +515,10 @@ body: |
%2(s64) = G_SEQUENCE %0(s32), 0, %1(s32), 1
; CHECK: %[[DREG]] = VMOVDRR [[IN1]], [[IN2]]
%3(s32), %4(s32) = G_EXTRACT %2(s64), 0, 32
; CHECK: [[OUT1:%[0-9]+]], [[OUT2:%[0-9]+]] = VMOVRRD %[[DREG]]
%3(s32) = G_EXTRACT %2(s64), 0
%4(s32) = G_EXTRACT %2(s64), 32
; CHECK: [[OUT1:%[0-9]+]] = VGETLNi32 %[[DREG]], 0
; CHECK: [[OUT2:%[0-9]+]] = VGETLNi32 %[[DREG]], 1
%r0 = COPY %3
; CHECK: %r0 = COPY [[OUT1]]
Expand Down
Loading

0 comments on commit 2c87ca8

Please sign in to comment.