/// instruction). Extension operations more complicated than that should not
/// invoke this. Returns the original opcode if it doesn't know how to select a
/// better one.
-static unsigned selectSimpleExtOpc(unsigned Opc, unsigned Size) {
+static unsigned selectSimpleExtOpc(unsigned Opc, unsigned Size, bool isThumb) {
using namespace TargetOpcode;
if (Size != 8 && Size != 16)
return Opc;
if (Opc == G_SEXT)
- return Size == 8 ? ARM::SXTB : ARM::SXTH;
+ return isThumb ? Size == 8 ? ARM::t2SXTB : ARM::t2SXTH
+ : Size == 8 ? ARM::SXTB : ARM::SXTH;
if (Opc == G_ZEXT)
- return Size == 8 ? ARM::UXTB : ARM::UXTH;
+ return isThumb ? Size == 8 ? ARM::t2UXTB : ARM::t2UXTH
+ : Size == 8 ? ARM::UXTB : ARM::UXTH;
return Opc;
}
switch (SrcSize) {
case 1: {
// ZExt boils down to & 0x1; for SExt we also subtract that from 0
- I.setDesc(TII.get(ARM::ANDri));
+ I.setDesc(TII.get(STI.isThumb() ? ARM::t2ANDri : ARM::ANDri));
MIB.addImm(1).add(predOps(ARMCC::AL)).add(condCodeOp());
if (isSExt) {
I.getOperand(0).setReg(AndResult);
auto InsertBefore = std::next(I.getIterator());
- auto SubI =
- BuildMI(MBB, InsertBefore, I.getDebugLoc(), TII.get(ARM::RSBri))
- .addDef(SExtResult)
- .addUse(AndResult)
- .addImm(0)
- .add(predOps(ARMCC::AL))
- .add(condCodeOp());
+ auto SubI = BuildMI(MBB, InsertBefore, I.getDebugLoc(),
+ TII.get(STI.isThumb() ? ARM::t2RSBri : ARM::RSBri))
+ .addDef(SExtResult)
+ .addUse(AndResult)
+ .addImm(0)
+ .add(predOps(ARMCC::AL))
+ .add(condCodeOp());
if (!constrainSelectedInstRegOperands(*SubI, TII, TRI, RBI))
return false;
}
}
case 8:
case 16: {
- unsigned NewOpc = selectSimpleExtOpc(I.getOpcode(), SrcSize);
+ unsigned NewOpc =
+ selectSimpleExtOpc(I.getOpcode(), SrcSize, STI.isThumb());
if (NewOpc == I.getOpcode())
return false;
I.setDesc(TII.get(NewOpc));
--- /dev/null
+# RUN: llc -O0 -mtriple thumb-- -mattr=+v6t2 -run-pass=instruction-select -verify-machineinstrs %s -o - | FileCheck %s
+--- |
+ define void @test_trunc_and_zext_s1() { ret void }
+ define void @test_trunc_and_sext_s1() { ret void }
+ define void @test_trunc_and_anyext_s1() { ret void }
+
+ define void @test_trunc_and_zext_s8() { ret void }
+ define void @test_trunc_and_sext_s8() { ret void }
+ define void @test_trunc_and_anyext_s8() { ret void }
+
+ define void @test_trunc_and_zext_s16() { ret void }
+ define void @test_trunc_and_sext_s16() { ret void }
+ define void @test_trunc_and_anyext_s16() { ret void }
+...
+---
+name: test_trunc_and_zext_s1
+# CHECK-LABEL: name: test_trunc_and_zext_s1
+legalized: true
+regBankSelected: true
+selected: false
+# CHECK: selected: true
+tracksRegLiveness: true
+registers:
+ - { id: 0, class: gprb }
+ - { id: 1, class: gprb }
+ - { id: 2, class: gprb }
+body: |
+ bb.0:
+ liveins: $r0
+
+ %0(s32) = COPY $r0
+ ; CHECK: [[VREG:%[0-9]+]]:gpr = COPY $r0
+
+ %1(s1) = G_TRUNC %0(s32)
+
+ %2(s32) = G_ZEXT %1(s1)
+ ; CHECK: [[RVREG:%[0-9]+]]:rgpr = COPY [[VREG]]
+ ; CHECK: [[VREGEXT:%[0-9]+]]:rgpr = t2ANDri [[RVREG]], 1, 14, $noreg, $noreg
+
+ $r0 = COPY %2(s32)
+ ; CHECK: $r0 = COPY [[VREGEXT]]
+
+ BX_RET 14, $noreg, implicit $r0
+ ; CHECK: BX_RET 14, $noreg, implicit $r0
+...
+---
+name: test_trunc_and_sext_s1
+# CHECK-LABEL: name: test_trunc_and_sext_s1
+legalized: true
+regBankSelected: true
+selected: false
+# CHECK: selected: true
+tracksRegLiveness: true
+registers:
+ - { id: 0, class: gprb }
+ - { id: 1, class: gprb }
+ - { id: 2, class: gprb }
+body: |
+ bb.0:
+ liveins: $r0
+
+ %0(s32) = COPY $r0
+ ; CHECK: [[VREG:%[0-9]+]]:gpr = COPY $r0
+
+ %1(s1) = G_TRUNC %0(s32)
+
+ %2(s32) = G_SEXT %1(s1)
+ ; CHECK: [[RVREG:%[0-9]+]]:rgpr = COPY [[VREG]]
+ ; CHECK: [[VREGAND:%[0-9]+]]:rgpr = t2ANDri [[RVREG]], 1, 14, $noreg, $noreg
+ ; CHECK: [[VREGEXT:%[0-9]+]]:rgpr = t2RSBri [[VREGAND]], 0, 14, $noreg, $noreg
+
+ $r0 = COPY %2(s32)
+ ; CHECK: $r0 = COPY [[VREGEXT]]
+
+ BX_RET 14, $noreg, implicit $r0
+ ; CHECK: BX_RET 14, $noreg, implicit $r0
+...
+---
+name: test_trunc_and_anyext_s1
+# CHECK-LABEL: name: test_trunc_and_anyext_s1
+legalized: true
+regBankSelected: true
+selected: false
+# CHECK: selected: true
+tracksRegLiveness: true
+registers:
+ - { id: 0, class: gprb }
+ - { id: 1, class: gprb }
+ - { id: 2, class: gprb }
+body: |
+ bb.0:
+ liveins: $r0
+
+ %0(s32) = COPY $r0
+ ; CHECK: [[VREG:%[0-9]+]]:gpr = COPY $r0
+
+ %1(s1) = G_TRUNC %0(s32)
+
+ %2(s32) = G_ANYEXT %1(s1)
+
+ $r0 = COPY %2(s32)
+ ; CHECK: $r0 = COPY [[VREG]]
+
+ BX_RET 14, $noreg, implicit $r0
+ ; CHECK: BX_RET 14, $noreg, implicit $r0
+...
+---
+name: test_trunc_and_zext_s8
+# CHECK-LABEL: name: test_trunc_and_zext_s8
+legalized: true
+regBankSelected: true
+selected: false
+# CHECK: selected: true
+tracksRegLiveness: true
+registers:
+ - { id: 0, class: gprb }
+ - { id: 1, class: gprb }
+ - { id: 2, class: gprb }
+body: |
+ bb.0:
+ liveins: $r0
+
+ %0(s32) = COPY $r0
+ ; CHECK: [[VREG:%[0-9]+]]:gpr = COPY $r0
+
+ %1(s8) = G_TRUNC %0(s32)
+ ; CHECK: [[VREGTRUNC:%[0-9]+]]:rgpr = COPY [[VREG]]
+
+ %2(s32) = G_ZEXT %1(s8)
+ ; CHECK: [[VREGEXT:%[0-9]+]]:rgpr = t2UXTB [[VREGTRUNC]], 0, 14, $noreg
+
+ $r0 = COPY %2(s32)
+ ; CHECK: $r0 = COPY [[VREGEXT]]
+
+ BX_RET 14, $noreg, implicit $r0
+ ; CHECK: BX_RET 14, $noreg, implicit $r0
+...
+---
+name: test_trunc_and_sext_s8
+# CHECK-LABEL: name: test_trunc_and_sext_s8
+legalized: true
+regBankSelected: true
+selected: false
+# CHECK: selected: true
+tracksRegLiveness: true
+registers:
+ - { id: 0, class: gprb }
+ - { id: 1, class: gprb }
+ - { id: 2, class: gprb }
+body: |
+ bb.0:
+ liveins: $r0
+
+ %0(s32) = COPY $r0
+ ; CHECK: [[VREG:%[0-9]+]]:gpr = COPY $r0
+
+ %1(s8) = G_TRUNC %0(s32)
+ ; CHECK: [[VREGTRUNC:%[0-9]+]]:rgpr = COPY [[VREG]]
+
+ %2(s32) = G_SEXT %1(s8)
+ ; CHECK: [[VREGEXT:%[0-9]+]]:rgpr = t2SXTB [[VREGTRUNC]], 0, 14, $noreg
+
+ $r0 = COPY %2(s32)
+ ; CHECK: $r0 = COPY [[VREGEXT]]
+
+ BX_RET 14, $noreg, implicit $r0
+ ; CHECK: BX_RET 14, $noreg, implicit $r0
+...
+---
+name: test_trunc_and_anyext_s8
+# CHECK-LABEL: name: test_trunc_and_anyext_s8
+legalized: true
+regBankSelected: true
+selected: false
+# CHECK: selected: true
+tracksRegLiveness: true
+registers:
+ - { id: 0, class: gprb }
+ - { id: 1, class: gprb }
+ - { id: 2, class: gprb }
+body: |
+ bb.0:
+ liveins: $r0
+
+ %0(s32) = COPY $r0
+ ; CHECK: [[VREG:%[0-9]+]]:gpr = COPY $r0
+
+ %1(s8) = G_TRUNC %0(s32)
+
+ %2(s32) = G_ANYEXT %1(s8)
+
+ $r0 = COPY %2(s32)
+ ; CHECK: $r0 = COPY [[VREG]]
+
+ BX_RET 14, $noreg, implicit $r0
+ ; CHECK: BX_RET 14, $noreg, implicit $r0
+...
+---
+name: test_trunc_and_zext_s16
+# CHECK-LABEL: name: test_trunc_and_zext_s16
+legalized: true
+regBankSelected: true
+selected: false
+# CHECK: selected: true
+tracksRegLiveness: true
+registers:
+ - { id: 0, class: gprb }
+ - { id: 1, class: gprb }
+ - { id: 2, class: gprb }
+body: |
+ bb.0:
+ liveins: $r0
+
+ %0(s32) = COPY $r0
+ ; CHECK: [[VREG:%[0-9]+]]:gpr = COPY $r0
+
+ %1(s16) = G_TRUNC %0(s32)
+ ; CHECK: [[VREGTRUNC:%[0-9]+]]:rgpr = COPY [[VREG]]
+
+ %2(s32) = G_ZEXT %1(s16)
+ ; CHECK: [[VREGEXT:%[0-9]+]]:rgpr = t2UXTH [[VREGTRUNC]], 0, 14, $noreg
+
+ $r0 = COPY %2(s32)
+ ; CHECK: $r0 = COPY [[VREGEXT]]
+
+ BX_RET 14, $noreg, implicit $r0
+ ; CHECK: BX_RET 14, $noreg, implicit $r0
+...
+---
+name: test_trunc_and_sext_s16
+# CHECK-LABEL: name: test_trunc_and_sext_s16
+legalized: true
+regBankSelected: true
+selected: false
+# CHECK: selected: true
+tracksRegLiveness: true
+registers:
+ - { id: 0, class: gprb }
+ - { id: 1, class: gprb }
+ - { id: 2, class: gprb }
+body: |
+ bb.0:
+ liveins: $r0
+
+ %0(s32) = COPY $r0
+ ; CHECK: [[VREG:%[0-9]+]]:gpr = COPY $r0
+
+ %1(s16) = G_TRUNC %0(s32)
+ ; CHECK: [[VREGTRUNC:%[0-9]+]]:rgpr = COPY [[VREG]]
+
+ %2(s32) = G_SEXT %1(s16)
+ ; CHECK: [[VREGEXT:%[0-9]+]]:rgpr = t2SXTH [[VREGTRUNC]], 0, 14, $noreg
+
+ $r0 = COPY %2(s32)
+ ; CHECK: $r0 = COPY [[VREGEXT]]
+
+ BX_RET 14, $noreg, implicit $r0
+ ; CHECK: BX_RET 14, $noreg, implicit $r0
+...
+---
+name: test_trunc_and_anyext_s16
+# CHECK-LABEL: name: test_trunc_and_anyext_s16
+legalized: true
+regBankSelected: true
+selected: false
+# CHECK: selected: true
+tracksRegLiveness: true
+registers:
+ - { id: 0, class: gprb }
+ - { id: 1, class: gprb }
+ - { id: 2, class: gprb }
+body: |
+ bb.0:
+ liveins: $r0
+
+ %0(s32) = COPY $r0
+ ; CHECK: [[VREG:%[0-9]+]]:gpr = COPY $r0
+
+ %1(s16) = G_TRUNC %0(s32)
+
+ %2(s32) = G_ANYEXT %1(s16)
+
+ $r0 = COPY %2(s32)
+ ; CHECK: $r0 = COPY [[VREG]]
+
+ BX_RET 14, $noreg, implicit $r0
+ ; CHECK: BX_RET 14, $noreg, implicit $r0
+...