xref: /minix3/sys/external/bsd/compiler_rt/dist/lib/builtins/arm/switch16.S (revision 0a6a1f1d05b60e214de2f05a7310ddd1f0e590e7)
1*0a6a1f1dSLionel Sambuc//===-- switch.S - Implement switch* --------------------------------------===//
2*0a6a1f1dSLionel Sambuc//
3*0a6a1f1dSLionel Sambuc//                     The LLVM Compiler Infrastructure
4*0a6a1f1dSLionel Sambuc//
5*0a6a1f1dSLionel Sambuc// This file is dual licensed under the MIT and the University of Illinois Open
6*0a6a1f1dSLionel Sambuc// Source Licenses. See LICENSE.TXT for details.
7*0a6a1f1dSLionel Sambuc//
8*0a6a1f1dSLionel Sambuc//===----------------------------------------------------------------------===//
9*0a6a1f1dSLionel Sambuc
10*0a6a1f1dSLionel Sambuc#include "../assembly.h"
11*0a6a1f1dSLionel Sambuc
12*0a6a1f1dSLionel Sambuc//
13*0a6a1f1dSLionel Sambuc// When compiling switch statements in thumb mode, the compiler
14*0a6a1f1dSLionel Sambuc// can use these __switch* helper functions  The compiler emits a blx to
15*0a6a1f1dSLionel Sambuc// the __switch* function followed by a table of displacements for each
16*0a6a1f1dSLionel Sambuc// case statement.  On entry, R0 is the index into the table. The __switch*
17*0a6a1f1dSLionel Sambuc// function uses the return address in lr to find the start of the table.
18*0a6a1f1dSLionel Sambuc// The first entry in the table is the count of the entries in the table.
19*0a6a1f1dSLionel Sambuc// It then uses R0 to index into the table and get the displacement of the
20*0a6a1f1dSLionel Sambuc// address to jump to.  If R0 is greater than the size of the table, it jumps
21*0a6a1f1dSLionel Sambuc// to the last entry in the table. Each displacement in the table is actually
22*0a6a1f1dSLionel Sambuc// the distance from lr to the label, thus making the tables PIC.
23*0a6a1f1dSLionel Sambuc
24*0a6a1f1dSLionel Sambuc
25*0a6a1f1dSLionel Sambuc	.text
26*0a6a1f1dSLionel Sambuc	.syntax unified
27*0a6a1f1dSLionel Sambuc
28*0a6a1f1dSLionel Sambuc//
29*0a6a1f1dSLionel Sambuc// The table contains signed 2-byte sized elements which are 1/2 the distance
30*0a6a1f1dSLionel Sambuc// from lr to the target label.
31*0a6a1f1dSLionel Sambuc//
32*0a6a1f1dSLionel Sambuc	.p2align 2
33*0a6a1f1dSLionel SambucDEFINE_COMPILERRT_PRIVATE_FUNCTION(__switch16)
34*0a6a1f1dSLionel Sambuc	ldrh    ip, [lr, #-1]           // get first 16-bit word in table
35*0a6a1f1dSLionel Sambuc	cmp     r0, ip                  // compare with index
36*0a6a1f1dSLionel Sambuc	add     r0, lr, r0, lsl #1      // compute address of element in table
37*0a6a1f1dSLionel Sambuc	add     ip, lr, ip, lsl #1      // compute address of last element in table
38*0a6a1f1dSLionel Sambuc	ite lo
39*0a6a1f1dSLionel Sambuc	ldrshlo r0, [r0, #1]            // load 16-bit element if r0 is in range
40*0a6a1f1dSLionel Sambuc	ldrshhs r0, [ip, #1]            // load 16-bit element if r0 out of range
41*0a6a1f1dSLionel Sambuc	add     ip, lr, r0, lsl #1      // compute label = lr + element*2
42*0a6a1f1dSLionel Sambuc	bx      ip                      // jump to computed label
43*0a6a1f1dSLionel SambucEND_COMPILERRT_FUNCTION(__switch16)
44*0a6a1f1dSLionel Sambuc
45