diff --git a/llvm/lib/Target/ARC/ARCExpandPseudos.cpp b/llvm/lib/Target/ARC/ARCExpandPseudos.cpp --- a/llvm/lib/Target/ARC/ARCExpandPseudos.cpp +++ b/llvm/lib/Target/ARC/ARCExpandPseudos.cpp @@ -35,8 +35,9 @@ StringRef getPassName() const override { return "ARC Expand Pseudos"; } private: - void ExpandStore(MachineFunction &, MachineBasicBlock::iterator); - void ExpandCTLZ(MachineFunction &, MachineBasicBlock::iterator); + void expandStore(MachineFunction &, MachineBasicBlock::iterator); + void expandCTLZ(MachineFunction &, MachineBasicBlock::iterator); + void expandCTTZ(MachineFunction &, MachineBasicBlock::iterator); const ARCInstrInfo *TII; }; @@ -58,7 +59,7 @@ } } -void ARCExpandPseudos::ExpandStore(MachineFunction &MF, +void ARCExpandPseudos::expandStore(MachineFunction &MF, MachineBasicBlock::iterator SII) { MachineInstr &SI = *SII; Register AddrReg = MF.getRegInfo().createVirtualRegister(&ARC::GPR32RegClass); @@ -75,7 +76,7 @@ SI.eraseFromParent(); } -void ARCExpandPseudos::ExpandCTLZ(MachineFunction &MF, +void ARCExpandPseudos::expandCTLZ(MachineFunction &MF, MachineBasicBlock::iterator MII) { // Expand: // %R2 = CTLZ %R0, %STATUS @@ -104,6 +105,29 @@ MI.eraseFromParent(); } +void ARCExpandPseudos::expandCTTZ(MachineFunction &MF, + MachineBasicBlock::iterator MII) { + // Expand: + // %R0 = CTTZ %R0, %STATUS + // To: + // %R0 = FFS_f_rr %R0, %STATUS + // %R0 = MOVcc_ru6 %R0, 32, pred:1, %STATUS + MachineInstr &MI = *MII; + const MachineOperand &Dest = MI.getOperand(0); + const MachineOperand &Src = MI.getOperand(1); + Register R = MF.getRegInfo().createVirtualRegister(&ARC::GPR32RegClass); + + BuildMI(*MI.getParent(), MI, MI.getDebugLoc(), TII->get(ARC::FFS_f_rr), R) + .add(Src); + BuildMI(*MI.getParent(), MI, MI.getDebugLoc(), TII->get(ARC::MOV_cc_ru6)) + .add(Dest) + .addImm(32) + .addImm(ARCCC::EQ) + .addReg(R); + + MI.eraseFromParent(); +} + bool ARCExpandPseudos::runOnMachineFunction(MachineFunction &MF) { const ARCSubtarget *STI = &MF.getSubtarget(); TII = STI->getInstrInfo(); @@ -116,11 +140,15 @@ case ARC::ST_FAR: case ARC::STH_FAR: case ARC::STB_FAR: - ExpandStore(MF, MBBI); + expandStore(MF, MBBI); Expanded = true; break; case ARC::CTLZ: - ExpandCTLZ(MF, MBBI); + expandCTLZ(MF, MBBI); + Expanded = true; + break; + case ARC::CTTZ: + expandCTTZ(MF, MBBI); Expanded = true; break; default: diff --git a/llvm/lib/Target/ARC/ARCISelLowering.cpp b/llvm/lib/Target/ARC/ARCISelLowering.cpp --- a/llvm/lib/Target/ARC/ARCISelLowering.cpp +++ b/llvm/lib/Target/ARC/ARCISelLowering.cpp @@ -136,9 +136,10 @@ // Sign extend inreg setOperationAction(ISD::SIGN_EXTEND_INREG, MVT::i1, Custom); - // TODO: Predicate with `options.hasBitScan() ? Legal : Expand` when - // the HasBitScan predicate is available. + // TODO: Predicate these with `options.hasBitScan() ? Legal : Expand` + // when the HasBitScan predicate is available. setOperationAction(ISD::CTLZ, MVT::i32, Legal); + setOperationAction(ISD::CTTZ, MVT::i32, Legal); } const char *ARCTargetLowering::getTargetNodeName(unsigned Opcode) const { diff --git a/llvm/lib/Target/ARC/ARCInstrInfo.td b/llvm/lib/Target/ARC/ARCInstrInfo.td --- a/llvm/lib/Target/ARC/ARCInstrInfo.td +++ b/llvm/lib/Target/ARC/ARCInstrInfo.td @@ -133,12 +133,17 @@ "STB_FAR $dst, $addr", [(truncstorei8 GPR32:$dst, AddrModeFar:$addr)]>; -// TODO: Add `Requires<[HasBitScan]>` predicate when available. -def CTLZ : PseudoInstARC<(outs GPR32:$A), - (ins GPR32:$B), - "error.fls $A, $B", - [(set GPR32:$A, (ctlz i32:$B))]> { - let Defs = [STATUS32]; +// TODO: Add `Requires<[HasBitScan]>` predicate to these when available. +let Defs = [STATUS32] in { + def CTLZ : PseudoInstARC<(outs GPR32:$A), + (ins GPR32:$B), + "error.fls $A, $B", + [(set GPR32:$A, (ctlz i32:$B))]>; + + def CTTZ : PseudoInstARC<(outs GPR32:$A), + (ins GPR32:$B), + "error.ffs $A, $B", + [(set GPR32:$A, (cttz i32:$B))]>; } //===----------------------------------------------------------------------===// @@ -314,6 +319,7 @@ defm SEXH : ArcUnaryGEN4Inst<0b000110, "sexh">; // Extension unary instruction definitions. +defm FFS : ArcUnaryEXT5Inst<0b010010, "ffs">; defm FLS : ArcUnaryEXT5Inst<0b010011, "fls">; let Predicates=[HasNorm] in { diff --git a/llvm/test/CodeGen/ARC/ctlz.ll b/llvm/test/CodeGen/ARC/intrinsics.ll rename from llvm/test/CodeGen/ARC/ctlz.ll rename to llvm/test/CodeGen/ARC/intrinsics.ll --- a/llvm/test/CodeGen/ARC/ctlz.ll +++ b/llvm/test/CodeGen/ARC/intrinsics.ll @@ -3,6 +3,7 @@ target triple = "arc" declare i32 @llvm.ctlz.i32(i32, i1) +declare i32 @llvm.cttz.i32(i32, i1) ; CHECK-LABEL: clz32: ; CHECK: fls.f %r0, %r0 @@ -12,3 +13,11 @@ %a = call i32 @llvm.ctlz.i32(i32 %x, i1 false) ret i32 %a } + +; CHECK-LABEL: ctz32: +; CHECK: ffs.f %r0, %r0 +; CHECK-NEXT: mov.eq %r0, 32 +define i32 @ctz32(i32 %x) { + %a = call i32 @llvm.cttz.i32(i32 %x, i1 false) + ret i32 %a +} diff --git a/llvm/test/MC/Disassembler/ARC/misc.txt b/llvm/test/MC/Disassembler/ARC/misc.txt --- a/llvm/test/MC/Disassembler/ARC/misc.txt +++ b/llvm/test/MC/Disassembler/ARC/misc.txt @@ -130,6 +130,18 @@ # CHECK: fls.f %r0, %r0 0x2f 0x28 0x13 0x80 +# CHECK: ffs %r0, %r0 +0x2f 0x28 0x12 0x00 + +# CHECK: ffs.f %r0, %r0 +0x2f 0x28 0x12 0x80 + +# CHECK: ffs %r15, %r15 +0x2f 0x2f 0xd2 0x13 + +# CHECK: ffs.f %r15, %r15 +0x2f 0x2f 0xd2 0x93 + # CHECK: norm %r22, %blink 0x2f 0x2e 0xc1 0x27