Commit d27ce3d9 by Srdjan Obucina Committed by Jim Stichnoth

Subzero, MIPS32: Intrinsic call Ctlz for i32

Implements intrinsic call llvm.ctlz for i32 R=stichnot@chromium.org Review URL: https://codereview.chromium.org/2354293002 . Patch from Srdjan Obucina <Srdjan.Obucina@imgtec.com>.
parent cadda79e
......@@ -469,6 +469,16 @@ void AssemblerMIPS32::c_un_s(const Operand *OpFs, const Operand *OpFt) {
"c.un.s");
}
void AssemblerMIPS32::clz(const Operand *OpRd, const Operand *OpRs) {
IValueT Opcode = 0x70000020;
const IValueT Rd = encodeGPRegister(OpRd, "Rd", "clz");
const IValueT Rs = encodeGPRegister(OpRs, "Rs", "clz");
Opcode |= Rd << 11;
Opcode |= Rd << 16;
Opcode |= Rs << 21;
emitInst(Opcode);
}
void AssemblerMIPS32::cvt_d_l(const Operand *OpFd, const Operand *OpFs) {
static constexpr IValueT Opcode = 0x44000021;
emitCOP1FmtFsFd(Opcode, Long, OpFd, OpFs, "cvt.d.l");
......@@ -612,6 +622,12 @@ void AssemblerMIPS32::movf(const Operand *OpRd, const Operand *OpRs,
emitInst(Opcode);
}
void AssemblerMIPS32::movn(const Operand *OpRd, const Operand *OpRs,
const Operand *OpRt) {
static constexpr IValueT Opcode = 0x44000013;
emitRdRsRt(Opcode, OpRd, OpRs, OpRt, "movn");
}
void AssemblerMIPS32::movn_d(const Operand *OpFd, const Operand *OpFs,
const Operand *OpFt) {
static constexpr IValueT Opcode = 0x44000013;
......
......@@ -140,6 +140,8 @@ public:
void c_un_s(const Operand *OpFd, const Operand *OpFs);
void clz(const Operand *OpRd, const Operand *OpRs);
void cvt_d_l(const Operand *OpFd, const Operand *OpFs);
void cvt_d_s(const Operand *OpFd, const Operand *OpFs);
......@@ -168,6 +170,8 @@ public:
void movf(const Operand *OpRd, const Operand *OpRs, const Operand *OpCc);
void movn(const Operand *OpRd, const Operand *OpRs, const Operand *OpRt);
void movn_d(const Operand *OpFd, const Operand *OpFs, const Operand *OpFt);
void movn_s(const Operand *OpFd, const Operand *OpFs, const Operand *OpFt);
......
......@@ -83,6 +83,7 @@ template <> const char *InstMIPS32C_ult_d::Opcode = "c.ult.d";
template <> const char *InstMIPS32C_ult_s::Opcode = "c.ult.s";
template <> const char *InstMIPS32C_un_d::Opcode = "c.un.d";
template <> const char *InstMIPS32C_un_s::Opcode = "c.un.s";
template <> const char *InstMIPS32Clz::Opcode = "clz";
template <> const char *InstMIPS32Cvt_d_l::Opcode = "cvt.d.l";
template <> const char *InstMIPS32Cvt_d_s::Opcode = "cvt.d.s";
template <> const char *InstMIPS32Cvt_d_w::Opcode = "cvt.d.w";
......@@ -854,6 +855,11 @@ template <> void InstMIPS32C_un_s::emitIAS(const Cfg *Func) const {
Asm->c_un_s(getSrc(0), getSrc(1));
}
template <> void InstMIPS32Clz::emitIAS(const Cfg *Func) const {
auto *Asm = Func->getAssembler<MIPS32::AssemblerMIPS32>();
Asm->clz(getDest(), getSrc(0));
}
template <> void InstMIPS32Cvt_d_l::emitIAS(const Cfg *Func) const {
auto *Asm = Func->getAssembler<MIPS32::AssemblerMIPS32>();
Asm->cvt_d_l(getDest(), getSrc(0));
......@@ -934,6 +940,11 @@ template <> void InstMIPS32Movf::emitIAS(const Cfg *Func) const {
Asm->movf(getDest(), getSrc(1), getSrc(2));
}
template <> void InstMIPS32Movn::emitIAS(const Cfg *Func) const {
auto *Asm = Func->getAssembler<MIPS32::AssemblerMIPS32>();
Asm->movn(getDest(), getSrc(0), getSrc(1));
}
template <> void InstMIPS32Movn_d::emitIAS(const Cfg *Func) const {
auto *Asm = Func->getAssembler<MIPS32::AssemblerMIPS32>();
Asm->movn_d(getDest(), getSrc(0), getSrc(1));
......
......@@ -209,6 +209,7 @@ public:
C_un_d,
C_un_s,
Call,
Clz,
Cvt_d_l,
Cvt_d_s,
Cvt_d_w,
......@@ -1126,6 +1127,7 @@ using InstMIPS32C_ult_d = InstMIPS32FPCmp<InstMIPS32::C_ult_d>;
using InstMIPS32C_ult_s = InstMIPS32FPCmp<InstMIPS32::C_ult_s>;
using InstMIPS32C_un_d = InstMIPS32FPCmp<InstMIPS32::C_un_d>;
using InstMIPS32C_un_s = InstMIPS32FPCmp<InstMIPS32::C_un_s>;
using InstMIPS32Clz = InstMIPS32TwoAddrGPR<InstMIPS32::Clz>;
using InstMIPS32Cvt_d_s = InstMIPS32TwoAddrFPR<InstMIPS32::Cvt_d_s>;
using InstMIPS32Cvt_d_l = InstMIPS32TwoAddrFPR<InstMIPS32::Cvt_d_l>;
using InstMIPS32Cvt_d_w = InstMIPS32TwoAddrFPR<InstMIPS32::Cvt_d_w>;
......@@ -1258,6 +1260,7 @@ template <> void InstMIPS32C_ult_d::emitIAS(const Cfg *Func) const;
template <> void InstMIPS32C_ult_s::emitIAS(const Cfg *Func) const;
template <> void InstMIPS32C_un_d::emitIAS(const Cfg *Func) const;
template <> void InstMIPS32C_un_s::emitIAS(const Cfg *Func) const;
template <> void InstMIPS32Clz::emitIAS(const Cfg *Func) const;
template <> void InstMIPS32Cvt_d_l::emitIAS(const Cfg *Func) const;
template <> void InstMIPS32Cvt_d_s::emitIAS(const Cfg *Func) const;
template <> void InstMIPS32Cvt_d_w::emitIAS(const Cfg *Func) const;
......@@ -1274,6 +1277,7 @@ template <> void InstMIPS32Mfhi::emit(const Cfg *Func) const;
template <> void InstMIPS32Mov_d::emitIAS(const Cfg *Func) const;
template <> void InstMIPS32Mov_s::emitIAS(const Cfg *Func) const;
template <> void InstMIPS32Movf::emitIAS(const Cfg *Func) const;
template <> void InstMIPS32Movn::emitIAS(const Cfg *Func) const;
template <> void InstMIPS32Movn_d::emitIAS(const Cfg *Func) const;
template <> void InstMIPS32Movn_s::emitIAS(const Cfg *Func) const;
template <> void InstMIPS32Movt::emitIAS(const Cfg *Func) const;
......
......@@ -2846,8 +2846,25 @@ void TargetMIPS32::lowerIntrinsicCall(const InstIntrinsicCall *Instr) {
return;
}
case Intrinsics::Ctlz: {
UnimplementedLoweringError(this, Instr);
return;
auto *Src = Instr->getArg(0);
const Type SrcTy = Src->getType();
assert(SrcTy == IceType_i32 || SrcTy == IceType_i64);
switch (SrcTy) {
case IceType_i32: {
auto *T = I32Reg();
auto *SrcR = legalizeToReg(Src);
_clz(T, SrcR);
_mov(Dest, T);
break;
}
case IceType_i64: {
UnimplementedLoweringError(this, Instr);
break;
}
default:
llvm::report_fatal_error("Control flow should never have reached here.");
}
break;
}
case Intrinsics::Cttz: {
UnimplementedLoweringError(this, Instr);
......
......@@ -264,6 +264,10 @@ public:
Context.insert<InstMIPS32C_un_s>(Src0, Src1);
}
void _clz(Variable *Dest, Variable *Src) {
Context.insert<InstMIPS32Clz>(Dest, Src);
}
void _cvt_d_l(Variable *Dest, Variable *Src) {
Context.insert<InstMIPS32Cvt_d_l>(Dest, Src);
}
......
; Test encoding of MIPS32 instructions used in intrinsic calls
; REQUIRES: allow_dump
; Compile using standalone assembler.
; RUN: %p2i --filetype=asm -i %s --target=mips32 --args -O2 \
; RUN: --allow-externally-defined-symbols --skip-unimplemented \
; RUN: | FileCheck %s --check-prefix=ASM
; Show bytes in assembled standalone code.
; RUN: %p2i --filetype=asm -i %s --target=mips32 --assemble --disassemble \
; RUN: --args -O2 --allow-externally-defined-symbols --skip-unimplemented \
; RUN: | FileCheck %s --check-prefix=DIS
; Compile using integrated assembler.
; RUN: %p2i --filetype=iasm -i %s --target=mips32 --args -O2 \
; RUN: --allow-externally-defined-symbols --skip-unimplemented \
; RUN: | FileCheck %s --check-prefix=IASM
; Show bytes in assembled integrated code.
; RUN: %p2i --filetype=iasm -i %s --target=mips32 --assemble --disassemble \
; RUN: --args -O2 --allow-externally-defined-symbols --skip-unimplemented \
; RUN: | FileCheck %s --check-prefix=DIS
declare i32 @llvm.ctlz.i32(i32, i1)
declare void @llvm.trap()
define internal i32 @encCtlz32(i32 %x) {
entry:
%r = call i32 @llvm.ctlz.i32(i32 %x, i1 false)
ret i32 %r
}
; ASM-LABEL: encCtlz32
; ASM-NEXT: .LencCtlz32$entry:
; ASM-NEXT: clz $a0, $a0
; ASM-NEXT: move $v0, $a0
; ASM-NEXT: jr $ra
; DIS-LABEL: 00000000 <encCtlz32>:
; DIS-NEXT: 0: 70842020 clz a0,a0
; DIS-NEXT: 4: 00801021 move v0,a0
; DIS-NEXT: 8: 03e00008 jr ra
; IASM-LABEL: encCtlz32
; IASM-NEXT: .LencCtlz32$entry:
; IASM-NEXT: .byte 0x20
; IASM-NEXT: .byte 0x20
; IASM-NEXT: .byte 0x84
; IASM-NEXT: .byte 0x70
; IASM-NEXT: .byte 0x21
; IASM-NEXT: .byte 0x10
; IASM-NEXT: .byte 0x80
; IASM-NEXT: .byte 0x0
; IASM-NEXT: .byte 0x8
; IASM-NEXT: .byte 0x0
; IASM-NEXT: .byte 0xe0
; IASM-NEXT: .byte 0x3
define internal void @encTrap() {
unreachable
}
; ASM-LABEL: encTrap
; ASM-NEXT: .LencTrap$__0:
; ASM-NEXT: teq $zero, $zero, 0
; DIS-LABEL: 00000010 <encTrap>:
; DIS-NEXT: 10: 00000034 teq zero,zero
; IASM-LABEL: encTrap:
; IASM-NEXT: .LencTrap$__0:
; IASM-NEXT: .byte 0x34
; IASM-NEXT: .byte 0x0
; IASM-NEXT: .byte 0x0
; IASM-NEXT: .byte 0x0
......@@ -403,6 +403,8 @@ entry:
; CHECK: xor [[REG_RES]],0x1f
; ARM32-LABEL: test_ctlz_32
; ARM32: clz
; MIPS32-LABEL: test_ctlz_32
; MIPS32: clz
define internal i32 @test_ctlz_32_const() {
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