Implement ARM32 switch lowering.
A naive implementation of switch lowering using sequential tests for each of the cases.
BUG= none
TEST=switch-opt.ll
R=jvoung@chromium.org
Review URL: https://codereview.chromium.org/1213593002.
diff --git a/src/IceTargetLoweringARM32.cpp b/src/IceTargetLoweringARM32.cpp
index 4797683..b1081b3 100644
--- a/src/IceTargetLoweringARM32.cpp
+++ b/src/IceTargetLoweringARM32.cpp
@@ -2037,8 +2037,36 @@
}
void TargetARM32::lowerSwitch(const InstSwitch *Inst) {
- (void)Inst;
- UnimplementedError(Func->getContext()->getFlags());
+ // This implements the most naive possible lowering.
+ // cmp a,val[0]; jeq label[0]; cmp a,val[1]; jeq label[1]; ... jmp default
+ Operand *Src0 = Inst->getComparison();
+ SizeT NumCases = Inst->getNumCases();
+ if (Src0->getType() == IceType_i64) {
+ // TODO(jvoung): handle and test undef for Src0
+ Variable *Src0Lo = legalizeToVar(loOperand(Src0));
+ Variable *Src0Hi = legalizeToVar(hiOperand(Src0));
+ for (SizeT I = 0; I < NumCases; ++I) {
+ Operand *ValueLo = Ctx->getConstantInt32(Inst->getValue(I));
+ Operand *ValueHi = Ctx->getConstantInt32(Inst->getValue(I) >> 32);
+ ValueLo = legalize(ValueLo, Legal_Reg | Legal_Flex);
+ ValueHi = legalize(ValueHi, Legal_Reg | Legal_Flex);
+ _cmp(Src0Lo, ValueLo);
+ _cmp(Src0Hi, ValueHi, CondARM32::EQ);
+ _br(Inst->getLabel(I), CondARM32::EQ);
+ }
+ _br(Inst->getLabelDefault());
+ return;
+ }
+
+ // 32 bit integer
+ Variable *Src0Var = legalizeToVar(Src0);
+ for (SizeT I = 0; I < NumCases; ++I) {
+ Operand *Value = Ctx->getConstantInt32(Inst->getValue(I));
+ Value = legalize(Value, Legal_Reg | Legal_Flex);
+ _cmp(Src0Var, Value);
+ _br(Inst->getLabel(I), CondARM32::EQ);
+ }
+ _br(Inst->getLabelDefault());
}
void TargetARM32::lowerUnreachable(const InstUnreachable * /*Inst*/) {
diff --git a/src/IceTargetLoweringARM32.h b/src/IceTargetLoweringARM32.h
index fdb025f..1691d6c 100644
--- a/src/IceTargetLoweringARM32.h
+++ b/src/IceTargetLoweringARM32.h
@@ -183,6 +183,9 @@
void _br(CfgNode *Target) {
Context.insert(InstARM32Br::create(Func, Target));
}
+ void _br(CfgNode *Target, CondARM32::Cond Condition) {
+ Context.insert(InstARM32Br::create(Func, Target, Condition));
+ }
void _cmp(Variable *Src0, Operand *Src1,
CondARM32::Cond Pred = CondARM32::AL) {
Context.insert(InstARM32Cmp::create(Func, Src0, Src1, Pred));
diff --git a/tests_lit/llvm2ice_tests/switch-opt.ll b/tests_lit/llvm2ice_tests/switch-opt.ll
index 1fbe064..ed6b8b7 100644
--- a/tests_lit/llvm2ice_tests/switch-opt.ll
+++ b/tests_lit/llvm2ice_tests/switch-opt.ll
@@ -4,6 +4,11 @@
; RUN: %p2i -i %s --filetype=obj --disassemble --args -O2 | FileCheck %s
+; TODO(jvoung): Update to -02 once the phi assignments is done for ARM
+; RUN: %if --need=target_ARM32 --command %p2i --filetype=asm --assemble \
+; RUN: --disassemble --target arm32 -i %s --args -Om1 --skip-unimplemented \
+; RUN: | %if --need=target_ARM32 --command FileCheck --check-prefix ARM32 %s
+
define i32 @testSwitch(i32 %a) {
entry:
switch i32 %a, label %sw.default [
@@ -49,6 +54,11 @@
; CHECK-LABEL: testSwitchImm
; CHECK-NOT: cmp 0x{{[0-9a-f]*}},
+; ARM32-LABEL: testSwitchImm
+; ARM32: cmp {{r[0-9]+}}, #1
+; ARM32-NEXT: beq
+; ARM32-NEXT: b
+
; Test for correct 64-bit lowering.
define internal i32 @testSwitch64(i64 %a) {
entry:
@@ -93,6 +103,24 @@
; CHECK-NEXT: cmp {{.*}},0x12
; CHECK-NEXT: je
+; ARM32-LABEL: testSwitch64
+; ARM32: cmp {{r[0-9]+}}, #123
+; ARM32-NEXT: cmpeq {{r[0-9]+}}, #0
+; ARM32-NEXT: beq
+; ARM32: cmp {{r[0-9]+}}, #234
+; ARM32-NEXT: cmpeq {{r[0-9]+}}, #0
+; ARM32-NEXT: beq
+; ARM32: movw [[REG:r[0-9]+]], #345
+; ARM32-NEXT: cmp {{r[0-9]+}}, [[REG]]
+; ARM32-NEXT: cmpeq {{r[0-9]+}}, #0
+; ARM32-NEXT: beq
+; ARM32: movw [[REG:r[0-9]+]], #30864
+; ARM32-NEXT: movt [[REG]], #13398
+; ARM32-NEXT: cmp {{r[0-9]+}}, [[REG]]
+; ARM32-NEXT: cmpeq {{r[0-9]+}}, #18
+; ARM32-NEXT: beq
+; ARM32-NEXT: b
+
; Similar to testSwitchImm, make sure proper addressing modes are
; used. In reality, this is tested by running the output through the
; assembler.
@@ -110,3 +138,10 @@
; CHECK-NEXT: jne
; CHECK-NEXT: cmp {{.*}},0x0
; CHECK-NEXT: je
+
+; ARM32-LABEL: testSwitchImm64
+; ARM32: cmp {{r[0-9]+}}, #1
+; ARM32-NEXT: cmpeq {{r[0-9]+}}, #0
+; ARM32-NEXT: beq [[ADDR:[0-9a-f]+]]
+; ARM32-NEXT: b [[ADDR]]
+