OSDN Git Service

Subzero, MIPS32: Intrinsic call Ctlz for i32
authorSrdjan Obucina <Srdjan.Obucina@imgtec.com>
Thu, 22 Sep 2016 19:56:12 +0000 (12:56 -0700)
committerJim Stichnoth <stichnot@chromium.org>
Thu, 22 Sep 2016 19:56:12 +0000 (12:56 -0700)
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>.

src/IceAssemblerMIPS32.cpp
src/IceAssemblerMIPS32.h
src/IceInstMIPS32.cpp
src/IceInstMIPS32.h
src/IceTargetLoweringMIPS32.cpp
src/IceTargetLoweringMIPS32.h
tests_lit/assembler/mips32/encoding_intrinsics.ll [new file with mode: 0644]
tests_lit/llvm2ice_tests/nacl-other-intrinsics.ll

index 633e4e7..ac2d10b 100644 (file)
@@ -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;
index c987790..7fa863c 100644 (file)
@@ -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);
index 5006f8f..7326516 100644 (file)
@@ -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));
index 23a556a..2d86564 100644 (file)
@@ -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;
index 32656ce..f61ba8a 100644 (file)
@@ -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);
index 04368dc..8c23775 100644 (file)
@@ -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);
   }
diff --git a/tests_lit/assembler/mips32/encoding_intrinsics.ll b/tests_lit/assembler/mips32/encoding_intrinsics.ll
new file mode 100644 (file)
index 0000000..8b6d3a1
--- /dev/null
@@ -0,0 +1,76 @@
+; 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
index 0408d3d..bb1e1dc 100644 (file)
@@ -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: