[Legalizer] Add support for G_OR NarrowScalar.

Legalize bitwise OR:
 A = BinOp<Ty> B, C
into:
 B1, ..., BN = G_UNMERGE_VALUES B
 C1, ..., CN = G_UNMERGE_VALUES C
 A1 = BinOp<Ty/N> B1, C2
 ...
 AN = BinOp<Ty/N> BN, CN
 A = G_MERGE_VALUES A1, ..., AN

llvm-svn: 314760
This commit is contained in:
Quentin Colombet 2017-10-03 04:53:56 +00:00
parent 0c11fe123a
commit 69c337e7d0
3 changed files with 93 additions and 11 deletions

View File

@ -396,6 +396,50 @@ LegalizerHelper::LegalizeResult LegalizerHelper::narrowScalar(MachineInstr &MI,
MI.eraseFromParent(); MI.eraseFromParent();
return Legalized; return Legalized;
} }
case TargetOpcode::G_OR: {
// Legalize bitwise operation:
// A = BinOp<Ty> B, C
// into:
// B1, ..., BN = G_UNMERGE_VALUES B
// C1, ..., CN = G_UNMERGE_VALUES C
// A1 = BinOp<Ty/N> B1, C2
// ...
// AN = BinOp<Ty/N> BN, CN
// A = G_MERGE_VALUES A1, ..., AN
unsigned NarrowSize = NarrowTy.getSizeInBits();
int NumParts =
MRI.getType(MI.getOperand(0).getReg()).getSizeInBits() / NarrowSize;
// List the registers where the destination will be scattered.
SmallVector<unsigned, 2> DstRegs;
// List the registers where the first argument will be split.
SmallVector<unsigned, 2> SrcsReg1;
// List the registers where the second argument will be split.
SmallVector<unsigned, 2> SrcsReg2;
// Create all the temporary registers.
for (int i = 0; i < NumParts; ++i) {
unsigned DstReg = MRI.createGenericVirtualRegister(NarrowTy);
unsigned SrcReg1 = MRI.createGenericVirtualRegister(NarrowTy);
unsigned SrcReg2 = MRI.createGenericVirtualRegister(NarrowTy);
DstRegs.push_back(DstReg);
SrcsReg1.push_back(SrcReg1);
SrcsReg2.push_back(SrcReg2);
}
// Explode the big arguments into smaller chunks.
MIRBuilder.buildUnmerge(SrcsReg1, MI.getOperand(1).getReg());
MIRBuilder.buildUnmerge(SrcsReg2, MI.getOperand(2).getReg());
// Do the operation on each small part.
for (int i = 0; i < NumParts; ++i)
MIRBuilder.buildOr(DstRegs[i], SrcsReg1[i], SrcsReg2[i]);
// Gather the destination registers into the final destination.
unsigned DstReg = MI.getOperand(0).getReg();
MIRBuilder.buildMerge(DstReg, DstRegs);
MI.eraseFromParent();
return Legalized;
}
} }
} }

View File

@ -48,6 +48,7 @@ LegalizerInfo::LegalizerInfo() {
DefaultActions[TargetOpcode::G_ADD] = NarrowScalar; DefaultActions[TargetOpcode::G_ADD] = NarrowScalar;
DefaultActions[TargetOpcode::G_LOAD] = NarrowScalar; DefaultActions[TargetOpcode::G_LOAD] = NarrowScalar;
DefaultActions[TargetOpcode::G_STORE] = NarrowScalar; DefaultActions[TargetOpcode::G_STORE] = NarrowScalar;
DefaultActions[TargetOpcode::G_OR] = NarrowScalar;
DefaultActions[TargetOpcode::G_BRCOND] = WidenScalar; DefaultActions[TargetOpcode::G_BRCOND] = WidenScalar;
DefaultActions[TargetOpcode::G_INSERT] = NarrowScalar; DefaultActions[TargetOpcode::G_INSERT] = NarrowScalar;

View File

@ -1,13 +1,4 @@
# RUN: llc -O0 -run-pass=legalizer -global-isel %s -o - | FileCheck %s # RUN: llc -O0 -mtriple=aarch64-apple-ios -run-pass=legalizer -global-isel %s -o - | FileCheck %s
--- |
target datalayout = "e-m:o-i64:64-i128:128-n32:64-S128"
target triple = "aarch64--"
define void @test_scalar_or_small() {
entry:
ret void
}
...
--- ---
name: test_scalar_or_small name: test_scalar_or_small
@ -19,7 +10,7 @@ registers:
- { id: 4, class: _ } - { id: 4, class: _ }
- { id: 5, class: _ } - { id: 5, class: _ }
body: | body: |
bb.0.entry: bb.0:
liveins: %x0, %x1, %x2, %x3 liveins: %x0, %x1, %x2, %x3
; CHECK-LABEL: name: test_scalar_or_small ; CHECK-LABEL: name: test_scalar_or_small
; CHECK: [[OP0:%.*]](s32) = G_TRUNC %0 ; CHECK: [[OP0:%.*]](s32) = G_TRUNC %0
@ -35,3 +26,49 @@ body: |
%5(s64) = G_ANYEXT %2 %5(s64) = G_ANYEXT %2
%x0 = COPY %5 %x0 = COPY %5
... ...
---
name: test_big_scalar_power_of_2
registers:
- { id: 0, class: _ }
- { id: 1, class: _ }
- { id: 2, class: _ }
- { id: 3, class: _ }
- { id: 4, class: _ }
- { id: 5, class: _ }
- { id: 6, class: _ }
- { id: 7, class: _ }
- { id: 8, class: _ }
body: |
bb.0:
liveins: %x0, %x1, %x2, %x3
; CHECK-LABEL: name: test_big_scalar_power_of_2
; CHECK: [[OP0_0:%.*]](s64) = COPY %x0
; CHECK-NEXT: [[OP0_1:%.*]](s64) = COPY %x1
; CHECK-NEXT: [[OP1_0:%.*]](s64) = COPY %x2
; CHECK-NEXT: [[OP1_1:%.*]](s64) = COPY %x3
; CHECK-NEXT: [[RES_0:%.*]](s64) = G_OR [[OP0_0]], [[OP1_0]]
; CHECK-NEXT: [[RES_1:%.*]](s64) = G_OR [[OP0_1]], [[OP1_1]]
; We have a temporary G_MERGE_VALUES in the legalizer
; that gets cleaned up with the G_UNMERGE_VALUES.
; Thus,
; tmp = G_MERGE_VALUES [[RES_0]], [[RES_1]]
; %7, %8 = G_UNMERGE_VALUES tmp
; %x0 = COPY %7
; %x1 = COPY %8
; translates into
; CHECK-NEXT: %x0 = COPY [[RES_0]]
; CHECK-NEXT: %x1 = COPY [[RES_1]]
%0(s64) = COPY %x0
%1(s64) = COPY %x1
%2(s64) = COPY %x2
%3(s64) = COPY %x3
%4(s128) = G_MERGE_VALUES %0, %1
%5(s128) = G_MERGE_VALUES %2, %3
%6(s128) = G_OR %4, %5
%7(s64), %8(s64) = G_UNMERGE_VALUES %6
%x0 = COPY %7
%x1 = COPY %8
RET_ReallyLR implicit %x0, implicit %x1
...