Commit 29823f1c by Jaydeep Patil Committed by Jim Stichnoth

[SubZero] Implement lowerSwitch for MIPS

The patch implements lowerSwitch for i32 and i64 types. R=stichnot@chromium.org Review URL: https://codereview.chromium.org/2289043002 . Patch from Jaydeep Patil <jaydeep.patil@imgtec.com>.
parent 8b21cc58
...@@ -456,8 +456,11 @@ void InstMIPS32Br::emit(const Cfg *Func) const { ...@@ -456,8 +456,11 @@ void InstMIPS32Br::emit(const Cfg *Func) const {
Ostream &Str = Func->getContext()->getStrEmit(); Ostream &Str = Func->getContext()->getStrEmit();
Str << "\t" Str << "\t"
"b" << InstMIPS32CondAttributes[Predicate].EmitString << "\t"; "b" << InstMIPS32CondAttributes[Predicate].EmitString << "\t";
if (Label) { if (Label != nullptr) {
Str << Label->getLabelName(); getSrc(0)->emit(Func);
Str << ", ";
getSrc(1)->emit(Func);
Str << ", " << Label->getLabelName();
} else { } else {
if (isUnconditionalBranch()) { if (isUnconditionalBranch()) {
Str << getTargetFalse()->getAsmName(); Str << getTargetFalse()->getAsmName();
...@@ -501,8 +504,11 @@ void InstMIPS32Br::dump(const Cfg *Func) const { ...@@ -501,8 +504,11 @@ void InstMIPS32Br::dump(const Cfg *Func) const {
Str << "\t" Str << "\t"
"b" << InstMIPS32CondAttributes[Predicate].EmitString << "\t"; "b" << InstMIPS32CondAttributes[Predicate].EmitString << "\t";
if (Label) { if (Label != nullptr) {
Str << Label->getLabelName(); getSrc(0)->dump(Func);
Str << ", ";
getSrc(1)->dump(Func);
Str << ", " << Label->getLabelName();
} else { } else {
if (isUnconditionalBranch()) { if (isUnconditionalBranch()) {
Str << getTargetFalse()->getAsmName(); Str << getTargetFalse()->getAsmName();
......
...@@ -671,6 +671,14 @@ public: ...@@ -671,6 +671,14 @@ public:
InstMIPS32Br(Func, TargetTrue, TargetFalse, Src0, NoLabel, Cond); InstMIPS32Br(Func, TargetTrue, TargetFalse, Src0, NoLabel, Cond);
} }
static InstMIPS32Br *create(Cfg *Func, CfgNode *TargetTrue,
CfgNode *TargetFalse, Operand *Src0,
Operand *Src1, const InstMIPS32Label *Label,
CondMIPS32::Cond Cond) {
return new (Func->allocate<InstMIPS32Br>())
InstMIPS32Br(Func, TargetTrue, TargetFalse, Src0, Src1, Label, Cond);
}
const CfgNode *getTargetTrue() const { return TargetTrue; } const CfgNode *getTargetTrue() const { return TargetTrue; }
const CfgNode *getTargetFalse() const { return TargetFalse; } const CfgNode *getTargetFalse() const { return TargetFalse; }
CondMIPS32::Cond getPredicate() const { return Predicate; } CondMIPS32::Cond getPredicate() const { return Predicate; }
......
...@@ -2318,7 +2318,38 @@ void TargetMIPS32::lowerStore(const InstStore *Instr) { ...@@ -2318,7 +2318,38 @@ void TargetMIPS32::lowerStore(const InstStore *Instr) {
void TargetMIPS32::doAddressOptStore() { UnimplementedError(getFlags()); } void TargetMIPS32::doAddressOptStore() { UnimplementedError(getFlags()); }
void TargetMIPS32::lowerSwitch(const InstSwitch *Instr) { void TargetMIPS32::lowerSwitch(const InstSwitch *Instr) {
UnimplementedLoweringError(this, Instr); Operand *Src = Instr->getComparison();
SizeT NumCases = Instr->getNumCases();
if (Src->getType() == IceType_i64) {
Src = legalizeUndef(Src);
Variable *Src0Lo = legalizeToReg(loOperand(Src));
Variable *Src0Hi = legalizeToReg(hiOperand(Src));
for (SizeT I = 0; I < NumCases; ++I) {
Operand *ValueLo = Ctx->getConstantInt32(Instr->getValue(I));
Operand *ValueHi = Ctx->getConstantInt32(Instr->getValue(I) >> 32);
CfgNode *TargetTrue = Instr->getLabel(I);
constexpr CfgNode *NoTarget = nullptr;
ValueHi = legalizeToReg(ValueHi);
InstMIPS32Label *IntraLabel = InstMIPS32Label::create(Func, this);
_br(NoTarget, NoTarget, Src0Hi, ValueHi, IntraLabel,
CondMIPS32::Cond::NE);
ValueLo = legalizeToReg(ValueLo);
_br(NoTarget, TargetTrue, Src0Lo, ValueLo, CondMIPS32::Cond::EQ);
Context.insert(IntraLabel);
}
_br(Instr->getLabelDefault());
return;
}
Variable *SrcVar = legalizeToReg(Src);
assert(SrcVar->mustHaveReg());
for (SizeT I = 0; I < NumCases; ++I) {
Operand *Value = Ctx->getConstantInt32(Instr->getValue(I));
CfgNode *TargetTrue = Instr->getLabel(I);
constexpr CfgNode *NoTargetFalse = nullptr;
Value = legalizeToReg(Value);
_br(NoTargetFalse, TargetTrue, SrcVar, Value, CondMIPS32::Cond::EQ);
}
_br(Instr->getLabelDefault());
} }
void TargetMIPS32::lowerBreakpoint(const InstBreakpoint *Instr) { void TargetMIPS32::lowerBreakpoint(const InstBreakpoint *Instr) {
......
...@@ -178,6 +178,13 @@ public: ...@@ -178,6 +178,13 @@ public:
Context.insert<InstMIPS32Br>(TargetTrue, TargetFalse, Src0, Condition); Context.insert<InstMIPS32Br>(TargetTrue, TargetFalse, Src0, Condition);
} }
void _br(CfgNode *TargetTrue, CfgNode *TargetFalse, Operand *Src0,
Operand *Src1, const InstMIPS32Label *Label,
CondMIPS32::Cond Condition) {
Context.insert<InstMIPS32Br>(TargetTrue, TargetFalse, Src0, Src1, Label,
Condition);
}
void _ret(Variable *RA, Variable *Src0 = nullptr) { void _ret(Variable *RA, Variable *Src0 = nullptr) {
Context.insert<InstMIPS32Ret>(RA, Src0); Context.insert<InstMIPS32Ret>(RA, Src0);
} }
......
...@@ -11,6 +11,14 @@ ...@@ -11,6 +11,14 @@
; 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
; TODO(jaydeep.patil): Using --skip-unimplemented for MIPS32
; RUN: %if --need=target_MIPS32 --need=allow_dump \
; RUN: --command %p2i --filetype=asm --assemble --disassemble \
; RUN: --target mips32 -i %s --args -Om1 --skip-unimplemented \
; RUN: -allow-externally-defined-symbols \
; RUN: | %if --need=target_MIPS32 --need=allow_dump \
; RUN: --command FileCheck --check-prefix MIPS32 %s
define internal i32 @testSwitch(i32 %a) { define internal i32 @testSwitch(i32 %a) {
entry: entry:
switch i32 %a, label %sw.default [ switch i32 %a, label %sw.default [
...@@ -40,6 +48,35 @@ sw.epilog: ; preds = %sw.bb2, %sw.default ...@@ -40,6 +48,35 @@ sw.epilog: ; preds = %sw.bb2, %sw.default
ret i32 %result.1 ret i32 %result.1
} }
; MIPS32-LABEL: testSwitch
; MIPS32: li {{.*}},1
; MIPS32: li {{.*}},17
; MIPS32: li {{.*}},1
; MIPS32: beq {{.*}},{{.*}},{{.*}} <[[SW_EPILOG:.*]]>
; MIPS32: li {{.*}},2
; MIPS32: beq {{.*}},{{.*}},{{.*}} <[[SW_EPILOG]]>
; MIPS32: li {{.*}},3
; MIPS32: beq {{.*}},{{.*}},{{.*}} <[[SW_EPILOG]]>
; MIPS32: li {{.*}},7
; MIPS32: beq {{.*}},{{.*}},{{.*}} <[[SW_BB1:.*]]>
; MIPS32: li {{.*}},8
; MIPS32: beq {{.*}},{{.*}},{{.*}} <[[SW_BB1]]>
; MIPS32: li {{.*}},15
; MIPS32: beq {{.*}},{{.*}},{{.*}} <[[SW_BB2:.*]]>
; MIPS32: li {{.*}},14
; MIPS32: beq {{.*}},{{.*}},{{.*}} <[[SW_BB2]]>
; MIPS32: b {{.*}} <[[SW_DEFAULT:.*]]>
; MIPS32: <[[SW_DEFAULT]]>
; MIPS32: li {{.*}},27
; MIPS32: b {{.*}} <[[SW_EPILOG]]>
; MIPS32: <[[SW_BB1]]>
; MIPS32: li {{.*}},21
; MIPS32: b {{.*}} <[[SW_BB2]]>
; MIPS32: <[[SW_BB2]]>
; MIPS32: b {{.*}} <[[SW_EPILOG]]>
; MIPS32: <[[SW_EPILOG]]>
; MIPS32: jr ra
; Check for a valid addressing mode when the switch operand is an ; Check for a valid addressing mode when the switch operand is an
; immediate. It's important that there is exactly one case, because ; immediate. It's important that there is exactly one case, because
; for two or more cases the source operand is legalized into a ; for two or more cases the source operand is legalized into a
...@@ -58,6 +95,14 @@ sw.default: ...@@ -58,6 +95,14 @@ sw.default:
; ARM32-NEXT: beq ; ARM32-NEXT: beq
; ARM32-NEXT: b ; ARM32-NEXT: b
; MIPS32-LABEL: testSwitchImm
; MIPS32: li {{.*}},10
; MIPS32: li {{.*}},1
; MIPS32: beq {{.*}},{{.*}},{{.*}} <.LtestSwitchImm$sw.default>
; MIPS32: .LtestSwitchImm$sw.default
; MIPS32: li v0,20
; MIPS32: jr ra
; Test for correct 64-bit lowering. ; Test for correct 64-bit lowering.
define internal i32 @testSwitch64(i64 %a) { define internal i32 @testSwitch64(i64 %a) {
entry: entry:
...@@ -102,6 +147,43 @@ return: ; preds = %sw.default, %sw.bb3 ...@@ -102,6 +147,43 @@ return: ; preds = %sw.default, %sw.bb3
; ARM32-NEXT: beq ; ARM32-NEXT: beq
; ARM32-NEXT: b ; ARM32-NEXT: b
; MIPS32-LABEL: testSwitch64
; MIPS32: bne {{.*}},{{.*}},{{.*}} <.LtestSwitch64$local$__0>
; MIPS32: li {{.*}},123
; MIPS32: beq {{.*}},{{.*}},{{.*}} <.LtestSwitch64$return>
; MIPS32: .LtestSwitch64$local$__0
; MIPS32: li {{.*}},0
; MIPS32: bne {{.*}},{{.*}},{{.*}} <.LtestSwitch64$local$__1>
; MIPS32: li {{.*}},234
; MIPS32: beq {{.*}},{{.*}},{{.*}} <.LtestSwitch64$sw.bb1>
; MIPS32: .LtestSwitch64$local$__1
; MIPS32: li {{.*}},0
; MIPS32: bne {{.*}},{{.*}},{{.*}} <.LtestSwitch64$local$__2>
; MIPS32: li {{.*}},345
; MIPS32: beq {{.*}},{{.*}},{{.*}} <.LtestSwitch64$sw.bb2>
; MIPS32: .LtestSwitch64$local$__2
; MIPS32: li {{.*}},18
; MIPS32: bne {{.*}},{{.*}},{{.*}} <.LtestSwitch64$local$__3>
; MIPS32: lui {{.*}},0x3456
; MIPS32: ori {{.*}},{{.*}},0x7890
; MIPS32: beq {{.*}},{{.*}},{{.*}} <.LtestSwitch64$sw.bb3>
; MIPS32: .LtestSwitch64$local$__3
; MIPS32: b {{.*}} <.LtestSwitch64$sw.default>
; MIPS32: .LtestSwitch64$sw.bb1
; MIPS32: li {{.*}},2
; MIPS32: b {{.*}} <.LtestSwitch64$return>
; MIPS32: .LtestSwitch64$sw.bb2
; MIPS32: li {{.*}},3
; MIPS32: b {{.*}} <.LtestSwitch64$return>
; MIPS32: .LtestSwitch64$sw.bb3
; MIPS32: li {{.*}},4
; MIPS32: b {{.*}} <.LtestSwitch64$return>
; MIPS32: .LtestSwitch64$sw.default
; MIPS32: li {{.*}},5
; MIPS32: b {{.*}} <.LtestSwitch64$return>
; MIPS32: .LtestSwitch64$return
; MIPS32: jr ra
; Similar to testSwitchImm, make sure proper addressing modes are ; Similar to testSwitchImm, make sure proper addressing modes are
; used. In reality, this is tested by running the output through the ; used. In reality, this is tested by running the output through the
; assembler. ; assembler.
...@@ -120,6 +202,19 @@ sw.default: ...@@ -120,6 +202,19 @@ sw.default:
; ARM32-NEXT: beq [[ADDR:[0-9a-f]+]] ; ARM32-NEXT: beq [[ADDR:[0-9a-f]+]]
; ARM32-NEXT: b [[ADDR]] ; ARM32-NEXT: b [[ADDR]]
; MIPS32-LABEL: testSwitchImm64
; MIPS32: li {{.*}},10
; MIPS32: li {{.*}},0
; MIPS32: li {{.*}},0
; MIPS32: bne {{.*}},{{.*}},{{.*}} <.LtestSwitchImm64$local$__0>
; MIPS32: li {{.*}},1
; MIPS32: beq {{.*}},{{.*}},{{.*}} <.LtestSwitchImm64$sw.default>
; MIPS32: .LtestSwitchImm64$local$__0
; MIPS32: b {{.*}} <.LtestSwitchImm64$sw.default>
; MIPS32: .LtestSwitchImm64$sw.default
; MIPS32: li {{.*}},20
; MIPS32: jr ra
define internal i32 @testSwitchUndef64() { define internal i32 @testSwitchUndef64() {
entry: entry:
switch i64 undef, label %sw.default [ switch i64 undef, label %sw.default [
...@@ -132,3 +227,16 @@ sw.default: ...@@ -132,3 +227,16 @@ sw.default:
; ARM32-LABEL: testSwitchUndef64 ; ARM32-LABEL: testSwitchUndef64
; ARM32: mov {{.*}}, #0 ; ARM32: mov {{.*}}, #0
; ARM32: mov {{.*}}, #0 ; ARM32: mov {{.*}}, #0
; MIPS32-LABEL: testSwitchUndef64
; MIPS32: li {{.*}},0
; MIPS32: li {{.*}},0
; MIPS32: li {{.*}},0
; MIPS32: bne {{.*}},{{.*}},{{.*}} <.LtestSwitchUndef64$local$__0>
; MIPS32: li {{.*}},1
; MIPS32: beq {{.*}},{{.*}},{{.*}} <.LtestSwitchUndef64$sw.default>
; MIPS32: .LtestSwitchUndef64$local$__0
; MIPS32: b {{.*}} <.LtestSwitchUndef64$sw.default>
; MIPS32: .LtestSwitchUndef64$sw.default
; MIPS32: li {{.*}},20
; MIPS32: jr ra
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