| # RUN: llc -mtriple=x86_64-unknown-linux-gnu -run-pass simple-register-coalescing -o - %s | FileCheck %s | |
| # Check there is no partial redundent copy left in the loop after register coalescing. | |
| --- | | |
| ; ModuleID = '<stdin>' | |
| source_filename = "<stdin>" | |
| target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" | |
| target triple = "x86_64-unknown-linux-gnu" | |
| @b = common local_unnamed_addr global i8* null, align 8 | |
| @a = common local_unnamed_addr global i32 0, align 4 | |
| define i32 @foo() local_unnamed_addr { | |
| entry: | |
| %t0 = load i8*, i8** @b, align 8 | |
| %t1 = load i8, i8* %t0, align 1 | |
| %cmp4 = icmp eq i8 %t1, 0 | |
| %t2 = load i32, i32* @a, align 4 | |
| br i1 %cmp4, label %while.end, label %while.body.preheader | |
| while.body.preheader: ; preds = %entry | |
| br label %while.body | |
| while.body: ; preds = %while.body, %while.body.preheader | |
| %t3 = phi i32 [ %add3, %while.body ], [ %t2, %while.body.preheader ] | |
| %t4 = phi i8 [ %t5, %while.body ], [ %t1, %while.body.preheader ] | |
| %conv = sext i8 %t4 to i32 | |
| %add = mul i32 %t3, 33 | |
| %add3 = add nsw i32 %add, %conv | |
| store i32 %add3, i32* @a, align 4 | |
| %t5 = load i8, i8* %t0, align 1 | |
| %cmp = icmp eq i8 %t5, 0 | |
| br i1 %cmp, label %while.end, label %while.body | |
| while.end: ; preds = %while.body, %entry | |
| %.lcssa = phi i32 [ %t2, %entry ], [ %add3, %while.body ] | |
| ret i32 %.lcssa | |
| } | |
| ... | |
| --- | |
| # Check A = B and B = A copies will not exist in the loop at the same time. | |
| # CHECK: name: foo | |
| # CHECK: [[L1:bb.3]].{{[a-zA-Z0-9.]+}}: | |
| # CHECK: %[[REGA:.*]] = COPY %[[REGB:.*]] | |
| # CHECK-NOT: %[[REGB]] = COPY %[[REGA]] | |
| # CHECK: JNE_1 %[[L1]] | |
| name: foo | |
| alignment: 4 | |
| exposesReturnsTwice: false | |
| legalized: false | |
| regBankSelected: false | |
| selected: false | |
| tracksRegLiveness: true | |
| registers: | |
| - { id: 0, class: gr64 } | |
| - { id: 1, class: gr8 } | |
| - { id: 2, class: gr32 } | |
| - { id: 3, class: gr32 } | |
| - { id: 4, class: gr8 } | |
| - { id: 5, class: gr32 } | |
| - { id: 6, class: gr8 } | |
| - { id: 7, class: gr32 } | |
| - { id: 8, class: gr32 } | |
| - { id: 9, class: gr32 } | |
| - { id: 10, class: gr32 } | |
| - { id: 11, class: gr32 } | |
| - { id: 12, class: gr8 } | |
| - { id: 13, class: gr32 } | |
| frameInfo: | |
| isFrameAddressTaken: false | |
| isReturnAddressTaken: false | |
| hasStackMap: false | |
| hasPatchPoint: false | |
| stackSize: 0 | |
| offsetAdjustment: 0 | |
| maxAlignment: 0 | |
| adjustsStack: false | |
| hasCalls: false | |
| maxCallFrameSize: 0 | |
| hasOpaqueSPAdjustment: false | |
| hasVAStart: false | |
| hasMustTailInVarArgFunc: false | |
| body: | | |
| bb.0.entry: | |
| %0 = MOV64rm $rip, 1, $noreg, @b, $noreg :: (dereferenceable load 8 from @b) | |
| %12 = MOV8rm %0, 1, $noreg, 0, $noreg :: (load 1 from %ir.t0) | |
| TEST8rr %12, %12, implicit-def $eflags | |
| %11 = MOV32rm $rip, 1, $noreg, @a, $noreg :: (dereferenceable load 4 from @a) | |
| JNE_1 %bb.1, implicit killed $eflags | |
| bb.4: | |
| %10 = COPY %11 | |
| JMP_1 %bb.3 | |
| bb.1.while.body.preheader: | |
| bb.2.while.body: | |
| %8 = MOVSX32rr8 %12 | |
| %10 = COPY %11 | |
| %10 = SHL32ri %10, 5, implicit-def dead $eflags | |
| %10 = ADD32rr %10, %11, implicit-def dead $eflags | |
| %10 = ADD32rr %10, %8, implicit-def dead $eflags | |
| MOV32mr $rip, 1, $noreg, @a, $noreg, %10 :: (store 4 into @a) | |
| %12 = MOV8rm %0, 1, $noreg, 0, $noreg :: (load 1 from %ir.t0) | |
| TEST8rr %12, %12, implicit-def $eflags | |
| %11 = COPY %10 | |
| JNE_1 %bb.2, implicit killed $eflags | |
| JMP_1 %bb.3 | |
| bb.3.while.end: | |
| $eax = COPY %10 | |
| RET 0, killed $eax | |
| ... |