Commit 37af5b0f by Reed Kotler Committed by Jim Stichnoth

Lower a few basic MIPS binops for i{8,16,32,64}.

This is basically the same patch as for ARM issue 1127003003 https://codereview.chromium.org/1127003003 BUG= https://code.google.com/p/nativeclient/issues/detail?id=4167 R=stichnot@chromium.org Review URL: https://codereview.chromium.org/1414383004 . Patch from Reed Kotler <rkotlerimgtec@gmail.com>.
parent 080b65b5
...@@ -51,8 +51,14 @@ const char *InstMIPS32::getWidthString(Type Ty) { ...@@ -51,8 +51,14 @@ const char *InstMIPS32::getWidthString(Type Ty) {
template <> const char *InstMIPS32Addiu::Opcode = "addiu"; template <> const char *InstMIPS32Addiu::Opcode = "addiu";
template <> const char *InstMIPS32Lui::Opcode = "lui"; template <> const char *InstMIPS32Lui::Opcode = "lui";
template <> const char *InstMIPS32La::Opcode = "la"; template <> const char *InstMIPS32La::Opcode = "la";
// Three-addr ops
template <> const char *InstMIPS32Add::Opcode = "add";
template <> const char *InstMIPS32And::Opcode = "and";
template <> const char *InstMIPS32Mul::Opcode = "mul";
template <> const char *InstMIPS32Or::Opcode = "or";
template <> const char *InstMIPS32Ori::Opcode = "ori"; template <> const char *InstMIPS32Ori::Opcode = "ori";
template <> const char *InstMIPS32Sub::Opcode = "sub";
template <> const char *InstMIPS32Xor::Opcode = "xor";
InstMIPS32Mov::InstMIPS32Mov(Cfg *Func, Variable *Dest, Operand *Src) InstMIPS32Mov::InstMIPS32Mov(Cfg *Func, Variable *Dest, Operand *Src)
: InstMIPS32(Func, InstMIPS32::Mov, 2, Dest) { : InstMIPS32(Func, InstMIPS32::Mov, 2, Dest) {
...@@ -104,13 +110,26 @@ void InstMIPS32::emitUnaryopGPR(const char *Opcode, const InstMIPS32 *Inst, ...@@ -104,13 +110,26 @@ void InstMIPS32::emitUnaryopGPR(const char *Opcode, const InstMIPS32 *Inst,
if (!BuildDefs::dump()) if (!BuildDefs::dump())
return; return;
Ostream &Str = Func->getContext()->getStrEmit(); Ostream &Str = Func->getContext()->getStrEmit();
// Type SrcTy = Inst->getSrc(0)->getType();
Str << "\t" << Opcode << "\t"; Str << "\t" << Opcode << "\t";
Inst->getDest()->emit(Func); Inst->getDest()->emit(Func);
Str << ", "; Str << ", ";
Inst->getSrc(0)->emit(Func); Inst->getSrc(0)->emit(Func);
} }
void InstMIPS32::emitThreeAddr(const char *Opcode, const InstMIPS32 *Inst,
const Cfg *Func) {
if (!BuildDefs::dump())
return;
Ostream &Str = Func->getContext()->getStrEmit();
assert(Inst->getSrcSize() == 2);
Str << "\t" << Opcode << "\t";
Inst->getDest()->emit(Func);
Str << ", ";
Inst->getSrc(0)->emit(Func);
Str << ", ";
Inst->getSrc(1)->emit(Func);
}
void InstMIPS32Ret::emit(const Cfg *Func) const { void InstMIPS32Ret::emit(const Cfg *Func) const {
if (!BuildDefs::dump()) if (!BuildDefs::dump())
return; return;
...@@ -225,12 +244,31 @@ void InstMIPS32Mov::emitSingleDestMultiSource(const Cfg *Func) const { ...@@ -225,12 +244,31 @@ void InstMIPS32Mov::emitSingleDestMultiSource(const Cfg *Func) const {
} }
void InstMIPS32Mov::emitSingleDestSingleSource(const Cfg *Func) const { void InstMIPS32Mov::emitSingleDestSingleSource(const Cfg *Func) const {
if (!BuildDefs::dump())
return;
Ostream &Str = Func->getContext()->getStrEmit(); Ostream &Str = Func->getContext()->getStrEmit();
// assert(Inst->getSrcSize() == 1); Variable *Dest = getDest();
// Type SrcTy = Inst->getSrc(0)->getType(); Operand *Src = getSrc(0);
Str << "\t" auto *S = llvm::dyn_cast<Variable>(Src);
<< "move" Str << "\t";
<< "\t"; if (Dest->hasReg()) {
if (S && S->hasReg())
Str << "move";
else
Str << "lw";
} else {
if (S && S->hasReg()) {
Str << "sw";
Str << "\t";
getSrc(0)->emit(Func);
Str << ", ";
getDest()->emit(Func);
return;
} else
Str << "move";
}
Str << "\t";
getDest()->emit(Func); getDest()->emit(Func);
Str << ", "; Str << ", ";
getSrc(0)->emit(Func); getSrc(0)->emit(Func);
......
...@@ -114,12 +114,18 @@ class InstMIPS32 : public InstTarget { ...@@ -114,12 +114,18 @@ class InstMIPS32 : public InstTarget {
public: public:
enum InstKindMIPS32 { enum InstKindMIPS32 {
k__Start = Inst::Target, k__Start = Inst::Target,
Add,
And,
Addiu, Addiu,
La, La,
Lui, Lui,
Mov, // actually a pseudo op for addi rd, rs, 0 Mov, // actually a pseudo op for addi rd, rs, 0
Mul,
Or,
Ori, Ori,
Ret Ret,
Sub,
Xor
}; };
static const char *getWidthString(Type Ty); static const char *getWidthString(Type Ty);
...@@ -133,6 +139,8 @@ public: ...@@ -133,6 +139,8 @@ public:
/// Shared emit routines for common forms of instructions. /// Shared emit routines for common forms of instructions.
static void emitUnaryopGPR(const char *Opcode, const InstMIPS32 *Inst, static void emitUnaryopGPR(const char *Opcode, const InstMIPS32 *Inst,
const Cfg *Func); const Cfg *Func);
static void emitThreeAddr(const char *Opcode, const InstMIPS32 *Inst,
const Cfg *Func);
protected: protected:
InstMIPS32(Cfg *Func, InstKindMIPS32 Kind, SizeT Maxsrcs, Variable *Dest) InstMIPS32(Cfg *Func, InstKindMIPS32 Kind, SizeT Maxsrcs, Variable *Dest)
...@@ -213,6 +221,55 @@ private: ...@@ -213,6 +221,55 @@ private:
static const char *Opcode; static const char *Opcode;
}; };
/// Instructions of the form x := y op z. May have the side-effect of setting
/// status flags.
template <InstMIPS32::InstKindMIPS32 K>
class InstMIPS32ThreeAddrGPR : public InstMIPS32 {
InstMIPS32ThreeAddrGPR() = delete;
InstMIPS32ThreeAddrGPR(const InstMIPS32ThreeAddrGPR &) = delete;
InstMIPS32ThreeAddrGPR &operator=(const InstMIPS32ThreeAddrGPR &) = delete;
public:
/// Create an ordinary binary-op instruction like add, and sub. Dest and Src1
/// must be registers.
static InstMIPS32ThreeAddrGPR *create(Cfg *Func, Variable *Dest,
Variable *Src0, Variable *Src1) {
return new (Func->allocate<InstMIPS32ThreeAddrGPR>())
InstMIPS32ThreeAddrGPR(Func, Dest, Src0, Src1);
}
void emit(const Cfg *Func) const override {
if (!BuildDefs::dump())
return;
emitThreeAddr(Opcode, this, Func);
}
void emitIAS(const Cfg *Func) const override {
(void)Func;
llvm_unreachable("Not yet implemented");
}
void dump(const Cfg *Func) const override {
if (!BuildDefs::dump())
return;
Ostream &Str = Func->getContext()->getStrDump();
dumpDest(Func);
Str << " = ";
dumpOpcode(Str, Opcode, getDest()->getType());
Str << " ";
dumpSources(Func);
}
static bool classof(const Inst *Inst) { return isClassof(Inst, K); }
private:
InstMIPS32ThreeAddrGPR(Cfg *Func, Variable *Dest, Variable *Src0,
Variable *Src1)
: InstMIPS32(Func, K, 2, Dest) {
addSource(Src0);
addSource(Src1);
}
static const char *Opcode;
};
template <InstMIPS32::InstKindMIPS32 K, bool Signed = false> template <InstMIPS32::InstKindMIPS32 K, bool Signed = false>
class InstMIPS32Imm16 : public InstMIPS32 { class InstMIPS32Imm16 : public InstMIPS32 {
InstMIPS32Imm16() = delete; InstMIPS32Imm16() = delete;
...@@ -285,10 +342,17 @@ private: ...@@ -285,10 +342,17 @@ private:
const uint32_t Imm; const uint32_t Imm;
}; };
typedef InstMIPS32Imm16<InstMIPS32::Addiu, true> InstMIPS32Addiu; using InstMIPS32Add = InstMIPS32ThreeAddrGPR<InstMIPS32::Add>;
typedef InstMIPS32Imm16<InstMIPS32::Lui> InstMIPS32Lui; using InstMIPS32Addiu = InstMIPS32Imm16<InstMIPS32::Addiu, true>;
typedef InstMIPS32UnaryopGPR<InstMIPS32::La> InstMIPS32La; using InstMIPS32And = InstMIPS32ThreeAddrGPR<InstMIPS32::And>;
typedef InstMIPS32Imm16<InstMIPS32::Ori> InstMIPS32Ori; using InstMIPS32Lui = InstMIPS32Imm16<InstMIPS32::Lui>;
using InstMIPS32La = InstMIPS32UnaryopGPR<InstMIPS32::La>;
using InstMIPS32Mul = InstMIPS32ThreeAddrGPR<InstMIPS32::Mul>;
using InstMIPS32Or = InstMIPS32ThreeAddrGPR<InstMIPS32::Or>;
using InstMIPS32Ori = InstMIPS32Imm16<InstMIPS32::Ori>;
using InstMIPS32Sub = InstMIPS32ThreeAddrGPR<InstMIPS32::Sub>;
using InstMIPS32Ori = InstMIPS32Imm16<InstMIPS32::Ori>;
using InstMIPS32Xor = InstMIPS32ThreeAddrGPR<InstMIPS32::Xor>;
/// Handles (some of) vmov's various formats. /// Handles (some of) vmov's various formats.
class InstMIPS32Mov final : public InstMIPS32 { class InstMIPS32Mov final : public InstMIPS32 {
......
...@@ -318,7 +318,7 @@ void TargetMIPS32::emitVariable(const Variable *Var) const { ...@@ -318,7 +318,7 @@ void TargetMIPS32::emitVariable(const Variable *Var) const {
} else { } else {
int32_t Offset = Var->getStackOffset(); int32_t Offset = Var->getStackOffset();
Str << Offset; Str << Offset;
Str << "(" << getRegName(getFrameOrStackReg(), FrameSPTy); Str << "($" << getRegName(getFrameOrStackReg(), FrameSPTy);
Str << ")"; Str << ")";
} }
UnimplementedError(Func->getContext()->getFlags()); UnimplementedError(Func->getContext()->getFlags());
...@@ -517,76 +517,83 @@ void TargetMIPS32::lowerArithmetic(const InstArithmetic *Inst) { ...@@ -517,76 +517,83 @@ void TargetMIPS32::lowerArithmetic(const InstArithmetic *Inst) {
Variable *Dest = Inst->getDest(); Variable *Dest = Inst->getDest();
Operand *Src0 = legalizeUndef(Inst->getSrc(0)); Operand *Src0 = legalizeUndef(Inst->getSrc(0));
Operand *Src1 = legalizeUndef(Inst->getSrc(1)); Operand *Src1 = legalizeUndef(Inst->getSrc(1));
(void)Src0;
(void)Src1;
if (Dest->getType() == IceType_i64) { if (Dest->getType() == IceType_i64) {
// TODO(reed kotler): fakedef needed for now until all cases are implemented
Variable *DestLo = llvm::cast<Variable>(loOperand(Dest));
Variable *DestHi = llvm::cast<Variable>(hiOperand(Dest));
Context.insert(InstFakeDef::create(Func, DestLo));
Context.insert(InstFakeDef::create(Func, DestHi));
UnimplementedError(Func->getContext()->getFlags()); UnimplementedError(Func->getContext()->getFlags());
} else if (isVectorType(Dest->getType())) { return;
}
if (isVectorType(Dest->getType())) {
Context.insert(InstFakeDef::create(Func, Dest));
UnimplementedError(Func->getContext()->getFlags()); UnimplementedError(Func->getContext()->getFlags());
} else { // Dest->getType() is non-i64 scalar return;
}
// Dest->getType() is non-i64 scalar
Variable *T = makeReg(Dest->getType());
Variable *Src0R = legalizeToReg(Src0);
Variable *Src1R = legalizeToReg(Src1);
switch (Inst->getOp()) { switch (Inst->getOp()) {
case InstArithmetic::_num: case InstArithmetic::_num:
UnimplementedError(Func->getContext()->getFlags());
break; break;
case InstArithmetic::Add: case InstArithmetic::Add:
UnimplementedError(Func->getContext()->getFlags()); _add(T, Src0R, Src1R);
// Variable *T = makeReg(Dest->getType()); _mov(Dest, T);
// _add(T, Src0, Src1);
// _mov(Dest, T);
return; return;
case InstArithmetic::And: case InstArithmetic::And:
UnimplementedError(Func->getContext()->getFlags()); _and(T, Src0R, Src1R);
break; _mov(Dest, T);
return;
case InstArithmetic::Or: case InstArithmetic::Or:
UnimplementedError(Func->getContext()->getFlags()); _or(T, Src0R, Src1R);
break; _mov(Dest, T);
return;
case InstArithmetic::Xor: case InstArithmetic::Xor:
UnimplementedError(Func->getContext()->getFlags()); _xor(T, Src0R, Src1R);
break; _mov(Dest, T);
return;
case InstArithmetic::Sub: case InstArithmetic::Sub:
UnimplementedError(Func->getContext()->getFlags()); _sub(T, Src0R, Src1R);
break; _mov(Dest, T);
case InstArithmetic::Mul: return;
UnimplementedError(Func->getContext()->getFlags()); case InstArithmetic::Mul: {
break; _mul(T, Src0R, Src1R);
_mov(Dest, T);
return;
}
case InstArithmetic::Shl: case InstArithmetic::Shl:
UnimplementedError(Func->getContext()->getFlags());
break; break;
case InstArithmetic::Lshr: case InstArithmetic::Lshr:
UnimplementedError(Func->getContext()->getFlags());
break; break;
case InstArithmetic::Ashr: case InstArithmetic::Ashr:
UnimplementedError(Func->getContext()->getFlags());
break; break;
case InstArithmetic::Udiv: case InstArithmetic::Udiv:
UnimplementedError(Func->getContext()->getFlags());
break; break;
case InstArithmetic::Sdiv: case InstArithmetic::Sdiv:
UnimplementedError(Func->getContext()->getFlags());
break; break;
case InstArithmetic::Urem: case InstArithmetic::Urem:
UnimplementedError(Func->getContext()->getFlags());
break; break;
case InstArithmetic::Srem: case InstArithmetic::Srem:
UnimplementedError(Func->getContext()->getFlags());
break; break;
case InstArithmetic::Fadd: case InstArithmetic::Fadd:
UnimplementedError(Func->getContext()->getFlags());
break; break;
case InstArithmetic::Fsub: case InstArithmetic::Fsub:
UnimplementedError(Func->getContext()->getFlags());
break; break;
case InstArithmetic::Fmul: case InstArithmetic::Fmul:
UnimplementedError(Func->getContext()->getFlags());
break; break;
case InstArithmetic::Fdiv: case InstArithmetic::Fdiv:
UnimplementedError(Func->getContext()->getFlags());
break; break;
case InstArithmetic::Frem: case InstArithmetic::Frem:
UnimplementedError(Func->getContext()->getFlags());
break; break;
} }
} // TODO(reed kotler):
// fakedef and fakeuse needed for now until all cases are implemented
Context.insert(InstFakeUse::create(Func, Src0R));
Context.insert(InstFakeUse::create(Func, Src1R));
Context.insert(InstFakeDef::create(Func, Dest));
UnimplementedError(Func->getContext()->getFlags());
} }
void TargetMIPS32::lowerAssign(const InstAssign *Inst) { void TargetMIPS32::lowerAssign(const InstAssign *Inst) {
...@@ -995,13 +1002,16 @@ Operand *TargetMIPS32::legalize(Operand *From, LegalMask Allowed, ...@@ -995,13 +1002,16 @@ Operand *TargetMIPS32::legalize(Operand *From, LegalMask Allowed,
// registers to the right type OperandMIPS32FlexReg as needed. // registers to the right type OperandMIPS32FlexReg as needed.
assert(Allowed & Legal_Reg); assert(Allowed & Legal_Reg);
// Go through the various types of operands: // Go through the various types of operands:
// OperandMIPS32Mem, OperandMIPS32Flex, Constant, and Variable. // OperandMIPS32Mem, Constant, and Variable.
// Given the above assertion, if type of operand is not legal // Given the above assertion, if type of operand is not legal
// (e.g., OperandMIPS32Mem and !Legal_Mem), we can always copy // (e.g., OperandMIPS32Mem and !Legal_Mem), we can always copy
// to a register. // to a register.
if (auto *C = llvm::dyn_cast<ConstantRelocatable>(From)) { if (auto *C = llvm::dyn_cast<ConstantRelocatable>(From)) {
(void)C; (void)C;
return From; // TODO(reed kotler): complete this case for proper implementation
Variable *Reg = makeReg(Ty, RegNum);
Context.insert(InstFakeDef::create(Func, Reg));
return Reg;
} else if (auto *C32 = llvm::dyn_cast<ConstantInteger32>(From)) { } else if (auto *C32 = llvm::dyn_cast<ConstantInteger32>(From)) {
uint32_t Value = static_cast<uint32_t>(C32->getValue()); uint32_t Value = static_cast<uint32_t>(C32->getValue());
// Check if the immediate will fit in a Flexible second operand, // Check if the immediate will fit in a Flexible second operand,
......
...@@ -91,6 +91,18 @@ public: ...@@ -91,6 +91,18 @@ public:
(void)C; (void)C;
llvm::report_fatal_error("Not yet implemented"); llvm::report_fatal_error("Not yet implemented");
} }
// The following are helpers that insert lowered MIPS32 instructions with
// minimal syntactic overhead, so that the lowering code can look as close to
// assembly as practical.
void _add(Variable *Dest, Variable *Src0, Variable *Src1) {
Context.insert(InstMIPS32Add::create(Func, Dest, Src0, Src1));
}
void _and(Variable *Dest, Variable *Src0, Variable *Src1) {
Context.insert(InstMIPS32And::create(Func, Dest, Src0, Src1));
}
void _ret(Variable *RA, Variable *Src0 = nullptr) { void _ret(Variable *RA, Variable *Src0 = nullptr) {
Context.insert(InstMIPS32Ret::create(Func, RA, Src0)); Context.insert(InstMIPS32Ret::create(Func, RA, Src0));
} }
...@@ -120,10 +132,26 @@ public: ...@@ -120,10 +132,26 @@ public:
} }
} }
void _mul(Variable *Dest, Variable *Src0, Variable *Src1) {
Context.insert(InstMIPS32Mul::create(Func, Dest, Src0, Src1));
}
void _or(Variable *Dest, Variable *Src0, Variable *Src1) {
Context.insert(InstMIPS32Or::create(Func, Dest, Src0, Src1));
}
void _ori(Variable *Dest, Variable *Src, uint32_t Imm) { void _ori(Variable *Dest, Variable *Src, uint32_t Imm) {
Context.insert(InstMIPS32Ori::create(Func, Dest, Src, Imm)); Context.insert(InstMIPS32Ori::create(Func, Dest, Src, Imm));
} }
void _sub(Variable *Dest, Variable *Src0, Variable *Src1) {
Context.insert(InstMIPS32Sub::create(Func, Dest, Src0, Src1));
}
void _xor(Variable *Dest, Variable *Src0, Variable *Src1) {
Context.insert(InstMIPS32Xor::create(Func, Dest, Src0, Src1));
}
void lowerArguments() override; void lowerArguments() override;
/// Operand legalization helpers. To deal with address mode constraints, /// Operand legalization helpers. To deal with address mode constraints,
......
...@@ -22,6 +22,18 @@ ...@@ -22,6 +22,18 @@
; RUN: -i %s --args -Om1 --skip-unimplemented \ ; RUN: -i %s --args -Om1 --skip-unimplemented \
; RUN: | %if --need=target_ARM32 --need=allow_dump \ ; RUN: | %if --need=target_ARM32 --need=allow_dump \
; RUN: --command FileCheck --check-prefix ARM32 %s ; RUN: --command FileCheck --check-prefix ARM32 %s
;
; RUN: %if --need=target_MIPS32 --need=allow_dump \
; RUN: --command %p2i --filetype=asm --assemble --disassemble --target mips32\
; RUN: -i %s --args -O2 --skip-unimplemented \
; RUN: | %if --need=target_MIPS32 --need=allow_dump \
; RUN: --command FileCheck --check-prefix MIPS32 %s
; RUN: %if --need=target_MIPS32 --need=allow_dump \
; RUN: --command %p2i --filetype=asm --assemble --disassemble --target mips32\
; RUN: -i %s --args -Om1 --skip-unimplemented \
; RUN: | %if --need=target_MIPS32 --need=allow_dump \
; RUN: --command FileCheck --check-prefix MIPS32 %s
define internal i32 @Add(i32 %a, i32 %b) { define internal i32 @Add(i32 %a, i32 %b) {
entry: entry:
...@@ -32,6 +44,8 @@ entry: ...@@ -32,6 +44,8 @@ entry:
; CHECK: add e ; CHECK: add e
; ARM32-LABEL: Add ; ARM32-LABEL: Add
; ARM32: add r ; ARM32: add r
; MIPS32-LABEL: Add
; MIPS32: add
define internal i32 @And(i32 %a, i32 %b) { define internal i32 @And(i32 %a, i32 %b) {
entry: entry:
...@@ -42,6 +56,8 @@ entry: ...@@ -42,6 +56,8 @@ entry:
; CHECK: and e ; CHECK: and e
; ARM32-LABEL: And ; ARM32-LABEL: And
; ARM32: and r ; ARM32: and r
; MIPS32-LABEL: And
; MIPS32: and
define internal i32 @Or(i32 %a, i32 %b) { define internal i32 @Or(i32 %a, i32 %b) {
entry: entry:
...@@ -52,6 +68,8 @@ entry: ...@@ -52,6 +68,8 @@ entry:
; CHECK: or e ; CHECK: or e
; ARM32-LABEL: Or ; ARM32-LABEL: Or
; ARM32: orr r ; ARM32: orr r
; MIPS32-LABEL: Or
; MIPS32: or
define internal i32 @Xor(i32 %a, i32 %b) { define internal i32 @Xor(i32 %a, i32 %b) {
entry: entry:
...@@ -62,6 +80,8 @@ entry: ...@@ -62,6 +80,8 @@ entry:
; CHECK: xor e ; CHECK: xor e
; ARM32-LABEL: Xor ; ARM32-LABEL: Xor
; ARM32: eor r ; ARM32: eor r
; MIPS32-LABEL: Xor
; MIPS32: xor
define internal i32 @Sub(i32 %a, i32 %b) { define internal i32 @Sub(i32 %a, i32 %b) {
entry: entry:
...@@ -72,6 +92,8 @@ entry: ...@@ -72,6 +92,8 @@ entry:
; CHECK: sub e ; CHECK: sub e
; ARM32-LABEL: Sub ; ARM32-LABEL: Sub
; ARM32: sub r ; ARM32: sub r
; MIPS32-LABEL: Sub
; MIPS32: sub
define internal i32 @Mul(i32 %a, i32 %b) { define internal i32 @Mul(i32 %a, i32 %b) {
entry: entry:
...@@ -82,6 +104,8 @@ entry: ...@@ -82,6 +104,8 @@ entry:
; CHECK: imul e ; CHECK: imul e
; ARM32-LABEL: Mul ; ARM32-LABEL: Mul
; ARM32: mul r ; ARM32: mul r
; MIPS32-LABEL: Mul
; MIPS32: mul
; Check for a valid ARM mul instruction where operands have to be registers. ; Check for a valid ARM mul instruction where operands have to be registers.
; On the other hand x86-32 does allow an immediate. ; On the other hand x86-32 does allow an immediate.
...@@ -95,6 +119,8 @@ entry: ...@@ -95,6 +119,8 @@ entry:
; ARM32-LABEL: MulImm ; ARM32-LABEL: MulImm
; ARM32: mov {{.*}}, #99 ; ARM32: mov {{.*}}, #99
; ARM32: mul r{{.*}}, r{{.*}}, r{{.*}} ; ARM32: mul r{{.*}}, r{{.*}}, r{{.*}}
; MIPS32-LABEL: MulImm
; MIPS32: mul
; Check for a valid addressing mode in the x86-32 mul instruction when ; Check for a valid addressing mode in the x86-32 mul instruction when
; the second source operand is an immediate. ; the second source operand is an immediate.
...@@ -119,6 +145,8 @@ entry: ...@@ -119,6 +145,8 @@ entry:
; ARM32: umull r ; ARM32: umull r
; ARM32: add r ; ARM32: add r
; MIPS32-LABEL: MulImm64
define internal i32 @Sdiv(i32 %a, i32 %b) { define internal i32 @Sdiv(i32 %a, i32 %b) {
entry: entry:
%div = sdiv i32 %a, %b %div = sdiv i32 %a, %b
...@@ -138,6 +166,8 @@ entry: ...@@ -138,6 +166,8 @@ entry:
; ARM32HWDIV: bne ; ARM32HWDIV: bne
; ARM32HWDIV: sdiv ; ARM32HWDIV: sdiv
; MIPS32-LABEL: Sdiv
define internal i32 @SdivConst(i32 %a) { define internal i32 @SdivConst(i32 %a) {
entry: entry:
%div = sdiv i32 %a, 219 %div = sdiv i32 %a, 219
...@@ -154,6 +184,8 @@ entry: ...@@ -154,6 +184,8 @@ entry:
; ARM32HWDIV-NOT: tst ; ARM32HWDIV-NOT: tst
; ARM32HWDIV: sdiv ; ARM32HWDIV: sdiv
; MIPS32-LABEL: SdivConst
define internal i32 @Srem(i32 %a, i32 %b) { define internal i32 @Srem(i32 %a, i32 %b) {
entry: entry:
%rem = srem i32 %a, %b %rem = srem i32 %a, %b
...@@ -173,6 +205,8 @@ entry: ...@@ -173,6 +205,8 @@ entry:
; ARM32HWDIV: sdiv ; ARM32HWDIV: sdiv
; ARM32HWDIV: mls ; ARM32HWDIV: mls
; MIPS32-LABEL: Srem
define internal i32 @Udiv(i32 %a, i32 %b) { define internal i32 @Udiv(i32 %a, i32 %b) {
entry: entry:
%div = udiv i32 %a, %b %div = udiv i32 %a, %b
...@@ -190,6 +224,8 @@ entry: ...@@ -190,6 +224,8 @@ entry:
; ARM32HWDIV: bne ; ARM32HWDIV: bne
; ARM32HWDIV: udiv ; ARM32HWDIV: udiv
; MIPS32-LABEL: Udiv
define internal i32 @Urem(i32 %a, i32 %b) { define internal i32 @Urem(i32 %a, i32 %b) {
entry: entry:
%rem = urem i32 %a, %b %rem = urem i32 %a, %b
...@@ -208,6 +244,8 @@ entry: ...@@ -208,6 +244,8 @@ entry:
; ARM32HWDIV: udiv ; ARM32HWDIV: udiv
; ARM32HWDIV: mls ; ARM32HWDIV: mls
; MIPS32-LABEL: Urem
; The following tests check that shift instructions don't try to use a ; The following tests check that shift instructions don't try to use a
; ConstantRelocatable as an immediate operand. ; ConstantRelocatable as an immediate operand.
......
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