[Subzero][MIPS32] Implement sext, zext and trunc
This patch adds support for sext, zext, trunc operations on i8, i16, i32 source operand types. Support for i1 source operand type will follow.
R=stichnot@chromium.org
Review URL: https://codereview.chromium.org/1948093002 .
Patch from Sagar Thakur <sagar.thakur@imgtec.com>.
diff --git a/src/IceInstMIPS32.cpp b/src/IceInstMIPS32.cpp
index 9ba8777..30d48e3 100644
--- a/src/IceInstMIPS32.cpp
+++ b/src/IceInstMIPS32.cpp
@@ -56,6 +56,7 @@
template <> const char *InstMIPS32Add::Opcode = "add";
template <> const char *InstMIPS32Addu::Opcode = "addu";
template <> const char *InstMIPS32And::Opcode = "and";
+template <> const char *InstMIPS32Andi::Opcode = "andi";
template <> const char *InstMIPS32Mfhi::Opcode = "mfhi";
template <> const char *InstMIPS32Mflo::Opcode = "mflo";
template <> const char *InstMIPS32Mthi::Opcode = "mthi";
@@ -65,10 +66,12 @@
template <> const char *InstMIPS32Multu::Opcode = "multu";
template <> const char *InstMIPS32Or::Opcode = "or";
template <> const char *InstMIPS32Ori::Opcode = "ori";
+template <> const char *InstMIPS32Sll::Opcode = "sll";
template <> const char *InstMIPS32Slt::Opcode = "slt";
template <> const char *InstMIPS32Slti::Opcode = "slti";
template <> const char *InstMIPS32Sltiu::Opcode = "sltiu";
template <> const char *InstMIPS32Sltu::Opcode = "sltu";
+template <> const char *InstMIPS32Sra::Opcode = "sra";
template <> const char *InstMIPS32Sub::Opcode = "sub";
template <> const char *InstMIPS32Subu::Opcode = "subu";
template <> const char *InstMIPS32Xor::Opcode = "xor";
diff --git a/src/IceInstMIPS32.h b/src/IceInstMIPS32.h
index e364f7f..4247e7e 100644
--- a/src/IceInstMIPS32.h
+++ b/src/IceInstMIPS32.h
@@ -121,6 +121,7 @@
Addiu,
Addu,
And,
+ Andi,
Br,
Call,
La,
@@ -137,10 +138,12 @@
Or,
Ori,
Ret,
+ Sll,
Slt,
Slti,
Sltiu,
Sltu,
+ Sra,
Sub,
Subu,
Xor,
@@ -462,6 +465,7 @@
using InstMIPS32Addu = InstMIPS32ThreeAddrGPR<InstMIPS32::Addu>;
using InstMIPS32Addiu = InstMIPS32Imm16<InstMIPS32::Addiu, true>;
using InstMIPS32And = InstMIPS32ThreeAddrGPR<InstMIPS32::And>;
+using InstMIPS32Andi = InstMIPS32Imm16<InstMIPS32::Andi>;
using InstMIPS32Lui = InstMIPS32Imm16<InstMIPS32::Lui>;
using InstMIPS32La = InstMIPS32UnaryopGPR<InstMIPS32::La>;
using InstMIPS32Mfhi = InstMIPS32UnaryopGPR<InstMIPS32::Mfhi>;
@@ -473,10 +477,12 @@
using InstMIPS32Multu = InstMIPS32ThreeAddrGPR<InstMIPS32::Multu>;
using InstMIPS32Or = InstMIPS32ThreeAddrGPR<InstMIPS32::Or>;
using InstMIPS32Ori = InstMIPS32Imm16<InstMIPS32::Ori>;
+using InstMIPS32Sll = InstMIPS32Imm16<InstMIPS32::Sll>;
using InstMIPS32Slt = InstMIPS32ThreeAddrGPR<InstMIPS32::Slt>;
using InstMIPS32Slti = InstMIPS32Imm16<InstMIPS32::Slti>;
using InstMIPS32Sltiu = InstMIPS32Imm16<InstMIPS32::Sltiu>;
using InstMIPS32Sltu = InstMIPS32ThreeAddrGPR<InstMIPS32::Sltu>;
+using InstMIPS32Sra = InstMIPS32Imm16<InstMIPS32::Sra>;
using InstMIPS32Sub = InstMIPS32ThreeAddrGPR<InstMIPS32::Sub>;
using InstMIPS32Subu = InstMIPS32ThreeAddrGPR<InstMIPS32::Subu>;
using InstMIPS32Ori = InstMIPS32Imm16<InstMIPS32::Ori>;
diff --git a/src/IceTargetLoweringMIPS32.cpp b/src/IceTargetLoweringMIPS32.cpp
index cbfad69..79f02fb 100644
--- a/src/IceTargetLoweringMIPS32.cpp
+++ b/src/IceTargetLoweringMIPS32.cpp
@@ -1,4 +1,3 @@
-//===- subzero/src/IceTargetLoweringMIPS32.cpp - MIPS32 lowering ----------===//
//
// The Subzero Code Generator
//
@@ -905,20 +904,80 @@
void TargetMIPS32::lowerCast(const InstCast *Instr) {
InstCast::OpKind CastKind = Instr->getCastKind();
+ Variable *Dest = Instr->getDest();
+ Operand *Src0 = legalizeUndef(Instr->getSrc(0));
+ const Type DestTy = Dest->getType();
+ const Type Src0Ty = Src0->getType();
+ const uint32_t ShiftAmount =
+ INT32_BITS - (CHAR_BITS * typeWidthInBytes(Src0Ty));
+ const uint32_t Mask = (1 << (CHAR_BITS * typeWidthInBytes(Src0Ty))) - 1;
+
+ if (isVectorType(DestTy) || Src0->getType() == IceType_i1) {
+ UnimplementedLoweringError(this, Instr);
+ return;
+ }
switch (CastKind) {
default:
Func->setError("Cast type not supported");
return;
case InstCast::Sext: {
- UnimplementedLoweringError(this, Instr);
+ if (DestTy == IceType_i64) {
+ auto *DestLo = llvm::cast<Variable>(loOperand(Dest));
+ auto *DestHi = llvm::cast<Variable>(hiOperand(Dest));
+ Variable *Src0R = legalizeToReg(Src0);
+ Variable *T_Lo = I32Reg();
+ if (Src0Ty == IceType_i32) {
+ _mov(DestLo, Src0R);
+ } else if (Src0Ty == IceType_i8 || Src0Ty == IceType_i16) {
+ _sll(T_Lo, Src0R, ShiftAmount);
+ _sra(DestLo, T_Lo, ShiftAmount);
+ }
+ _sra(DestHi, DestLo, INT32_BITS - 1);
+ } else {
+ Variable *Src0R = legalizeToReg(Src0);
+ Variable *T = makeReg(DestTy);
+ if (Src0Ty == IceType_i8 || Src0Ty == IceType_i16) {
+ _sll(T, Src0R, ShiftAmount);
+ _sra(Dest, T, ShiftAmount);
+ }
+ }
break;
}
case InstCast::Zext: {
- UnimplementedLoweringError(this, Instr);
+ if (DestTy == IceType_i64) {
+ auto *DestLo = llvm::cast<Variable>(loOperand(Dest));
+ auto *DestHi = llvm::cast<Variable>(hiOperand(Dest));
+ Variable *Src0R = legalizeToReg(Src0);
+
+ switch (Src0Ty) {
+ default: { assert(Src0Ty != IceType_i64); } break;
+ case IceType_i32:
+ _mov(DestLo, Src0R);
+ break;
+ case IceType_i8:
+ case IceType_i16:
+ _andi(DestLo, Src0R, Mask);
+ break;
+ }
+
+ auto *Zero = getZero();
+ _addiu(DestHi, Zero, 0);
+ } else {
+ Variable *Src0R = legalizeToReg(Src0);
+ Variable *T = makeReg(DestTy);
+ if (Src0Ty == IceType_i8 || Src0Ty == IceType_i16)
+ _andi(T, Src0R, Mask);
+ _mov(Dest, T);
+ }
break;
}
case InstCast::Trunc: {
- UnimplementedLoweringError(this, Instr);
+ if (Src0Ty == IceType_i64)
+ Src0 = loOperand(Src0);
+ Variable *Src0R = legalizeToReg(Src0);
+ Variable *T = makeReg(DestTy);
+ _mov(T, Src0R);
+ _mov(Dest, T);
break;
}
case InstCast::Fptrunc:
diff --git a/src/IceTargetLoweringMIPS32.h b/src/IceTargetLoweringMIPS32.h
index 5802052..0454f30 100644
--- a/src/IceTargetLoweringMIPS32.h
+++ b/src/IceTargetLoweringMIPS32.h
@@ -150,6 +150,10 @@
Context.insert<InstMIPS32And>(Dest, Src0, Src1);
}
+ void _andi(Variable *Dest, Variable *Src, uint32_t Imm) {
+ Context.insert<InstMIPS32Andi>(Dest, Src, Imm);
+ }
+
void _br(CfgNode *Target) { Context.insert<InstMIPS32Br>(Target); }
void _ret(Variable *RA, Variable *Src0 = nullptr) {
@@ -216,6 +220,10 @@
Context.insert<InstMIPS32Ori>(Dest, Src, Imm);
}
+ void _sll(Variable *Dest, Variable *Src, uint32_t Imm) {
+ Context.insert<InstMIPS32Sll>(Dest, Src, Imm);
+ }
+
void _slt(Variable *Dest, Variable *Src0, Variable *Src1) {
Context.insert<InstMIPS32Slt>(Dest, Src0, Src1);
}
@@ -232,6 +240,10 @@
Context.insert<InstMIPS32Sltu>(Dest, Src0, Src1);
}
+ void _sra(Variable *Dest, Variable *Src, uint32_t Imm) {
+ Context.insert<InstMIPS32Sra>(Dest, Src, Imm);
+ }
+
void _sub(Variable *Dest, Variable *Src0, Variable *Src1) {
Context.insert<InstMIPS32Sub>(Dest, Src0, Src1);
}
@@ -346,6 +358,8 @@
static SmallBitVector RegisterAliases[RegMIPS32::Reg_NUM];
SmallBitVector RegsUsed;
VarList PhysicalRegisters[IceType_NUM];
+ static constexpr uint32_t CHAR_BITS = 8;
+ static constexpr uint32_t INT32_BITS = 32;
private:
ENABLE_MAKE_UNIQUE;
diff --git a/tests_lit/llvm2ice_tests/64bit.pnacl.ll b/tests_lit/llvm2ice_tests/64bit.pnacl.ll
index b19fa2a..aa0f26d 100644
--- a/tests_lit/llvm2ice_tests/64bit.pnacl.ll
+++ b/tests_lit/llvm2ice_tests/64bit.pnacl.ll
@@ -799,6 +799,9 @@
; ARM32-LABEL: trunc64To32Signed
; ARM32: mov r0, r2
+; MIPS32-LABEL: trunc64To32Signed
+; MIPS32: move v0,a2
+
define internal i32 @trunc64To16Signed(i64 %a) {
entry:
%conv = trunc i64 %a to i16
@@ -816,6 +819,11 @@
; ARM32-LABEL: trunc64To16Signed
; ARM32: sxth r0, r0
+; MIPS32-LABEL: trunc64To16Signed
+; MIPS32: sll a0,a0,0x10
+; MIPS32: sra a0,a0,0x10
+; MIPS32: move v0,a0
+
define internal i32 @trunc64To8Signed(i64 %a) {
entry:
%conv = trunc i64 %a to i8
@@ -833,6 +841,11 @@
; ARM32-LABEL: trunc64To8Signed
; ARM32: sxtb r0, r0
+; MIPS32-LABEL: trunc64To8Signed
+; MIPS32: sll a0,a0,0x18
+; MIPS32: sra a0,a0,0x18
+; MIPS32: move v0,a0
+
define internal i32 @trunc64To32SignedConst() {
entry:
%conv = trunc i64 12345678901234 to i32
@@ -848,6 +861,10 @@
; ARM32: movw r0, #12274 ; 0x2ff2
; ARM32: movt r0, #29646 ; 0x73ce
+; MIPS32-LABEL: trunc64To32SignedConst
+; MIPS32: lui v0,0x73ce
+; MIPS32: ori v0,v0,0x2ff2
+
define internal i32 @trunc64To16SignedConst() {
entry:
%conv = trunc i64 12345678901234 to i16
@@ -867,6 +884,12 @@
; ARM32: movt r0, #29646 ; 0x73ce
; ARM32: sxth r0, r0
+; MIPS32-LABEL: trunc64To16SignedConst
+; MIPS32: lui v0,0x73ce
+; MIPS32: ori v0,v0,0x2ff2
+; MIPS32: sll v0,v0,0x10
+; MIPS32: sra v0,v0,0x10
+
define internal i32 @trunc64To32Unsigned(i64 %padding, i64 %a) {
entry:
%conv = trunc i64 %a to i32
@@ -881,6 +904,9 @@
; ARM32-LABEL: trunc64To32Unsigned
; ARM32: mov r0, r2
+; MIPS32-LABEL: trunc64To32Unsigned
+; MIPS32: move v0,a2
+
define internal i32 @trunc64To16Unsigned(i64 %a) {
entry:
%conv = trunc i64 %a to i16
@@ -898,6 +924,10 @@
; ARM32-LABEL: trunc64To16Unsigned
; ARM32: uxth
+; MIPS32-LABEL: trunc64To16Unsigned
+; MIPS32: andi a0,a0,0xffff
+; MIPS32: move v0,a0
+
define internal i32 @trunc64To8Unsigned(i64 %a) {
entry:
%conv = trunc i64 %a to i8
@@ -915,6 +945,10 @@
; ARM32-LABEL: trunc64To8Unsigned
; ARM32: uxtb
+; MIPS32-LABEL: trunc64To8Unsigned
+; MIPS32: andi a0,a0,0xff
+; MIPS32: move v0,a0
+
define internal i32 @trunc64To1(i64 %a) {
entry:
; %tobool = icmp ne i64 %a, 0
@@ -952,6 +986,10 @@
; ARM32-LABEL: sext32To64
; ARM32: asr {{.*}}, #31
+; MIPS32-LABEL: sext32To64
+; MIPS32-LABEL: sra v1,a0,0x1f
+; MIPS32-LABEL: move v0,a0
+
define internal i64 @sext16To64(i32 %a) {
entry:
%a.arg_trunc = trunc i32 %a to i16
@@ -970,6 +1008,12 @@
; ARM32: sxth
; ARM32: asr {{.*}}, #31
+; MIPS32-LABEL: sext16To64
+; MIPS32: sll a0,a0,0x10
+; MIPS32: sra a0,a0,0x10
+; MIPS32: sra v1,a0,0x1f
+; MIPS32: move v0,a0
+
define internal i64 @sext8To64(i32 %a) {
entry:
%a.arg_trunc = trunc i32 %a to i8
@@ -988,6 +1032,12 @@
; ARM32: sxtb
; ARM32: asr {{.*}}, #31
+; MIPS32-LABEL: sext8To64
+; MIPS32: sll a0,a0,0x18
+; MIPS32: sra a0,a0,0x18
+; MIPS32: sra v1,a0,0x1f
+; MIPS32: move v0,a0
+
define internal i64 @sext1To64(i32 %a) {
entry:
%a.arg_trunc = trunc i32 %a to i1
@@ -1026,6 +1076,10 @@
; ARM32-LABEL: zext32To64
; ARM32: mov {{.*}}, #0
+; MIPS32-LABEL: zext32To64
+; MIPS32: li v1,0
+; MIPS32: move v0,a0
+
define internal i64 @zext16To64(i32 %a) {
entry:
%a.arg_trunc = trunc i32 %a to i16
@@ -1044,6 +1098,11 @@
; ARM32: uxth
; ARM32: mov {{.*}}, #0
+; MIPS32-LABEL: zext16To64
+; MIPS32: andi a0,a0,0xffff
+; MIPS32: li v1,0
+; MIPS32: move v0,a0
+
define internal i64 @zext8To64(i32 %a) {
entry:
%a.arg_trunc = trunc i32 %a to i8
@@ -1062,6 +1121,11 @@
; ARM32: uxtb
; ARM32: mov {{.*}}, #0
+; MIPS32-LABEL: zext8To64
+; MIPS32: andi a0,a0,0xff
+; MIPS32: li v1,0
+; MIPS32: move v0,a0
+
define internal i64 @zext1To64(i32 %a) {
entry:
%a.arg_trunc = trunc i32 %a to i1