# RUN: llc -march=x86-64 -start-after branch-folder -stop-after branch-folder -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(<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 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 } ... --- name: test tracksRegLiveness: true liveins: - { reg: '%rdi' } body: | bb.0.entry: liveins: %rdi ; CHECK: %eax = MOV32rm %rdi, 1, _, 0, _ :: (load 4 from %ir.a) ; CHECK-NEXT: MOV32mi killed %rdi, 1, _, 0, _, 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, _, 0, _, 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, _, 0, _ :: (load 4 from %ir.0) ; CHECK: MOV32mr %rsp, 1, _, -4, _, 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, _, 0, _ :: (volatile load 4 from %ir.x) ; CHECK: MOV32mr killed %rdi, 1, _, 0, _, %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, _, 0, _, 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, _, 0, _ :: (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, _, 0, _ :: (load 16 from %ir.vec) ; CHECK-NEXT: %xmm1 = MOVAPSrm %rdi, 1, _, 16, _ :: (load 16 from %ir.vec + 16) ; CHECK: MOVAPSmr %rdi, 1, _, 0, _, killed %xmm0 :: (store 16 into %ir.vec) ; CHECK-NEXT: MOVAPSmr killed %rdi, 1, _, 16, _, 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, _, 0, _ :: (load 16 from %ir.vec, align 32) ; CHECK-NEXT: %xmm1 = MOVAPSrm %rdi, 1, _, 16, _ :: (load 16 from %ir.vec + 16, align 32) ; CHECK: MOVAPSmr %rdi, 1, _, 0, _, killed %xmm0 :: (store 16 into %ir.vec, align 32) ; CHECK-NEXT: MOVAPSmr killed %rdi, 1, _, 16, _, killed %xmm1 :: (store 16 into %ir.vec + 16, align 32) %xmm0 = MOVAPSrm %rdi, 1, _, 0, _ :: (load 16 from %ir.vec, align 32) %xmm1 = MOVAPSrm %rdi, 1, _, 16, _ :: (load 16 from %ir.vec + 16, align 32) %xmm2 = FsFLD0SS %xmm1 = MOVSSrr killed %xmm1, killed %xmm2 MOVAPSmr %rdi, 1, _, 0, _, killed %xmm0 :: (store 16 into %ir.vec, align 32) MOVAPSmr killed %rdi, 1, _, 16, _, killed %xmm1 :: (store 16 into %ir.vec + 16, align 32) 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, _, %const.0, _ :: (load 8 from constant-pool) ; CHECK-NEXT: %xmm0 = ADDSDrm killed %xmm0, %rip, 1, _, %const.0, _ :: (load 8 from constant-pool + 8) %xmm0 = ADDSDrm killed %xmm0, %rip, 1, _, %const.0, _ :: (load 8 from constant-pool) %xmm0 = ADDSDrm killed %xmm0, %rip, 1, _, %const.0, _ :: (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 .cfi_def_cfa_offset 32 LD_F80m %rsp, 1, _, 32, _, implicit-def dead %fpsw ; CHECK: name: stack_psv ; CHECK: ST_FP80m %rsp, 1, _, 0, _, implicit-def dead %fpsw :: (store 10 into stack, align 16) ST_FP80m %rsp, 1, _, 0, _, implicit-def dead %fpsw :: (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, _, @G, _ :: (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, _, 0, _, implicit-def %rax :: (load 4 from @G) ; CHECK: %ecx = MOV32rm killed %rcx, 1, _, 0, _, 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 JA_1 %bb.2.def, 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, _ :: (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, _, 0, _, implicit-def %rax :: (load 4 from @a, !tbaa !2) ; CHECK-NEXT: %eax = MOV32rm killed %rax, 1, _, 0, _ :: (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 %rsi, 1, _, 0, _ :: (load 4 from %ir.c, !alias.scope !9) %xmm0 = MOVSSrm %rsi, 1, _, 0, _ :: (load 4 from %ir.c, !alias.scope !9) ; CHECK-NEXT: MOVSSmr %rdi, 1, _, 20, _, 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 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, _, 0, _ :: (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, _, 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) 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, _, 0, _ :: (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, _, 0, _ :: (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, _, 0, _ :: (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 ...