SPRUI03E June 2015 – January 2023
The $LABEL_DIFF(x,y) operator can be applied to an argument for a 32-bit data-defining directive (like .word, for example). The operator simply computes the difference between two labels that are defined in the same section. This operator is sometimes used by the compiler under the Linux ABI (--linux compiler option) when generating position independent code for a switch statement.
For example, in Generating a Switch Table With Offset Switch Case Labels a switch table is generated which contains the PC-relative offsets of the switch case labels:
.asg A15, FP
.asg B14, DP
.asg B15, SP
.sect ".text"
.clink
.global myfunc
;******************************************************************************
;* FUNCTION NAME: myfunc *
;******************************************************************************
myfunc:
;** --------------------------------------------------------------------------*
B .S1 $C$L10
|| SUB .L2X A4,10,B5
|| STW .D2T2 B3,*SP--(16)
CMPGTU .L2 B5,7,B0
|| STW .D2T1 A4,*+SP(12)
|| MV .S2X A4,B4
[ B0] BNOP .S1 $C$L9,3
; BRANCH OCCURS {$C$L10} ; |6|
;** --------------------------------------------------------------------------*
$C$L1:
<case 0 code>
...
;** --------------------------------------------------------------------------*
$C$L2:
<case 1 code>
...
;** --------------------------------------------------------------------------*
$C$L3:
<case 2 code>
...
;** --------------------------------------------------------------------------*
$C$L4:
<case 3 code>
...
;** --------------------------------------------------------------------------*
$C$L5:
<case 4 code>
...
;** --------------------------------------------------------------------------*
$C$L6:
<case 5 code>
...
;** --------------------------------------------------------------------------*
$C$L7:
<case 6 code>
...
;** --------------------------------------------------------------------------*
$C$L8:
<case 7 code>
...
;** --------------------------------------------------------------------------*
$C$L9:
<default case code>
...
;** --------------------------------------------------------------------------*
$C$L10:
NOP 2
; BRANCHCC OCCURS {$C$L9} {-9} ;
;** --------------------------------------------------------------------------*
SUB .L2 B4,10,B5 ; Norm switch value -> switch table index
|| ADDKPC .S2 $C$SW1,B4,0 ; Load address of switch table to B4
LDW .D2T2 *+B4[B5],B5 ; Load PC-relative offset from switch table
NOP 4
ADD .L2 B5,B4,B4 ; Combine to get case label into B5
BNOP .S2 B4,5 ; Branch to case label
; BRANCH OCCURS {B4} ;
; Switch table definition
.align 32
.clink
$C$SW1: .nocmp
.word $LABEL_DIFF($C$L1,$C$SW1) ; 10
.word $LABEL_DIFF($C$L2,$C$SW1) ; 11
.word $LABEL_DIFF($C$L3,$C$SW1) ; 12
.word $LABEL_DIFF($C$L4,$C$SW1) ; 13
.word $LABEL_DIFF($C$L5,$C$SW1) ; 14
.word $LABEL_DIFF($C$L6,$C$SW1) ; 15
.word $LABEL_DIFF($C$L7,$C$SW1) ; 16
.word $LABEL_DIFF($C$L8,$C$SW1) ; 17
.align 32
.sect ".text"
...
Generating a Switch Table With Offset Switch Case Labels mixes data into the code section. Compression is disabled for the code section that contains the $LABEL_DIFF() operator, since the label difference must resolve to a constant value during assembly.