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) { ...@@ -469,6 +469,16 @@ void AssemblerMIPS32::c_un_s(const Operand *OpFs, const Operand *OpFt) {
"c.un.s"); "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) { void AssemblerMIPS32::cvt_d_l(const Operand *OpFd, const Operand *OpFs) {
static constexpr IValueT Opcode = 0x44000021; static constexpr IValueT Opcode = 0x44000021;
emitCOP1FmtFsFd(Opcode, Long, OpFd, OpFs, "cvt.d.l"); emitCOP1FmtFsFd(Opcode, Long, OpFd, OpFs, "cvt.d.l");
...@@ -612,6 +622,12 @@ void AssemblerMIPS32::movf(const Operand *OpRd, const Operand *OpRs, ...@@ -612,6 +622,12 @@ void AssemblerMIPS32::movf(const Operand *OpRd, const Operand *OpRs,
emitInst(Opcode); 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, void AssemblerMIPS32::movn_d(const Operand *OpFd, const Operand *OpFs,
const Operand *OpFt) { const Operand *OpFt) {
static constexpr IValueT Opcode = 0x44000013; static constexpr IValueT Opcode = 0x44000013;
......
...@@ -140,6 +140,8 @@ public: ...@@ -140,6 +140,8 @@ public:
void c_un_s(const Operand *OpFd, const Operand *OpFs); 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_l(const Operand *OpFd, const Operand *OpFs);
void cvt_d_s(const Operand *OpFd, const Operand *OpFs); void cvt_d_s(const Operand *OpFd, const Operand *OpFs);
...@@ -168,6 +170,8 @@ public: ...@@ -168,6 +170,8 @@ public:
void movf(const Operand *OpRd, const Operand *OpRs, const Operand *OpCc); 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_d(const Operand *OpFd, const Operand *OpFs, const Operand *OpFt);
void movn_s(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"; ...@@ -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_ult_s::Opcode = "c.ult.s";
template <> const char *InstMIPS32C_un_d::Opcode = "c.un.d"; template <> const char *InstMIPS32C_un_d::Opcode = "c.un.d";
template <> const char *InstMIPS32C_un_s::Opcode = "c.un.s"; 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_l::Opcode = "cvt.d.l";
template <> const char *InstMIPS32Cvt_d_s::Opcode = "cvt.d.s"; template <> const char *InstMIPS32Cvt_d_s::Opcode = "cvt.d.s";
template <> const char *InstMIPS32Cvt_d_w::Opcode = "cvt.d.w"; template <> const char *InstMIPS32Cvt_d_w::Opcode = "cvt.d.w";
...@@ -854,6 +855,11 @@ template <> void InstMIPS32C_un_s::emitIAS(const Cfg *Func) const { ...@@ -854,6 +855,11 @@ template <> void InstMIPS32C_un_s::emitIAS(const Cfg *Func) const {
Asm->c_un_s(getSrc(0), getSrc(1)); 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 { template <> void InstMIPS32Cvt_d_l::emitIAS(const Cfg *Func) const {
auto *Asm = Func->getAssembler<MIPS32::AssemblerMIPS32>(); auto *Asm = Func->getAssembler<MIPS32::AssemblerMIPS32>();
Asm->cvt_d_l(getDest(), getSrc(0)); Asm->cvt_d_l(getDest(), getSrc(0));
...@@ -934,6 +940,11 @@ template <> void InstMIPS32Movf::emitIAS(const Cfg *Func) const { ...@@ -934,6 +940,11 @@ template <> void InstMIPS32Movf::emitIAS(const Cfg *Func) const {
Asm->movf(getDest(), getSrc(1), getSrc(2)); 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 { template <> void InstMIPS32Movn_d::emitIAS(const Cfg *Func) const {
auto *Asm = Func->getAssembler<MIPS32::AssemblerMIPS32>(); auto *Asm = Func->getAssembler<MIPS32::AssemblerMIPS32>();
Asm->movn_d(getDest(), getSrc(0), getSrc(1)); Asm->movn_d(getDest(), getSrc(0), getSrc(1));
......
...@@ -209,6 +209,7 @@ public: ...@@ -209,6 +209,7 @@ public:
C_un_d, C_un_d,
C_un_s, C_un_s,
Call, Call,
Clz,
Cvt_d_l, Cvt_d_l,
Cvt_d_s, Cvt_d_s,
Cvt_d_w, Cvt_d_w,
...@@ -1126,6 +1127,7 @@ using InstMIPS32C_ult_d = InstMIPS32FPCmp<InstMIPS32::C_ult_d>; ...@@ -1126,6 +1127,7 @@ using InstMIPS32C_ult_d = InstMIPS32FPCmp<InstMIPS32::C_ult_d>;
using InstMIPS32C_ult_s = InstMIPS32FPCmp<InstMIPS32::C_ult_s>; using InstMIPS32C_ult_s = InstMIPS32FPCmp<InstMIPS32::C_ult_s>;
using InstMIPS32C_un_d = InstMIPS32FPCmp<InstMIPS32::C_un_d>; using InstMIPS32C_un_d = InstMIPS32FPCmp<InstMIPS32::C_un_d>;
using InstMIPS32C_un_s = InstMIPS32FPCmp<InstMIPS32::C_un_s>; 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_s = InstMIPS32TwoAddrFPR<InstMIPS32::Cvt_d_s>;
using InstMIPS32Cvt_d_l = InstMIPS32TwoAddrFPR<InstMIPS32::Cvt_d_l>; using InstMIPS32Cvt_d_l = InstMIPS32TwoAddrFPR<InstMIPS32::Cvt_d_l>;
using InstMIPS32Cvt_d_w = InstMIPS32TwoAddrFPR<InstMIPS32::Cvt_d_w>; using InstMIPS32Cvt_d_w = InstMIPS32TwoAddrFPR<InstMIPS32::Cvt_d_w>;
...@@ -1258,6 +1260,7 @@ template <> void InstMIPS32C_ult_d::emitIAS(const Cfg *Func) const; ...@@ -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_ult_s::emitIAS(const Cfg *Func) const;
template <> void InstMIPS32C_un_d::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 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_l::emitIAS(const Cfg *Func) const;
template <> void InstMIPS32Cvt_d_s::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; template <> void InstMIPS32Cvt_d_w::emitIAS(const Cfg *Func) const;
...@@ -1274,6 +1277,7 @@ template <> void InstMIPS32Mfhi::emit(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_d::emitIAS(const Cfg *Func) const;
template <> void InstMIPS32Mov_s::emitIAS(const Cfg *Func) const; template <> void InstMIPS32Mov_s::emitIAS(const Cfg *Func) const;
template <> void InstMIPS32Movf::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_d::emitIAS(const Cfg *Func) const;
template <> void InstMIPS32Movn_s::emitIAS(const Cfg *Func) const; template <> void InstMIPS32Movn_s::emitIAS(const Cfg *Func) const;
template <> void InstMIPS32Movt::emitIAS(const Cfg *Func) const; template <> void InstMIPS32Movt::emitIAS(const Cfg *Func) const;
......
...@@ -2846,8 +2846,25 @@ void TargetMIPS32::lowerIntrinsicCall(const InstIntrinsicCall *Instr) { ...@@ -2846,8 +2846,25 @@ void TargetMIPS32::lowerIntrinsicCall(const InstIntrinsicCall *Instr) {
return; return;
} }
case Intrinsics::Ctlz: { case Intrinsics::Ctlz: {
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); UnimplementedLoweringError(this, Instr);
return; break;
}
default:
llvm::report_fatal_error("Control flow should never have reached here.");
}
break;
} }
case Intrinsics::Cttz: { case Intrinsics::Cttz: {
UnimplementedLoweringError(this, Instr); UnimplementedLoweringError(this, Instr);
......
...@@ -264,6 +264,10 @@ public: ...@@ -264,6 +264,10 @@ public:
Context.insert<InstMIPS32C_un_s>(Src0, Src1); 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) { void _cvt_d_l(Variable *Dest, Variable *Src) {
Context.insert<InstMIPS32Cvt_d_l>(Dest, 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: ...@@ -403,6 +403,8 @@ entry:
; CHECK: xor [[REG_RES]],0x1f ; CHECK: xor [[REG_RES]],0x1f
; ARM32-LABEL: test_ctlz_32 ; ARM32-LABEL: test_ctlz_32
; ARM32: clz ; ARM32: clz
; MIPS32-LABEL: test_ctlz_32
; MIPS32: clz
define internal i32 @test_ctlz_32_const() { define internal i32 @test_ctlz_32_const() {
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