Commit 0a7f99d9 by Srdjan Obucina Committed by Jim Stichnoth

Subzero, MIPS32: Intrinsic call Cttz for i32

Implements intrinsic call llvm.cttz for i32 R=stichnot@chromium.org Review URL: https://codereview.chromium.org/2358393004 . Patch from Srdjan Obucina <Srdjan.Obucina@imgtec.com>.
parent 6ee373fc
...@@ -777,6 +777,12 @@ void AssemblerMIPS32::sub_s(const Operand *OpFd, const Operand *OpFs, ...@@ -777,6 +777,12 @@ void AssemblerMIPS32::sub_s(const Operand *OpFd, const Operand *OpFs,
emitCOP1FmtFtFsFd(Opcode, SinglePrecision, OpFd, OpFs, OpFt, "sub.s"); emitCOP1FmtFtFsFd(Opcode, SinglePrecision, OpFd, OpFs, OpFt, "sub.s");
} }
void AssemblerMIPS32::subu(const Operand *OpRd, const Operand *OpRs,
const Operand *OpRt) {
static constexpr IValueT Opcode = 0x00000023;
emitRdRsRt(Opcode, OpRd, OpRs, OpRt, "subu");
}
void AssemblerMIPS32::sw(const Operand *OpRt, const Operand *OpBase, void AssemblerMIPS32::sw(const Operand *OpRt, const Operand *OpBase,
const uint32_t Offset) { const uint32_t Offset) {
switch (OpRt->getType()) { switch (OpRt->getType()) {
......
...@@ -218,6 +218,8 @@ public: ...@@ -218,6 +218,8 @@ public:
void sub_s(const Operand *OpFd, const Operand *OpFs, const Operand *OpFt); void sub_s(const Operand *OpFd, const Operand *OpFs, const Operand *OpFt);
void subu(const Operand *OpRd, const Operand *OpRs, const Operand *OpRt);
void sw(const Operand *OpRt, const Operand *OpBase, const uint32_t Offset); void sw(const Operand *OpRt, const Operand *OpBase, const uint32_t Offset);
void teq(const Operand *OpRs, const Operand *OpRt, const uint32_t TrapCode); void teq(const Operand *OpRs, const Operand *OpRt, const uint32_t TrapCode);
......
...@@ -1079,6 +1079,11 @@ template <> void InstMIPS32Sub_s::emitIAS(const Cfg *Func) const { ...@@ -1079,6 +1079,11 @@ template <> void InstMIPS32Sub_s::emitIAS(const Cfg *Func) const {
Asm->sub_s(getDest(), getSrc(0), getSrc(1)); Asm->sub_s(getDest(), getSrc(0), getSrc(1));
} }
template <> void InstMIPS32Subu::emitIAS(const Cfg *Func) const {
auto *Asm = Func->getAssembler<MIPS32::AssemblerMIPS32>();
Asm->subu(getDest(), getSrc(0), getSrc(1));
}
template <> void InstMIPS32Sw::emitIAS(const Cfg *Func) const { template <> void InstMIPS32Sw::emitIAS(const Cfg *Func) const {
auto *Asm = Func->getAssembler<MIPS32::AssemblerMIPS32>(); auto *Asm = Func->getAssembler<MIPS32::AssemblerMIPS32>();
auto *Mem = llvm::dyn_cast<OperandMIPS32Mem>(getSrc(1)); auto *Mem = llvm::dyn_cast<OperandMIPS32Mem>(getSrc(1));
......
...@@ -1305,6 +1305,7 @@ template <> void InstMIPS32Sra::emitIAS(const Cfg *Func) const; ...@@ -1305,6 +1305,7 @@ template <> void InstMIPS32Sra::emitIAS(const Cfg *Func) const;
template <> void InstMIPS32Srl::emitIAS(const Cfg *Func) const; template <> void InstMIPS32Srl::emitIAS(const Cfg *Func) const;
template <> void InstMIPS32Sub_d::emitIAS(const Cfg *Func) const; template <> void InstMIPS32Sub_d::emitIAS(const Cfg *Func) const;
template <> void InstMIPS32Sub_s::emitIAS(const Cfg *Func) const; template <> void InstMIPS32Sub_s::emitIAS(const Cfg *Func) const;
template <> void InstMIPS32Subu::emitIAS(const Cfg *Func) const;
template <> void InstMIPS32Teq::emitIAS(const Cfg *Func) const; template <> void InstMIPS32Teq::emitIAS(const Cfg *Func) const;
template <> void InstMIPS32Trunc_l_d::emitIAS(const Cfg *Func) const; template <> void InstMIPS32Trunc_l_d::emitIAS(const Cfg *Func) const;
template <> void InstMIPS32Trunc_l_s::emitIAS(const Cfg *Func) const; template <> void InstMIPS32Trunc_l_s::emitIAS(const Cfg *Func) const;
......
...@@ -2867,7 +2867,34 @@ void TargetMIPS32::lowerIntrinsicCall(const InstIntrinsicCall *Instr) { ...@@ -2867,7 +2867,34 @@ void TargetMIPS32::lowerIntrinsicCall(const InstIntrinsicCall *Instr) {
break; break;
} }
case Intrinsics::Cttz: { case Intrinsics::Cttz: {
UnimplementedLoweringError(this, Instr); auto *Src = Instr->getArg(0);
const Type SrcTy = Src->getType();
assert(SrcTy == IceType_i32 || SrcTy == IceType_i64);
switch (SrcTy) {
case IceType_i32: {
auto *T1 = I32Reg();
auto *T2 = I32Reg();
auto *T3 = I32Reg();
auto *T4 = I32Reg();
auto *T5 = I32Reg();
auto *T6 = I32Reg();
auto *SrcR = legalizeToReg(Src);
_addiu(T1, SrcR, -1);
_not(T2, SrcR);
_and(T3, T2, T1);
_clz(T4, T3);
_addiu(T5, getZero(), 32);
_subu(T6, T5, T4);
_mov(Dest, T6);
break;
}
case IceType_i64: {
UnimplementedLoweringError(this, Instr);
break;
}
default:
llvm::report_fatal_error("Control flow should never have reached here.");
}
return; return;
} }
case Intrinsics::Fabs: { case Intrinsics::Fabs: {
...@@ -3367,7 +3394,8 @@ void TargetMIPS32::postLower() { ...@@ -3367,7 +3394,8 @@ void TargetMIPS32::postLower() {
return; return;
// TODO(rkotler): Find two-address non-SSA instructions where Dest==Src0, // TODO(rkotler): Find two-address non-SSA instructions where Dest==Src0,
// and set the IsDestRedefined flag to keep liveness analysis consistent. // and set the IsDestRedefined flag to keep liveness analysis consistent.
UnimplementedError(getFlags()); markRedefinitions();
Context.availabilityUpdate();
} }
void TargetMIPS32::makeRandomRegisterPermutation( void TargetMIPS32::makeRandomRegisterPermutation(
......
...@@ -23,6 +23,7 @@ ...@@ -23,6 +23,7 @@
; RUN: | FileCheck %s --check-prefix=DIS ; RUN: | FileCheck %s --check-prefix=DIS
declare i32 @llvm.ctlz.i32(i32, i1) declare i32 @llvm.ctlz.i32(i32, i1)
declare i32 @llvm.cttz.i32(i32, i1)
declare void @llvm.trap() declare void @llvm.trap()
define internal i32 @encCtlz32(i32 %x) { define internal i32 @encCtlz32(i32 %x) {
...@@ -57,6 +58,62 @@ entry: ...@@ -57,6 +58,62 @@ entry:
; IASM-NEXT: .byte 0xe0 ; IASM-NEXT: .byte 0xe0
; IASM-NEXT: .byte 0x3 ; IASM-NEXT: .byte 0x3
define internal i32 @encCttz32(i32 %x) {
entry:
%r = call i32 @llvm.cttz.i32(i32 %x, i1 false)
ret i32 %r
}
; ASM-LABEL: encCttz32
; ASM-NEXT: .LencCttz32$entry:
; ASM-NEXT: addiu $v0, $a0, -1
; ASM-NEXT: nor $a0, $a0, $zero
; ASM-NEXT: and $a0, $a0, $v0
; ASM-NEXT: clz $a0, $a0
; ASM-NEXT: addiu $v0, $zero, 32
; ASM-NEXT: subu $v0, $v0, $a0
; ASM-NEXT: jr $ra
; DIS-LABEL: 00000010 <encCttz32>:
; DIS-NEXT: 10: 2482ffff addiu v0,a0,-1
; DIS-NEXT: 14: 00802027 nor a0,a0,zero
; DIS-NEXT: 18: 00822024 and a0,a0,v0
; DIS-NEXT: 1c: 70842020 clz a0,a0
; DIS-NEXT: 20: 24020020 li v0,32
; DIS-NEXT: 24: 00441023 subu v0,v0,a0
; DIS-NEXT: 28: 03e00008 jr ra
; IASM-LABEL: encCttz32
; IASM-NEXT: .LencCttz32$entry:
; IASM-NEXT: .byte 0xff
; IASM-NEXT: .byte 0xff
; IASM-NEXT: .byte 0x82
; IASM-NEXT: .byte 0x24
; IASM-NEXT: .byte 0x27
; IASM-NEXT: .byte 0x20
; IASM-NEXT: .byte 0x80
; IASM-NEXT: .byte 0x0
; IASM-NEXT: .byte 0x24
; IASM-NEXT: .byte 0x20
; IASM-NEXT: .byte 0x82
; IASM-NEXT: .byte 0x0
; IASM-NEXT: .byte 0x20
; IASM-NEXT: .byte 0x20
; IASM-NEXT: .byte 0x84
; IASM-NEXT: .byte 0x70
; IASM-NEXT: .byte 0x20
; IASM-NEXT: .byte 0x0
; IASM-NEXT: .byte 0x2
; IASM-NEXT: .byte 0x24
; IASM-NEXT: .byte 0x23
; IASM-NEXT: .byte 0x10
; IASM-NEXT: .byte 0x44
; IASM-NEXT: .byte 0x0
; IASM-NEXT: .byte 0x8
; IASM-NEXT: .byte 0x0
; IASM-NEXT: .byte 0xe0
; IASM-NEXT: .byte 0x3
define internal void @encTrap() { define internal void @encTrap() {
unreachable unreachable
} }
...@@ -65,8 +122,8 @@ define internal void @encTrap() { ...@@ -65,8 +122,8 @@ define internal void @encTrap() {
; ASM-NEXT: .LencTrap$__0: ; ASM-NEXT: .LencTrap$__0:
; ASM-NEXT: teq $zero, $zero, 0 ; ASM-NEXT: teq $zero, $zero, 0
; DIS-LABEL: 00000010 <encTrap>: ; DIS-LABEL: 00000030 <encTrap>:
; DIS-NEXT: 10: 00000034 teq zero,zero ; DIS-NEXT: 30: 00000034 teq zero,zero
; IASM-LABEL: encTrap: ; IASM-LABEL: encTrap:
; IASM-NEXT: .LencTrap$__0: ; IASM-NEXT: .LencTrap$__0:
......
...@@ -484,6 +484,13 @@ entry: ...@@ -484,6 +484,13 @@ entry:
; ARM32-LABEL: test_cttz_32 ; ARM32-LABEL: test_cttz_32
; ARM32: rbit ; ARM32: rbit
; ARM32: clz ; ARM32: clz
; MIPS32-LABEL: test_cttz_32
; MIPS32: addiu
; MIPS32: nor
; MIPS32: and
; MIPS32: clz
; MIPS32: li
; MIPS32: subu
define internal i64 @test_cttz_64(i64 %x) { define internal i64 @test_cttz_64(i64 %x) {
entry: entry:
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment