Index: clang/lib/Basic/Targets/ARC.h =================================================================== --- clang/lib/Basic/Targets/ARC.h +++ clang/lib/Basic/Targets/ARC.h @@ -67,6 +67,8 @@ } bool hasExtIntType() const override { return true; } + + bool isCLZForZeroUndef() const override { return false; } }; } // namespace targets Index: llvm/lib/Target/ARC/ARCExpandPseudos.cpp =================================================================== --- llvm/lib/Target/ARC/ARCExpandPseudos.cpp +++ llvm/lib/Target/ARC/ARCExpandPseudos.cpp @@ -13,6 +13,7 @@ #include "ARCInstrInfo.h" #include "ARCRegisterInfo.h" #include "ARCSubtarget.h" +#include "MCTargetDesc/ARCInfo.h" #include "llvm/ADT/Statistic.h" #include "llvm/CodeGen/MachineFunctionPass.h" #include "llvm/CodeGen/MachineInstrBuilder.h" @@ -35,6 +36,7 @@ private: void ExpandStore(MachineFunction &, MachineBasicBlock::iterator); + void ExpandCTLZ(MachineFunction &, MachineBasicBlock::iterator); const ARCInstrInfo *TII; }; @@ -73,10 +75,45 @@ SI.eraseFromParent(); } +void ARCExpandPseudos::ExpandCTLZ(MachineFunction &MF, + MachineBasicBlock::iterator SII) { + // Expand: + // %R2 = CTLZ %R0, %STATUS + // To: + // %R2 = FLS_f_rr %R0, %STATUS + // %R2 = MOV_cc_ru6 %R2, 32, pred:1, %STATUS + // %R2 = RSUB_cc_rru6 %R2, 31, pred:2, %STATUS + MachineInstr &SI = *SII; + const MachineOperand &Dest = SI.getOperand(0); + assert(Dest.isReg()); + const MachineOperand &Src = SI.getOperand(1); + assert(Src.isReg()); + unsigned DestReg = Dest.getReg(); + + BuildMI(*SI.getParent(), SI, SI.getDebugLoc(), TII->get(ARC::FLS_f_rr), + DestReg) + .add(Src) + .addReg(ARC::STATUS32, RegState::ImplicitDefine); + + unsigned Ra = MF.getRegInfo().createVirtualRegister(&ARC::GPR32RegClass); + unsigned Rb = MF.getRegInfo().createVirtualRegister(&ARC::GPR32RegClass); + BuildMI(*SI.getParent(), SI, SI.getDebugLoc(), TII->get(ARC::MOV_cc_ru6), Ra) + .addImm(32) + .addImm(ARCCC::EQ) + .addReg(DestReg); + BuildMI(*SI.getParent(), SI, SI.getDebugLoc(), TII->get(ARC::RSUB_cc_rru6), + Rb) + .addImm(31) + .addImm(ARCCC::NE) + .addReg(Ra); + + SI.eraseFromParent(); +} + bool ARCExpandPseudos::runOnMachineFunction(MachineFunction &MF) { const ARCSubtarget *STI = &MF.getSubtarget(); TII = STI->getInstrInfo(); - bool ExpandedStore = false; + bool Expanded = false; for (auto &MBB : MF) { MachineBasicBlock::iterator MBBI = MBB.begin(), E = MBB.end(); while (MBBI != E) { @@ -86,7 +123,11 @@ case ARC::STH_FAR: case ARC::STB_FAR: ExpandStore(MF, MBBI); - ExpandedStore = true; + Expanded = true; + break; + case ARC::CTLZ: + ExpandCTLZ(MF, MBBI); + Expanded = true; break; default: break; @@ -94,7 +135,7 @@ MBBI = NMBBI; } } - return ExpandedStore; + return Expanded; } FunctionPass *llvm::createARCExpandPseudosPass() { Index: llvm/lib/Target/ARC/ARCISelLowering.cpp =================================================================== --- llvm/lib/Target/ARC/ARCISelLowering.cpp +++ llvm/lib/Target/ARC/ARCISelLowering.cpp @@ -135,6 +135,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. + setOperationAction(ISD::CTLZ, MVT::i32, Legal); } const char *ARCTargetLowering::getTargetNodeName(unsigned Opcode) const { Index: llvm/lib/Target/ARC/ARCInstrInfo.td =================================================================== --- llvm/lib/Target/ARC/ARCInstrInfo.td +++ llvm/lib/Target/ARC/ARCInstrInfo.td @@ -133,6 +133,14 @@ "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]; +} + //===----------------------------------------------------------------------===// // Instruction Generation multiclasses. // Generate many variants of a single instruction with a single defining Index: llvm/test/CodeGen/ARC/ctlz.ll =================================================================== --- /dev/null +++ llvm/test/CodeGen/ARC/ctlz.ll @@ -0,0 +1,14 @@ +; RUN: llc -march=arc < %s | FileCheck %s + +target triple = "arc" + +declare i32 @llvm.ctlz.i32(i32, i1) + +; CHECK-LABEL: clz32: +; CHECK: fls.f %r0, %r0 +; CHECK: mov.eq [[R:%r[01]]], 32 +; CHECK: rsub.ne [[R]], [[R]], 31 +define i32 @clz32(i32 %x) { + %a = call i32 @llvm.ctlz.i32(i32 %x, i1 false) + ret i32 %a +}