412 lines
8.7 KiB
ArmAsm
412 lines
8.7 KiB
ArmAsm
@ RUN: llvm-mc -triple thumbv7a--none-eabi -arm-implicit-it=always < %s -show-encoding | FileCheck %s
|
|
|
|
@ Single instruction
|
|
.section test1
|
|
@ CHECK-LABEL: test1
|
|
addeq r0, #1
|
|
@ CHECK: it eq
|
|
@ CHECK: addeq
|
|
|
|
@ Multiple instructions, same condition
|
|
.section test2
|
|
@ CHECK-LABEL: test2
|
|
addeq r0, #1
|
|
addeq r0, #1
|
|
addeq r0, #1
|
|
addeq r0, #1
|
|
@ CHECK: itttt eq
|
|
@ CHECK: addeq
|
|
@ CHECK: addeq
|
|
@ CHECK: addeq
|
|
@ CHECK: addeq
|
|
|
|
@ Multiple instructions, equal but opposite conditions
|
|
.section test3
|
|
@ CHECK-LABEL: test3
|
|
addeq r0, #1
|
|
addne r0, #1
|
|
addeq r0, #1
|
|
addne r0, #1
|
|
@ CHECK: itete eq
|
|
@ CHECK: addeq
|
|
@ CHECK: addne
|
|
@ CHECK: addeq
|
|
@ CHECK: addne
|
|
|
|
@ Multiple instructions, unrelated conditions
|
|
.section test4
|
|
@ CHECK-LABEL: test4
|
|
addeq r0, #1
|
|
addlt r0, #1
|
|
addeq r0, #1
|
|
addge r0, #1
|
|
@ CHECK: it eq
|
|
@ CHECK: addeq
|
|
@ CHECK: it lt
|
|
@ CHECK: addlt
|
|
@ CHECK: it eq
|
|
@ CHECK: addeq
|
|
@ CHECK: it ge
|
|
@ CHECK: addge
|
|
|
|
@ More than 4 instructions eligible for a block
|
|
.section test5
|
|
@ CHECK-LABEL: test5
|
|
addeq r0, #1
|
|
addeq r0, #1
|
|
addeq r0, #1
|
|
addeq r0, #1
|
|
addeq r0, #1
|
|
addeq r0, #1
|
|
@ CHECK: itttt eq
|
|
@ CHECK: addeq
|
|
@ CHECK: addeq
|
|
@ CHECK: addeq
|
|
@ CHECK: addeq
|
|
@ CHECK: itt eq
|
|
@ CHECK: addeq
|
|
@ CHECK: addeq
|
|
|
|
@ Flush on a label
|
|
.section test6
|
|
@ CHECK-LABEL: test6
|
|
addeq r0, #1
|
|
label:
|
|
addeq r0, #1
|
|
five:
|
|
addeq r0, #1
|
|
@ CHECK: it eq
|
|
@ CHECK: addeq
|
|
@ CHECK: label
|
|
@ CHECK: it eq
|
|
@ CHECK: addeq
|
|
@ CHECK: five
|
|
@ CHECK: it eq
|
|
@ CHECK: addeq
|
|
|
|
@ Flush on a section-change directive
|
|
.section test7a
|
|
@ CHECK-LABEL: test7a
|
|
addeq r0, #1
|
|
.section test7b
|
|
addeq r0, #1
|
|
.previous
|
|
addeq r0, #1
|
|
.pushsection test7c
|
|
addeq r0, #1
|
|
.popsection
|
|
addeq r0, #1
|
|
@ CHECK: it eq
|
|
@ CHECK: addeq
|
|
@ CHECK: it eq
|
|
@ CHECK: addeq
|
|
@ CHECK: it eq
|
|
@ CHECK: addeq
|
|
@ CHECK: it eq
|
|
@ CHECK: addeq
|
|
@ CHECK: it eq
|
|
@ CHECK: addeq
|
|
|
|
@ Flush on an ISA change (even to the same ISA)
|
|
.section test8
|
|
@ CHECK-LABEL: test8
|
|
addeq r0, #1
|
|
.thumb
|
|
addeq r0, #1
|
|
.arm
|
|
addeq r0, #1
|
|
.thumb
|
|
addeq r0, #1
|
|
@ CHECK: it eq
|
|
@ CHECK: addeq
|
|
@ CHECK: it eq
|
|
@ CHECK: addeq
|
|
@ CHECK: addeq
|
|
@ CHECK: it eq
|
|
@ CHECK: addeq
|
|
|
|
@ Flush on an arch, cpu or fpu change
|
|
.section test9
|
|
@ CHECK-LABEL: test9
|
|
addeq r0, #1
|
|
.arch armv7-a
|
|
addeq r0, #1
|
|
.cpu cortex-a15
|
|
addeq r0, #1
|
|
.fpu vfpv3
|
|
addeq r0, #1
|
|
@ CHECK: it eq
|
|
@ CHECK: addeq
|
|
@ CHECK: it eq
|
|
@ CHECK: addeq
|
|
@ CHECK: it eq
|
|
@ CHECK: addeq
|
|
@ CHECK: it eq
|
|
@ CHECK: addeq
|
|
|
|
@ Flush on an unpredicable instruction
|
|
.section test10
|
|
@ CHECK-LABEL: test10
|
|
addeq r0, #1
|
|
setend le
|
|
addeq r0, #1
|
|
hvc #0
|
|
addeq r0, #1
|
|
@ CHECK: it eq
|
|
@ CHECK: addeq
|
|
@ CHECK: setend le
|
|
@ CHECK: it eq
|
|
@ CHECK: addeq
|
|
@ CHECK: hvc.w #0
|
|
@ CHECK: it eq
|
|
@ CHECK: addeq
|
|
|
|
@ Flush when reaching an explicit IT instruction
|
|
.section test11
|
|
@ CHECK-LABEL: test11
|
|
addeq r0, #1
|
|
it eq
|
|
addeq r0, #1
|
|
@ CHECK: it eq
|
|
@ CHECK: addeq
|
|
@ CHECK: it eq
|
|
@ CHECK: addeq
|
|
|
|
@ Don't extend an explicit IT instruction
|
|
.section test12
|
|
@ CHECK-LABEL: test12
|
|
it eq
|
|
addeq r0, #1
|
|
addeq r0, #1
|
|
@ CHECK: it eq
|
|
@ CHECK: addeq
|
|
@ CHECK: it eq
|
|
@ CHECK: addeq
|
|
|
|
@ Branch-like instructions can only be used at the end of an IT block, so
|
|
@ terminate it.
|
|
.section test13
|
|
@ CHECK-LABEL: test13
|
|
.cpu cortex-a15
|
|
addeq pc, r0
|
|
addeq pc, sp, pc
|
|
ldreq pc, [r0, #4]
|
|
ldreq pc, [r0, #-4]
|
|
ldreq pc, [r0, r1]
|
|
ldreq pc, [pc, #-0]
|
|
moveq pc, r0
|
|
bleq #4
|
|
blxeq #4
|
|
blxeq r0
|
|
bxeq r0
|
|
bxjeq r0
|
|
tbbeq [r0, r1]
|
|
tbheq [r0, r1, lsl #1]
|
|
ereteq
|
|
rfeiaeq r0
|
|
rfeiaeq r0!
|
|
rfedbeq r0
|
|
rfedbeq r0!
|
|
smceq #0
|
|
ldmiaeq r0, {pc}
|
|
ldmiaeq r0!, {r1, pc}
|
|
ldmdbeq r0, {pc}
|
|
ldmdbeq r0!, {r1, pc}
|
|
popeq {pc}
|
|
.arch armv8-m.main
|
|
bxnseq r0
|
|
blxnseq r0
|
|
@ CHECK: it eq
|
|
@ CHECK: addeq pc, r0
|
|
@ CHECK: it eq
|
|
@ CHECK: addeq pc, sp, pc
|
|
@ CHECK: it eq
|
|
@ CHECK: ldreq.w pc, [r0, #4]
|
|
@ CHECK: it eq
|
|
@ CHECK: ldreq pc, [r0, #-4]
|
|
@ CHECK: it eq
|
|
@ CHECK: ldreq.w pc, [r0, r1]
|
|
@ CHECK: it eq
|
|
@ CHECK: ldreq.w pc, [pc, #-0]
|
|
@ CHECK: it eq
|
|
@ CHECK: moveq pc, r0
|
|
@ CHECK: it eq
|
|
@ CHECK: bleq #4
|
|
@ CHECK: it eq
|
|
@ CHECK: blxeq #4
|
|
@ CHECK: it eq
|
|
@ CHECK: blxeq r0
|
|
@ CHECK: it eq
|
|
@ CHECK: bxeq r0
|
|
@ CHECK: it eq
|
|
@ CHECK: bxjeq r0
|
|
@ CHECK: it eq
|
|
@ CHECK: tbbeq [r0, r1]
|
|
@ CHECK: it eq
|
|
@ CHECK: tbheq [r0, r1, lsl #1]
|
|
@ CHECK: it eq
|
|
@ CHECK: ereteq
|
|
@ CHECK: it eq
|
|
@ CHECK: rfeiaeq r0
|
|
@ CHECK: it eq
|
|
@ CHECK: rfeiaeq r0!
|
|
@ CHECK: it eq
|
|
@ CHECK: rfedbeq r0
|
|
@ CHECK: it eq
|
|
@ CHECK: rfedbeq r0!
|
|
@ CHECK: it eq
|
|
@ CHECK: smceq #0
|
|
@ CHECK: it eq
|
|
@ CHECK: ldmeq.w r0, {pc}
|
|
@ CHECK: it eq
|
|
@ CHECK: ldmeq.w r0!, {r1, pc}
|
|
@ CHECK: it eq
|
|
@ CHECK: ldmdbeq r0, {pc}
|
|
@ CHECK: it eq
|
|
@ CHECK: ldmdbeq r0!, {r1, pc}
|
|
@ CHECK: it eq
|
|
@ CHECK: popeq {pc}
|
|
@ CHECK: it eq
|
|
@ CHECK: bxnseq r0
|
|
@ CHECK: it eq
|
|
@ CHECK: blxnseq r0
|
|
|
|
@ Thumb 16-bit ALU instructions set the flags iff they are not in an IT block,
|
|
@ so instruction matching must change when generating an implicit IT block.
|
|
.section test14
|
|
@ CHECK-LABEL: test14
|
|
@ Outside an IT block, the 16-bit encoding must set flags
|
|
add r0, #1
|
|
@ CHECK:add.w r0, r0, #1 @ encoding: [0x00,0xf1,0x01,0x00]
|
|
adds r0, #1
|
|
@ CHECK: adds r0, #1 @ encoding: [0x01,0x30]
|
|
@ Inside an IT block, the 16-bit encoding can not set flags
|
|
addeq r0, #1
|
|
@ CHECK: itt eq
|
|
@ CHECK: addeq r0, #1 @ encoding: [0x01,0x30]
|
|
addseq r0, #1
|
|
@ CHECK: addseq.w r0, r0, #1 @ encoding: [0x10,0xf1,0x01,0x00]
|
|
|
|
@ Some variants of the B instruction have their own condition code field, and
|
|
@ are not valid in IT blocks.
|
|
.section test15
|
|
@ CHECK-LABEL: test15
|
|
@ Outside of an IT block, the 4 variants (narrow/wide,
|
|
@ predicated/non-predicated) are selected as normal, and the predicated
|
|
@ encodings are used instead of opening a new IT block:
|
|
b #0x100
|
|
@ CHECK: b #256 @ encoding: [0x80,0xe0]
|
|
b #0x800
|
|
@ CHECK: b.w #2048 @ encoding: [0x00,0xf0,0x00,0xbc]
|
|
beq #0x4
|
|
@ CHECK-NOT: it
|
|
@ CHECK: beq #4 @ encoding: [0x02,0xd0]
|
|
beq #0x100
|
|
@ CHECK-NOT: it
|
|
@ CHECK: beq.w #256 @ encoding: [0x00,0xf0,0x80,0x80]
|
|
|
|
@ We could support "beq #0x100000" to "beq #0x1fffffc" by using t2Bcc in
|
|
@ an IT block (these currently fail as the target is out of range). However, long
|
|
@ ranges like this are rarely assembly-time constants, so this probably isn't
|
|
@ worth doing.
|
|
|
|
@ If we already have an open IT block, we can use the non-predicated encodings,
|
|
@ which have a greater range:
|
|
addeq r0, r1
|
|
beq #0x4
|
|
@ CHECK: itt eq
|
|
@ CHECK: addeq r0, r1
|
|
@ CHECK: beq #4 @ encoding: [0x02,0xe0]
|
|
addeq r0, r1
|
|
beq #0x100
|
|
@ CHECK: itt eq
|
|
@ CHECK: addeq r0, r1
|
|
@ CHECK: beq #256 @ encoding: [0x80,0xe0]
|
|
addeq r0, r1
|
|
beq #0x800
|
|
@ CHECK: itt eq
|
|
@ CHECK: addeq r0, r1
|
|
@ CHECK: beq.w #2048 @ encoding: [0x00,0xf0,0x00,0xbc]
|
|
|
|
@ If we have an open but incompatible IT block, we close it and use the
|
|
@ self-predicated encodings, without an IT block:
|
|
addeq r0, r1
|
|
bgt #0x4
|
|
@ CHECK: it eq
|
|
@ CHECK: addeq r0, r1
|
|
@ CHECK: bgt #4 @ encoding: [0x02,0xdc]
|
|
addeq r0, r1
|
|
bgt #0x100
|
|
@ CHECK: it eq
|
|
@ CHECK: addeq r0, r1
|
|
@ CHECK: bgt.w #256 @ encoding: [0x00,0xf3,0x80,0x80]
|
|
|
|
@ Breakpoint instructions are allowed in IT blocks, but are always executed
|
|
@ regardless of the condition flags. We could continue an IT block through
|
|
@ them, but currently do not.
|
|
.section test16
|
|
@ CHECK-LABEL: test16
|
|
addeq r0, r1
|
|
bkpt #0
|
|
addeq r0, r1
|
|
@ CHECK: it eq
|
|
@ CHECK: addeq r0, r1
|
|
@ CHECK: bkpt #0
|
|
@ CHECK: it eq
|
|
@ CHECK: addeq r0, r1
|
|
|
|
@ The .if directive causes entire assembly statments to be dropped before they
|
|
@ reach the IT block generation code. This happens to be exactly what we want,
|
|
@ and allows IT blocks to extend into and out of .if blocks. Only one arm of the
|
|
@ .if will be seen by the IT state tracking code, so the subeq shouldn't have
|
|
@ any effect here.
|
|
.section test17
|
|
@ CHECK-LABEL: test17
|
|
addeq r0, r1
|
|
.if 1
|
|
addeq r0, r1
|
|
.else
|
|
subeq r0, r1
|
|
.endif
|
|
addeq r0, r1
|
|
@ CHECK: ittt eq
|
|
@ CHECK: addeq
|
|
@ CHECK: addeq
|
|
@ CHECK: addeq
|
|
|
|
@ TODO: There are some other directives which we could continue through, such
|
|
@ as .set and .global, but we currently conservatively flush the IT block before
|
|
@ every directive (except for .if and friends, which are handled separately).
|
|
.section test18
|
|
@ CHECK-LABEL: test18
|
|
addeq r0, r1
|
|
.set s, 1
|
|
addeq r0, r1
|
|
@ CHECK: it eq
|
|
@ CHECK: addeq
|
|
@ CHECK: it eq
|
|
@ CHECK: addeq
|
|
|
|
@ The .rept directive can be used to create long IT blocks.
|
|
.section test19
|
|
@ CHECK-LABEL: test19
|
|
.rept 3
|
|
addeq r0, r1
|
|
subne r0, r1
|
|
.endr
|
|
@ CHECK: itete eq
|
|
@ CHECK: addeq r0, r1
|
|
@ CHECK: subne r0, r0, r1
|
|
@ CHECK: addeq r0, r1
|
|
@ CHECK: subne r0, r0, r1
|
|
@ CHECK: ite eq
|
|
@ CHECK: addeq r0, r1
|
|
@ CHECK: subne r0, r0, r1
|
|
|
|
@ Flush at end of file
|
|
.section test99
|
|
@ CHECK-LABEL: test99
|
|
addeq r0, #1
|
|
@ CHECK: it eq
|
|
@ CHECK: addeq
|