llvm-project/llvm/test/CodeGen/MIR/X86/memory-operands.mir
Craig Topper b1c304c494 [CodeGen] Try to make the print of memory operand alignment a little more user friendly.
Memory operands store a base alignment that does not factor in
the effect of the offset on the alignment.

Previously the printing code only printed the base alignment if
it was different than the size. If there is an offset, the reader
would need to figure out the effective alignment themselves. This
has confused me before and someone else was recently confused on
IRC.

This patch prints the possibly offset adjusted alignment if it is
different than the size. And prints the base alignment if it is
different than the alignment. The MIR parser has been updated to
read basealign in addition to align.

Reviewed By: arsenm

Differential Revision: https://reviews.llvm.org/D94344
2021-01-11 19:58:47 -08:00

572 lines
17 KiB
YAML

# RUN: llc -march=x86-64 -run-pass none -o - %s | FileCheck %s
# This test ensures that the MIR parser parses the machine memory operands
# correctly.
--- |
define i32 @test(i32* %a) {
entry:
%b = load i32, i32* %a
store i32 42, i32* %a
ret i32 %b
}
define void @test2(i32* %"a value") {
entry2:
%b = load i32, i32* %"a value"
%c = add i32 %b, 1
store i32 %c, i32* %"a value"
ret void
}
define void @test3(i32*) {
entry3:
%1 = alloca i32
%b = load i32, i32* %0
%c = add i32 %b, 1
store i32 %c, i32* %1
ret void
}
define i32 @volatile_inc(i32* %x) {
entry:
%0 = load volatile i32, i32* %x
%1 = add i32 %0, 1
store volatile i32 %1, i32* %x
ret i32 %1
}
define void @non_temporal_store(i32* %a, i32 %b) {
entry:
store i32 %b, i32* %a, align 16, !nontemporal !0
ret void
}
!0 = !{i32 1}
define i32 @invariant_load(i32* %x) {
entry:
%v = load i32, i32* %x, !invariant.load !1
ret i32 %v
}
!1 = !{}
define void @memory_offset(<8 x float>* %vec) {
entry:
%v = load <8 x float>, <8 x float>* %vec
%v2 = insertelement <8 x float> %v, float 0.0, i32 4
store <8 x float> %v2, <8 x float>* %vec
ret void
}
define void @memory_alignment(<16 x float>* %vec) {
entry:
%v = load <16 x float>, <16 x float>* %vec
%v2 = insertelement <16 x float> %v, float 0.0, i32 4
store <16 x float> %v2, <16 x float>* %vec
ret void
}
define double @constant_pool_psv(double %a) {
entry:
%b = fadd double %a, 3.250000e+00
ret double %b
}
declare x86_fp80 @cosl(x86_fp80) #0
define x86_fp80 @stack_psv(x86_fp80 %x) {
entry:
%y = call x86_fp80 @cosl(x86_fp80 %x) #0
ret x86_fp80 %y
}
attributes #0 = { readonly }
@G = external global i32
define i32 @got_psv() {
entry:
%a = load i32, i32* @G
%b = add i32 %a, 1
ret i32 %b
}
@0 = external global i32
define i32 @global_value() {
entry:
%a = load i32, i32* @G
%b = add i32 %a, 1
%c = load i32, i32* @0
%d = add i32 %b, %c
ret i32 %d
}
define i32 @jumptable_psv(i32 %in) {
entry:
switch i32 %in, label %def [
i32 0, label %lbl1
i32 1, label %lbl2
i32 2, label %lbl3
i32 3, label %lbl4
]
def:
ret i32 0
lbl1:
ret i32 1
lbl2:
ret i32 2
lbl3:
ret i32 4
lbl4:
ret i32 8
}
%struct.XXH_state64_t = type { i32, i32, i64, i64, i64 }
@a = common global i32 0, align 4
define i32 @tbaa_metadata() {
entry:
%0 = load i32, i32* @a, align 4, !tbaa !2
%1 = inttoptr i32 %0 to %struct.XXH_state64_t*
%total_len2 = bitcast %struct.XXH_state64_t* %1 to i32*
%2 = load i32, i32* %total_len2, align 4, !tbaa !6
ret i32 %2
}
!2 = !{!3, !3, i64 0}
!3 = !{!"int", !4, i64 0}
!4 = !{!"omnipotent char", !5, i64 0}
!5 = !{!"Simple C/C++ TBAA"}
!6 = !{!7, !3, i64 0}
!7 = !{!"XXH_state64_t", !3, i64 0, !3, i64 4, !8, i64 8, !8, i64 16, !8, i64 24}
!8 = !{!"long long", !4, i64 0}
define void @aa_scope(float* nocapture %a, float* nocapture readonly %c) #1 {
entry:
%0 = load float, float* %c, align 4, !alias.scope !9
%arrayidx.i = getelementptr inbounds float, float* %a, i64 5
store float %0, float* %arrayidx.i, align 4, !noalias !9
%1 = load float, float* %c, align 4
%arrayidx = getelementptr inbounds float, float* %a, i64 7
store float %1, float* %arrayidx, align 4
ret void
}
attributes #1 = { nounwind uwtable }
!9 = distinct !{!9, !10, !"some scope"}
!10 = distinct !{!10, !"some domain"}
define zeroext i1 @range_metadata(i8* %x) {
entry:
%0 = load i8, i8* %x, align 1, !range !11
%tobool = trunc i8 %0 to i1
ret i1 %tobool
}
!11 = !{i8 0, i8 2}
%st = type { i32, i32 }
@values = common global [50 x %st] zeroinitializer, align 16
define void @gep_value(i64 %d) {
entry:
%conv = trunc i64 %d to i32
store i32 %conv, i32* getelementptr inbounds ([50 x %st], [50 x %st]* @values, i64 0, i64 0, i32 0), align 16
ret void
}
define i8* @undef_value() {
entry:
%0 = load i8*, i8** undef, align 8
ret i8* %0
}
define void @dummy0() { ret void }
define void @dummy1() { ret void }
define void @dummy2() { ret void }
define void @dummy3() { ret void }
...
---
name: test
tracksRegLiveness: true
liveins:
- { reg: '$rdi' }
body: |
bb.0.entry:
liveins: $rdi
; CHECK: $eax = MOV32rm $rdi, 1, $noreg, 0, $noreg :: (load 4 from %ir.a)
; CHECK-NEXT: MOV32mi killed $rdi, 1, $noreg, 0, $noreg, 42 :: (store 4 into %ir.a)
$eax = MOV32rm $rdi, 1, _, 0, _ :: (load 4 from %ir.a)
MOV32mi killed $rdi, 1, _, 0, _, 42 :: (store 4 into %ir.a)
RETQ $eax
...
---
name: test2
tracksRegLiveness: true
liveins:
- { reg: '$rdi' }
body: |
bb.0.entry2:
liveins: $rdi
; CHECK: INC32m killed $rdi, 1, $noreg, 0, $noreg, implicit-def dead $eflags :: (store 4 into %ir."a value"), (load 4 from %ir."a value")
INC32m killed $rdi, 1, _, 0, _, implicit-def dead $eflags :: (store 4 into %ir."a value"), (load 4 from %ir."a value")
RETQ
...
---
name: test3
tracksRegLiveness: true
liveins:
- { reg: '$rdi' }
frameInfo:
maxAlignment: 4
stack:
- { id: 0, offset: -12, size: 4, alignment: 4 }
body: |
bb.0.entry3:
liveins: $rdi
; Verify that the unnamed local values can be serialized.
; CHECK-LABEL: name: test3
; CHECK: $eax = MOV32rm killed $rdi, 1, $noreg, 0, $noreg :: (load 4 from %ir.0)
; CHECK: MOV32mr $rsp, 1, $noreg, -4, $noreg, killed $eax :: (store 4 into %ir.1)
$eax = MOV32rm killed $rdi, 1, _, 0, _ :: (load 4 from %ir.0)
$eax = INC32r killed $eax, implicit-def dead $eflags
MOV32mr $rsp, 1, _, -4, _, killed $eax :: (store 4 into %ir.1)
RETQ
...
---
name: volatile_inc
tracksRegLiveness: true
liveins:
- { reg: '$rdi' }
body: |
bb.0.entry:
liveins: $rdi
; CHECK: name: volatile_inc
; CHECK: $eax = MOV32rm $rdi, 1, $noreg, 0, $noreg :: (volatile load 4 from %ir.x)
; CHECK: MOV32mr killed $rdi, 1, $noreg, 0, $noreg, $eax :: (volatile store 4 into %ir.x)
$eax = MOV32rm $rdi, 1, _, 0, _ :: (volatile load 4 from %ir.x)
$eax = INC32r killed $eax, implicit-def dead $eflags
MOV32mr killed $rdi, 1, _, 0, _, $eax :: (volatile store 4 into %ir.x)
RETQ $eax
...
---
name: non_temporal_store
tracksRegLiveness: true
liveins:
- { reg: '$rdi' }
- { reg: '$esi' }
body: |
bb.0.entry:
liveins: $esi, $rdi
; CHECK: name: non_temporal_store
; CHECK: MOVNTImr killed $rdi, 1, $noreg, 0, $noreg, killed $esi :: (non-temporal store 4 into %ir.a)
MOVNTImr killed $rdi, 1, _, 0, _, killed $esi :: (non-temporal store 4 into %ir.a)
RETQ
...
---
name: invariant_load
tracksRegLiveness: true
liveins:
- { reg: '$rdi' }
body: |
bb.0.entry:
liveins: $rdi
; CHECK: name: invariant_load
; CHECK: $eax = MOV32rm killed $rdi, 1, $noreg, 0, $noreg :: (invariant load 4 from %ir.x)
$eax = MOV32rm killed $rdi, 1, _, 0, _ :: (invariant load 4 from %ir.x)
RETQ $eax
...
---
name: memory_offset
tracksRegLiveness: true
liveins:
- { reg: '$rdi' }
body: |
bb.0.entry:
liveins: $rdi
; CHECK: name: memory_offset
; CHECK: $xmm0 = MOVAPSrm $rdi, 1, $noreg, 0, $noreg :: (load 16 from %ir.vec)
; CHECK-NEXT: $xmm1 = MOVAPSrm $rdi, 1, $noreg, 16, $noreg :: (load 16 from %ir.vec + 16)
; CHECK: MOVAPSmr $rdi, 1, $noreg, 0, $noreg, killed $xmm0 :: (store 16 into %ir.vec)
; CHECK-NEXT: MOVAPSmr killed $rdi, 1, $noreg, 16, $noreg, killed $xmm1 :: (store 16 into %ir.vec + 16)
$xmm0 = MOVAPSrm $rdi, 1, _, 0, _ :: (load 16 from %ir.vec)
$xmm1 = MOVAPSrm $rdi, 1, _, 16, _ :: (load 16 from %ir.vec + 16)
$xmm2 = FsFLD0SS
$xmm1 = MOVSSrr killed $xmm1, killed $xmm2
MOVAPSmr $rdi, 1, _, 0, _, killed $xmm0 :: (store 16 into %ir.vec)
MOVAPSmr killed $rdi, 1, _, 16, _, killed $xmm1 :: (store 16 into %ir.vec + 16)
RETQ
...
---
name: memory_alignment
tracksRegLiveness: true
liveins:
- { reg: '$rdi' }
body: |
bb.0.entry:
liveins: $rdi
; CHECK: name: memory_alignment
; CHECK: $xmm0 = MOVAPSrm $rdi, 1, $noreg, 0, $noreg :: (load 16 from %ir.vec, align 64)
; CHECK-NEXT: $xmm1 = MOVAPSrm $rdi, 1, $noreg, 16, $noreg :: (load 16 from %ir.vec + 16, basealign 64)
; CHECK-NEXT: $xmm2 = MOVAPSrm $rdi, 1, $noreg, 32, $noreg :: (load 16 from %ir.vec + 32, align 32, basealign 64)
; CHECK-NEXT: $xmm3 = MOVAPSrm $rdi, 1, $noreg, 48, $noreg :: (load 16 from %ir.vec + 48, basealign 64)
; CHECK: MOVAPSmr $rdi, 1, $noreg, 0, $noreg, killed $xmm0 :: (store 16 into %ir.vec, align 64)
; CHECK-NEXT: MOVAPSmr $rdi, 1, $noreg, 16, $noreg, killed $xmm1 :: (store 16 into %ir.vec + 16, basealign 64)
; CHECK-NEXT: MOVAPSmr $rdi, 1, $noreg, 32, $noreg, killed $xmm2 :: (store 16 into %ir.vec + 32, align 32, basealign 64)
; CHECK-NEXT: MOVAPSmr killed $rdi, 1, $noreg, 48, $noreg, killed $xmm3 :: (store 16 into %ir.vec + 48, basealign 64)
$xmm0 = MOVAPSrm $rdi, 1, _, 0, _ :: (load 16 from %ir.vec, align 64)
$xmm1 = MOVAPSrm $rdi, 1, _, 16, _ :: (load 16 from %ir.vec + 16, basealign 64)
$xmm2 = MOVAPSrm $rdi, 1, _, 32, _ :: (load 16 from %ir.vec + 32, align 32, basealign 64)
$xmm3 = MOVAPSrm $rdi, 1, _, 48, _ :: (load 16 from %ir.vec + 48, basealign 64)
$xmm4 = FsFLD0SS
$xmm1 = MOVSSrr killed $xmm1, killed $xmm4
MOVAPSmr $rdi, 1, _, 0, _, killed $xmm0 :: (store 16 into %ir.vec, align 64)
MOVAPSmr $rdi, 1, _, 16, _, killed $xmm1 :: (store 16 into %ir.vec + 16, basealign 64)
MOVAPSmr $rdi, 1, _, 32, _, killed $xmm2 :: (store 16 into %ir.vec + 32, align 32, basealign 64)
MOVAPSmr killed $rdi, 1, _, 48, _, killed $xmm3 :: (store 16 into %ir.vec + 48, basealign 64)
RETQ
...
---
name: constant_pool_psv
tracksRegLiveness: true
liveins:
- { reg: '$xmm0' }
constants:
- id: 0
value: 'double 3.250000e+00'
body: |
bb.0.entry:
liveins: $xmm0
; CHECK: name: constant_pool_psv
; CHECK: $xmm0 = ADDSDrm killed $xmm0, $rip, 1, $noreg, %const.0, $noreg, implicit $mxcsr :: (load 8 from constant-pool)
; CHECK-NEXT: $xmm0 = ADDSDrm killed $xmm0, $rip, 1, $noreg, %const.0, $noreg, implicit $mxcsr :: (load 8 from constant-pool + 8)
$xmm0 = ADDSDrm killed $xmm0, $rip, 1, _, %const.0, _, implicit $mxcsr :: (load 8 from constant-pool)
$xmm0 = ADDSDrm killed $xmm0, $rip, 1, _, %const.0, _, implicit $mxcsr :: (load 8 from constant-pool + 8)
RETQ $xmm0
...
---
name: stack_psv
tracksRegLiveness: true
frameInfo:
stackSize: 24
maxAlignment: 16
adjustsStack: true
hasCalls: true
maxCallFrameSize: 16
fixedStack:
- { id: 0, offset: 0, size: 10, alignment: 16, isImmutable: true, isAliased: false }
body: |
bb.0.entry:
$rsp = frame-setup SUB64ri8 $rsp, 24, implicit-def dead $eflags
CFI_INSTRUCTION def_cfa_offset 32
LD_F80m $rsp, 1, $noreg, 32, $noreg, implicit-def dead $fpsw, implicit $fpcw
; CHECK: name: stack_psv
; CHECK: ST_FP80m $rsp, 1, $noreg, 0, $noreg, implicit-def dead $fpsw, implicit $fpcw :: (store 10 into stack, align 16)
ST_FP80m $rsp, 1, _, 0, _, implicit-def dead $fpsw, implicit $fpcw :: (store 10 into stack, align 16)
CALL64pcrel32 &cosl, csr_64, implicit $rsp, implicit-def $rsp, implicit-def $fp0
$rsp = ADD64ri8 $rsp, 24, implicit-def dead $eflags
RETQ
...
---
name: got_psv
tracksRegLiveness: true
body: |
bb.0.entry:
; CHECK: name: got_psv
; CHECK: $rax = MOV64rm $rip, 1, $noreg, @G, $noreg :: (load 8 from got)
$rax = MOV64rm $rip, 1, _, @G, _ :: (load 8 from got)
$eax = MOV32rm killed $rax, 1, _, 0, _
$eax = INC32r killed $eax, implicit-def dead $eflags
RETQ $eax
...
---
name: global_value
tracksRegLiveness: true
body: |
bb.0.entry:
$rax = MOV64rm $rip, 1, _, @G, _
; CHECK-LABEL: name: global_value
; CHECK: $eax = MOV32rm killed $rax, 1, $noreg, 0, $noreg, implicit-def $rax :: (load 4 from @G)
; CHECK: $ecx = MOV32rm killed $rcx, 1, $noreg, 0, $noreg, implicit-def $rcx :: (load 4 from @0)
$eax = MOV32rm killed $rax, 1, _, 0, _, implicit-def $rax :: (load 4 from @G)
$rcx = MOV64rm $rip, 1, _, @0, _
$ecx = MOV32rm killed $rcx, 1, _, 0, _, implicit-def $rcx :: (load 4 from @0)
$eax = LEA64_32r killed $rax, 1, killed $rcx, 1, _
RETQ $eax
...
---
name: jumptable_psv
tracksRegLiveness: true
liveins:
- { reg: '$edi' }
jumpTable:
kind: label-difference32
entries:
- id: 0
blocks: [ '%bb.3.lbl1', '%bb.4.lbl2', '%bb.5.lbl3', '%bb.6.lbl4' ]
body: |
bb.0.entry:
successors: %bb.2.def, %bb.1.entry
liveins: $edi
$eax = MOV32rr $edi, implicit-def $rax
CMP32ri8 killed $edi, 3, implicit-def $eflags
JCC_1 %bb.2.def, 7, implicit killed $eflags
bb.1.entry:
successors: %bb.3.lbl1, %bb.4.lbl2, %bb.5.lbl3, %bb.6.lbl4
liveins: $rax
$rcx = LEA64r $rip, 1, _, %jump-table.0, _
; CHECK: name: jumptable_psv
; CHECK: $rax = MOVSX64rm32 $rcx, 4, killed $rax, 0, $noreg :: (load 4 from jump-table, align 8)
$rax = MOVSX64rm32 $rcx, 4, killed $rax, 0, _ :: (load 4 from jump-table, align 8)
$rax = ADD64rr killed $rax, killed $rcx, implicit-def dead $eflags
JMP64r killed $rax
bb.2.def:
$eax = MOV32r0 implicit-def dead $eflags
RETQ $eax
bb.3.lbl1:
$eax = MOV32ri 1
RETQ $eax
bb.4.lbl2:
$eax = MOV32ri 2
RETQ $eax
bb.5.lbl3:
$eax = MOV32ri 4
RETQ $eax
bb.6.lbl4:
$eax = MOV32ri 8
RETQ $eax
...
---
name: tbaa_metadata
tracksRegLiveness: true
body: |
bb.0.entry:
$rax = MOV64rm $rip, 1, _, @a, _ :: (load 8 from got)
; CHECK-LABEL: name: tbaa_metadata
; CHECK: $eax = MOV32rm killed $rax, 1, $noreg, 0, $noreg, implicit-def $rax :: (load 4 from @a, !tbaa !2)
; CHECK-NEXT: $eax = MOV32rm killed $rax, 1, $noreg, 0, $noreg :: (load 4 from %ir.total_len2, !tbaa !6)
$eax = MOV32rm killed $rax, 1, _, 0, _, implicit-def $rax :: (load 4 from @a, !tbaa !2)
$eax = MOV32rm killed $rax, 1, _, 0, _ :: (load 4 from %ir.total_len2, !tbaa !6)
RETQ $eax
...
---
name: aa_scope
tracksRegLiveness: true
liveins:
- { reg: '$rdi' }
- { reg: '$rsi' }
body: |
bb.0.entry:
liveins: $rdi, $rsi
; CHECK-LABEL: name: aa_scope
; CHECK: $xmm0 = MOVSSrm_alt $rsi, 1, $noreg, 0, $noreg :: (load 4 from %ir.c, !alias.scope !9)
$xmm0 = MOVSSrm_alt $rsi, 1, _, 0, _ :: (load 4 from %ir.c, !alias.scope !9)
; CHECK-NEXT: MOVSSmr $rdi, 1, $noreg, 20, $noreg, killed $xmm0 :: (store 4 into %ir.arrayidx.i, !noalias !9)
MOVSSmr $rdi, 1, _, 20, _, killed $xmm0 :: (store 4 into %ir.arrayidx.i, !noalias !9)
$xmm0 = MOVSSrm_alt killed $rsi, 1, _, 0, _ :: (load 4 from %ir.c)
MOVSSmr killed $rdi, 1, _, 28, _, killed $xmm0 :: (store 4 into %ir.arrayidx)
RETQ
...
---
name: range_metadata
tracksRegLiveness: true
liveins:
- { reg: '$rdi' }
body: |
bb.0.entry:
liveins: $rdi
; CHECK-LABEL: name: range_metadata
; CHECK: $al = MOV8rm killed $rdi, 1, $noreg, 0, $noreg :: (load 1 from %ir.x, !range !11)
$al = MOV8rm killed $rdi, 1, _, 0, _ :: (load 1 from %ir.x, !range !11)
RETQ $al
...
---
name: gep_value
tracksRegLiveness: true
liveins:
- { reg: '$rdi' }
body: |
bb.0.entry:
liveins: $rdi
$rax = MOV64rm $rip, 1, _, @values, _ :: (load 8 from got)
; CHECK-LABEL: gep_value
; CHECK: MOV32mr killed $rax, 1, $noreg, 0, $noreg, $edi, implicit killed $rdi :: (store 4 into `i32* getelementptr inbounds ([50 x %st], [50 x %st]* @values, i64 0, i64 0, i32 0)`, align 16)
MOV32mr killed $rax, 1, _, 0, _, $edi, implicit killed $rdi :: (store 4 into `i32* getelementptr inbounds ([50 x %st], [50 x %st]* @values, i64 0, i64 0, i32 0)`, align 16)
RETQ
...
---
name: undef_value
tracksRegLiveness: true
body: |
bb.0.entry:
; CHECK-LABEL: name: undef_value
; CHECK: $rax = MOV64rm undef $rax, 1, $noreg, 0, $noreg :: (load 8 from `i8** undef`)
$rax = MOV64rm undef $rax, 1, _, 0, _ :: (load 8 from `i8** undef`)
RETQ $rax
...
---
# Test memory operand without associated value.
# CHECK-LABEL: name: dummy0
# CHECK: $rax = MOV64rm undef $rax, 1, $noreg, 0, $noreg :: (load 8)
name: dummy0
tracksRegLiveness: true
body: |
bb.0:
$rax = MOV64rm undef $rax, 1, _, 0, _ :: (load 8)
RETQ $rax
...
---
# Test parsing of stack references in machine memory operands.
# CHECK-LABEL: name: dummy1
# CHECK: $rax = MOV64rm $rsp, 1, $noreg, 0, $noreg :: (load 8 from %stack.0)
name: dummy1
tracksRegLiveness: true
stack:
- { id: 0, size: 4, alignment: 4 }
body: |
bb.0:
$rax = MOV64rm $rsp, 1, _, 0, _ :: (load 8 from %stack.0)
RETQ $rax
...
---
# Test parsing of unknown size in machine memory operands without alignment.
# CHECK-LABEL: name: dummy2
# CHECK: $rax = MOV64rm $rsp, 1, $noreg, 0, $noreg :: (load unknown-size from %stack.0, align 1)
name: dummy2
tracksRegLiveness: true
stack:
- { id: 0, size: 4, alignment: 4 }
body: |
bb.0:
$rax = MOV64rm $rsp, 1, _, 0, _ :: (load unknown-size from %stack.0)
RETQ $rax
...
---
# Test parsing of unknown size in machine memory operands with alignment.
# CHECK-LABEL: name: dummy3
# CHECK: $rax = MOV64rm $rsp, 1, $noreg, 0, $noreg :: (load unknown-size from %stack.0, align 4)
name: dummy3
tracksRegLiveness: true
stack:
- { id: 0, size: 4, alignment: 4 }
body: |
bb.0:
$rax = MOV64rm $rsp, 1, _, 0, _ :: (load unknown-size from %stack.0, align 4)
RETQ $rax
...