"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");
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;
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);
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);
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";
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));
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));
C_un_d,
C_un_s,
Call,
+ Clz,
Cvt_d_l,
Cvt_d_s,
Cvt_d_w,
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>;
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;
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;
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);
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);
}
--- /dev/null
+; 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
; 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: