[llvm] 92068d6 - [SimplifyCFG] add tests for branch cond merging with prof metadata; NFC

Sanjay Patel via llvm-commits llvm-commits at lists.llvm.org
Thu Mar 18 12:39:57 PDT 2021


Author: Sanjay Patel
Date: 2021-03-18T15:39:50-04:00
New Revision: 92068d6c31a45315402e4cefd3ec1c340090b41d

URL: https://github.com/llvm/llvm-project/commit/92068d6c31a45315402e4cefd3ec1c340090b41d
DIFF: https://github.com/llvm/llvm-project/commit/92068d6c31a45315402e4cefd3ec1c340090b41d.diff

LOG: [SimplifyCFG] add tests for branch cond merging with prof metadata; NFC

See PR49336.

Added: 
    

Modified: 
    llvm/test/Transforms/SimplifyCFG/preserve-branchweights.ll

Removed: 
    


################################################################################
diff  --git a/llvm/test/Transforms/SimplifyCFG/preserve-branchweights.ll b/llvm/test/Transforms/SimplifyCFG/preserve-branchweights.ll
index 25106d435cc7..657accc9b6c2 100644
--- a/llvm/test/Transforms/SimplifyCFG/preserve-branchweights.ll
+++ b/llvm/test/Transforms/SimplifyCFG/preserve-branchweights.ll
@@ -318,10 +318,10 @@ define void @test8(i64 %x, i64 %y) nounwind {
 ; CHECK-NEXT:    [[LT:%.*]] = icmp slt i64 [[X:%.*]], [[Y:%.*]]
 ; CHECK-NEXT:    br i1 [[LT]], label [[A:%.*]], label [[B:%.*]], !prof !7
 ; CHECK:       a:
-; CHECK-NEXT:    call void @helper(i32 0) [[ATTR1:#.*]]
+; CHECK-NEXT:    call void @helper(i32 0) #[[ATTR1:[0-9]+]]
 ; CHECK-NEXT:    ret void
 ; CHECK:       b:
-; CHECK-NEXT:    call void @helper(i32 1) [[ATTR1]]
+; CHECK-NEXT:    call void @helper(i32 1) #[[ATTR1]]
 ; CHECK-NEXT:    ret void
 ;
 entry:
@@ -355,14 +355,14 @@ define i1 @test9(i32 %x, i32 %y) nounwind {
 ; CHECK-NEXT:    i32 92, label [[END]]
 ; CHECK-NEXT:    ], !prof !8
 ; CHECK:       a:
-; CHECK-NEXT:    call void @helper(i32 0) [[ATTR1]]
+; CHECK-NEXT:    call void @helper(i32 0) #[[ATTR1]]
 ; CHECK-NEXT:    [[RETA:%.*]] = icmp slt i32 [[X]], [[Y:%.*]]
 ; CHECK-NEXT:    ret i1 [[RETA]]
 ; CHECK:       bees:
 ; CHECK-NEXT:    br label [[END]]
 ; CHECK:       end:
 ; CHECK-NEXT:    [[RET:%.*]] = phi i1 [ true, [[ENTRY:%.*]] ], [ false, [[BEES]] ], [ true, [[ENTRY]] ], [ true, [[ENTRY]] ]
-; CHECK-NEXT:    call void @helper(i32 2) [[ATTR1]]
+; CHECK-NEXT:    call void @helper(i32 2) #[[ATTR1]]
 ; CHECK-NEXT:    ret i1 [[RET]]
 ;
 entry:
@@ -394,10 +394,10 @@ define void @test10(i32 %x) nounwind readnone ssp noredzone {
 ; CHECK-NEXT:    [[SWITCH:%.*]] = icmp ult i32 [[X_OFF]], 3
 ; CHECK-NEXT:    br i1 [[SWITCH]], label [[LOR_END:%.*]], label [[LOR_RHS:%.*]], !prof !9
 ; CHECK:       lor.rhs:
-; CHECK-NEXT:    call void @helper(i32 1) [[ATTR1]]
+; CHECK-NEXT:    call void @helper(i32 1) #[[ATTR1]]
 ; CHECK-NEXT:    ret void
 ; CHECK:       lor.end:
-; CHECK-NEXT:    call void @helper(i32 0) [[ATTR1]]
+; CHECK-NEXT:    call void @helper(i32 0) #[[ATTR1]]
 ; CHECK-NEXT:    ret void
 ;
 entry:
@@ -424,10 +424,10 @@ define void @test11(i32 %x) nounwind {
 ; CHECK-NEXT:    [[COND:%.*]] = icmp eq i32 [[I]], 24
 ; CHECK-NEXT:    br i1 [[COND]], label [[C:%.*]], label [[A:%.*]], !prof !10
 ; CHECK:       a:
-; CHECK-NEXT:    call void @helper(i32 0) [[ATTR1]]
+; CHECK-NEXT:    call void @helper(i32 0) #[[ATTR1]]
 ; CHECK-NEXT:    ret void
 ; CHECK:       c:
-; CHECK-NEXT:    call void @helper(i32 2) [[ATTR1]]
+; CHECK-NEXT:    call void @helper(i32 2) #[[ATTR1]]
 ; CHECK-NEXT:    ret void
 ;
   %i = shl i32 %x, 1
@@ -472,7 +472,7 @@ sw.epilog:
 define void @test13(i32 %x) nounwind {
 ; CHECK-LABEL: @test13(
 ; CHECK-NEXT:  entry:
-; CHECK-NEXT:    call void @helper(i32 0) [[ATTR1]]
+; CHECK-NEXT:    call void @helper(i32 0) #[[ATTR1]]
 ; CHECK-NEXT:    ret void
 ;
 entry:
@@ -636,6 +636,400 @@ exit:
   ret i32 %outval
 }
 
+; FIXME: Merging the icmps with logic-op defeats the purpose of the metadata.
+; We can't tell which condition is expensive if they are combined.
+
+define void @or_icmps_harmful(i32 %x, i32 %y, i8* %p) {
+; CHECK-LABEL: @or_icmps_harmful(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[EXPECTED_TRUE:%.*]] = icmp sgt i32 [[X:%.*]], -1
+; CHECK-NEXT:    [[EXPENSIVE:%.*]] = icmp eq i32 [[Y:%.*]], 0
+; CHECK-NEXT:    [[OR_COND:%.*]] = or i1 [[EXPECTED_TRUE]], [[EXPENSIVE]]
+; CHECK-NEXT:    br i1 [[OR_COND]], label [[EXIT:%.*]], label [[FALSE:%.*]], !prof !19
+; CHECK:       false:
+; CHECK-NEXT:    store i8 42, i8* [[P:%.*]], align 1
+; CHECK-NEXT:    br label [[EXIT]]
+; CHECK:       exit:
+; CHECK-NEXT:    ret void
+;
+entry:
+  %expected_true = icmp sgt i32 %x, -1
+  br i1 %expected_true, label %exit, label %rare, !prof !15
+
+rare:
+  %expensive = icmp eq i32 %y, 0
+  br i1 %expensive, label %exit, label %false
+
+false:
+  store i8 42, i8* %p, align 1
+  br label %exit
+
+exit:
+  ret void
+}
+
+; FIXME: Merging the icmps with logic-op defeats the purpose of the metadata.
+; We can't tell which condition is expensive if they are combined.
+
+define void @or_icmps_harmful_inverted(i32 %x, i32 %y, i8* %p) {
+; CHECK-LABEL: @or_icmps_harmful_inverted(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[EXPECTED_FALSE:%.*]] = icmp sle i32 [[X:%.*]], -1
+; CHECK-NEXT:    [[EXPENSIVE:%.*]] = icmp eq i32 [[Y:%.*]], 0
+; CHECK-NEXT:    [[OR_COND:%.*]] = or i1 [[EXPECTED_FALSE]], [[EXPENSIVE]]
+; CHECK-NEXT:    br i1 [[OR_COND]], label [[EXIT:%.*]], label [[FALSE:%.*]], !prof !19
+; CHECK:       false:
+; CHECK-NEXT:    store i8 42, i8* [[P:%.*]], align 1
+; CHECK-NEXT:    br label [[EXIT]]
+; CHECK:       exit:
+; CHECK-NEXT:    ret void
+;
+entry:
+  %expected_false = icmp sgt i32 %x, -1
+  br i1 %expected_false, label %rare, label %exit, !prof !16
+
+rare:
+  %expensive = icmp eq i32 %y, 0
+  br i1 %expensive, label %exit, label %false
+
+false:
+  store i8 42, i8* %p, align 1
+  br label %exit
+
+exit:
+  ret void
+}
+
+; The probability threshold is set by a builtin_expect setting.
+
+define void @or_icmps_not_that_harmful(i32 %x, i32 %y, i8* %p) {
+; CHECK-LABEL: @or_icmps_not_that_harmful(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[EXPECTED_TRUE:%.*]] = icmp sgt i32 [[X:%.*]], -1
+; CHECK-NEXT:    [[EXPENSIVE:%.*]] = icmp eq i32 [[Y:%.*]], 0
+; CHECK-NEXT:    [[OR_COND:%.*]] = or i1 [[EXPECTED_TRUE]], [[EXPENSIVE]]
+; CHECK-NEXT:    br i1 [[OR_COND]], label [[EXIT:%.*]], label [[FALSE:%.*]], !prof !20
+; CHECK:       false:
+; CHECK-NEXT:    store i8 42, i8* [[P:%.*]], align 1
+; CHECK-NEXT:    br label [[EXIT]]
+; CHECK:       exit:
+; CHECK-NEXT:    ret void
+;
+entry:
+  %expected_true = icmp sgt i32 %x, -1
+  br i1 %expected_true, label %exit, label %rare, !prof !17
+
+rare:
+  %expensive = icmp eq i32 %y, 0
+  br i1 %expensive, label %exit, label %false
+
+false:
+  store i8 42, i8* %p, align 1
+  br label %exit
+
+exit:
+  ret void
+}
+
+define void @or_icmps_not_that_harmful_inverted(i32 %x, i32 %y, i8* %p) {
+; CHECK-LABEL: @or_icmps_not_that_harmful_inverted(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[EXPECTED_TRUE:%.*]] = icmp sgt i32 [[X:%.*]], -1
+; CHECK-NEXT:    [[EXPENSIVE:%.*]] = icmp eq i32 [[Y:%.*]], 0
+; CHECK-NEXT:    [[OR_COND:%.*]] = or i1 [[EXPECTED_TRUE]], [[EXPENSIVE]]
+; CHECK-NEXT:    br i1 [[OR_COND]], label [[EXIT:%.*]], label [[FALSE:%.*]], !prof !21
+; CHECK:       false:
+; CHECK-NEXT:    store i8 42, i8* [[P:%.*]], align 1
+; CHECK-NEXT:    br label [[EXIT]]
+; CHECK:       exit:
+; CHECK-NEXT:    ret void
+;
+entry:
+  %expected_true = icmp sgt i32 %x, -1
+  br i1 %expected_true, label %exit, label %rare, !prof !18
+
+rare:
+  %expensive = icmp eq i32 %y, 0
+  br i1 %expensive, label %exit, label %false
+
+false:
+  store i8 42, i8* %p, align 1
+  br label %exit
+
+exit:
+  ret void
+}
+
+define void @or_icmps_useful(i32 %x, i32 %y, i8* %p) {
+; CHECK-LABEL: @or_icmps_useful(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[EXPECTED_TRUE:%.*]] = icmp sle i32 [[X:%.*]], -1
+; CHECK-NEXT:    [[EXPENSIVE:%.*]] = icmp eq i32 [[Y:%.*]], 0
+; CHECK-NEXT:    [[OR_COND:%.*]] = or i1 [[EXPECTED_TRUE]], [[EXPENSIVE]]
+; CHECK-NEXT:    br i1 [[OR_COND]], label [[EXIT:%.*]], label [[FALSE:%.*]], !prof !22
+; CHECK:       false:
+; CHECK-NEXT:    store i8 42, i8* [[P:%.*]], align 1
+; CHECK-NEXT:    br label [[EXIT]]
+; CHECK:       exit:
+; CHECK-NEXT:    ret void
+;
+entry:
+  %expected_true = icmp sgt i32 %x, -1
+  br i1 %expected_true, label %likely, label %exit, !prof !15
+
+likely:
+  %expensive = icmp eq i32 %y, 0
+  br i1 %expensive, label %exit, label %false
+
+false:
+  store i8 42, i8* %p, align 1
+  br label %exit
+
+exit:
+  ret void
+}
+
+define void @or_icmps_useful_inverted(i32 %x, i32 %y, i8* %p) {
+; CHECK-LABEL: @or_icmps_useful_inverted(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[EXPECTED_FALSE:%.*]] = icmp sgt i32 [[X:%.*]], -1
+; CHECK-NEXT:    [[EXPENSIVE:%.*]] = icmp eq i32 [[Y:%.*]], 0
+; CHECK-NEXT:    [[OR_COND:%.*]] = or i1 [[EXPECTED_FALSE]], [[EXPENSIVE]]
+; CHECK-NEXT:    br i1 [[OR_COND]], label [[EXIT:%.*]], label [[FALSE:%.*]], !prof !22
+; CHECK:       false:
+; CHECK-NEXT:    store i8 42, i8* [[P:%.*]], align 1
+; CHECK-NEXT:    br label [[EXIT]]
+; CHECK:       exit:
+; CHECK-NEXT:    ret void
+;
+entry:
+  %expected_false = icmp sgt i32 %x, -1
+  br i1 %expected_false, label %exit, label %likely, !prof !16
+
+likely:
+  %expensive = icmp eq i32 %y, 0
+  br i1 %expensive, label %exit, label %false
+
+false:
+  store i8 42, i8* %p, align 1
+  br label %exit
+
+exit:
+  ret void
+}
+
+; Don't crash processing degenerate metadata.
+
+define void @or_icmps_empty_metadata(i32 %x, i32 %y, i8* %p) {
+; CHECK-LABEL: @or_icmps_empty_metadata(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[EXPECTED_TRUE:%.*]] = icmp sgt i32 [[X:%.*]], -1
+; CHECK-NEXT:    [[EXPENSIVE:%.*]] = icmp eq i32 [[Y:%.*]], 0
+; CHECK-NEXT:    [[OR_COND:%.*]] = or i1 [[EXPECTED_TRUE]], [[EXPENSIVE]]
+; CHECK-NEXT:    br i1 [[OR_COND]], label [[EXIT:%.*]], label [[MORE_RARE:%.*]]
+; CHECK:       more_rare:
+; CHECK-NEXT:    store i8 42, i8* [[P:%.*]], align 1
+; CHECK-NEXT:    br label [[EXIT]]
+; CHECK:       exit:
+; CHECK-NEXT:    ret void
+;
+entry:
+  %expected_true = icmp sgt i32 %x, -1
+  br i1 %expected_true, label %exit, label %rare, !prof !19
+
+rare:
+  %expensive = icmp eq i32 %y, 0
+  br i1 %expensive, label %exit, label %more_rare
+
+more_rare:
+  store i8 42, i8* %p, align 1
+  br label %exit
+
+exit:
+  ret void
+}
+
+; FIXME: Merging the icmps with logic-op defeats the purpose of the metadata.
+; We can't tell which condition is expensive if they are combined.
+
+define void @and_icmps_harmful(i32 %x, i32 %y, i8* %p) {
+; CHECK-LABEL: @and_icmps_harmful(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[EXPECTED_FALSE:%.*]] = icmp sgt i32 [[X:%.*]], -1
+; CHECK-NEXT:    [[EXPENSIVE:%.*]] = icmp eq i32 [[Y:%.*]], 0
+; CHECK-NEXT:    [[OR_COND:%.*]] = and i1 [[EXPECTED_FALSE]], [[EXPENSIVE]]
+; CHECK-NEXT:    br i1 [[OR_COND]], label [[FALSE:%.*]], label [[EXIT:%.*]], !prof !23
+; CHECK:       false:
+; CHECK-NEXT:    store i8 42, i8* [[P:%.*]], align 1
+; CHECK-NEXT:    br label [[EXIT]]
+; CHECK:       exit:
+; CHECK-NEXT:    ret void
+;
+entry:
+  %expected_false = icmp sgt i32 %x, -1
+  br i1 %expected_false, label %rare, label %exit, !prof !16
+
+rare:
+  %expensive = icmp eq i32 %y, 0
+  br i1 %expensive, label %false, label %exit
+
+false:
+  store i8 42, i8* %p, align 1
+  br label %exit
+
+exit:
+  ret void
+}
+
+; FIXME: Merging the icmps with logic-op defeats the purpose of the metadata.
+; We can't tell which condition is expensive if they are combined.
+
+define void @and_icmps_harmful_inverted(i32 %x, i32 %y, i8* %p) {
+; CHECK-LABEL: @and_icmps_harmful_inverted(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[EXPECTED_TRUE:%.*]] = icmp sle i32 [[X:%.*]], -1
+; CHECK-NEXT:    [[EXPENSIVE:%.*]] = icmp eq i32 [[Y:%.*]], 0
+; CHECK-NEXT:    [[OR_COND:%.*]] = and i1 [[EXPECTED_TRUE]], [[EXPENSIVE]]
+; CHECK-NEXT:    br i1 [[OR_COND]], label [[FALSE:%.*]], label [[EXIT:%.*]], !prof !23
+; CHECK:       false:
+; CHECK-NEXT:    store i8 42, i8* [[P:%.*]], align 1
+; CHECK-NEXT:    br label [[EXIT]]
+; CHECK:       exit:
+; CHECK-NEXT:    ret void
+;
+entry:
+  %expected_true = icmp sgt i32 %x, -1
+  br i1 %expected_true, label %exit, label %rare, !prof !15
+
+rare:
+  %expensive = icmp eq i32 %y, 0
+  br i1 %expensive, label %false, label %exit
+
+false:
+  store i8 42, i8* %p, align 1
+  br label %exit
+
+exit:
+  ret void
+}
+
+define void @and_icmps_not_that_harmful(i32 %x, i32 %y, i8* %p) {
+; CHECK-LABEL: @and_icmps_not_that_harmful(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[EXPECTED_FALSE:%.*]] = icmp sgt i32 [[X:%.*]], -1
+; CHECK-NEXT:    [[EXPENSIVE:%.*]] = icmp eq i32 [[Y:%.*]], 0
+; CHECK-NEXT:    [[OR_COND:%.*]] = and i1 [[EXPECTED_FALSE]], [[EXPENSIVE]]
+; CHECK-NEXT:    br i1 [[OR_COND]], label [[FALSE:%.*]], label [[EXIT:%.*]], !prof !24
+; CHECK:       false:
+; CHECK-NEXT:    store i8 42, i8* [[P:%.*]], align 1
+; CHECK-NEXT:    br label [[EXIT]]
+; CHECK:       exit:
+; CHECK-NEXT:    ret void
+;
+entry:
+  %expected_false = icmp sgt i32 %x, -1
+  br i1 %expected_false, label %rare, label %exit, !prof !18
+
+rare:
+  %expensive = icmp eq i32 %y, 0
+  br i1 %expensive, label %false, label %exit
+
+false:
+  store i8 42, i8* %p, align 1
+  br label %exit
+
+exit:
+  ret void
+}
+
+define void @and_icmps_not_that_harmful_inverted(i32 %x, i32 %y, i8* %p) {
+; CHECK-LABEL: @and_icmps_not_that_harmful_inverted(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[EXPECTED_TRUE:%.*]] = icmp sle i32 [[X:%.*]], -1
+; CHECK-NEXT:    [[EXPENSIVE:%.*]] = icmp eq i32 [[Y:%.*]], 0
+; CHECK-NEXT:    [[OR_COND:%.*]] = and i1 [[EXPECTED_TRUE]], [[EXPENSIVE]]
+; CHECK-NEXT:    br i1 [[OR_COND]], label [[FALSE:%.*]], label [[EXIT:%.*]], !prof !24
+; CHECK:       false:
+; CHECK-NEXT:    store i8 42, i8* [[P:%.*]], align 1
+; CHECK-NEXT:    br label [[EXIT]]
+; CHECK:       exit:
+; CHECK-NEXT:    ret void
+;
+entry:
+  %expected_true = icmp sgt i32 %x, -1
+  br i1 %expected_true, label %exit, label %rare, !prof !17
+
+rare:
+  %expensive = icmp eq i32 %y, 0
+  br i1 %expensive, label %false, label %exit
+
+false:
+  store i8 42, i8* %p, align 1
+  br label %exit
+
+exit:
+  ret void
+}
+
+define void @and_icmps_useful(i32 %x, i32 %y, i8* %p) {
+; CHECK-LABEL: @and_icmps_useful(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[EXPECTED_TRUE:%.*]] = icmp sgt i32 [[X:%.*]], -1
+; CHECK-NEXT:    [[EXPENSIVE:%.*]] = icmp eq i32 [[Y:%.*]], 0
+; CHECK-NEXT:    [[OR_COND:%.*]] = and i1 [[EXPECTED_TRUE]], [[EXPENSIVE]]
+; CHECK-NEXT:    br i1 [[OR_COND]], label [[FALSE:%.*]], label [[EXIT:%.*]], !prof !25
+; CHECK:       false:
+; CHECK-NEXT:    store i8 42, i8* [[P:%.*]], align 1
+; CHECK-NEXT:    br label [[EXIT]]
+; CHECK:       exit:
+; CHECK-NEXT:    ret void
+;
+entry:
+  %expected_true = icmp sgt i32 %x, -1
+  br i1 %expected_true, label %likely, label %exit, !prof !15
+
+likely:
+  %expensive = icmp eq i32 %y, 0
+  br i1 %expensive, label %false, label %exit
+
+false:
+  store i8 42, i8* %p, align 1
+  br label %exit
+
+exit:
+  ret void
+}
+
+define void @and_icmps_useful_inverted(i32 %x, i32 %y, i8* %p) {
+; CHECK-LABEL: @and_icmps_useful_inverted(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[EXPECTED_FALSE:%.*]] = icmp sle i32 [[X:%.*]], -1
+; CHECK-NEXT:    [[EXPENSIVE:%.*]] = icmp eq i32 [[Y:%.*]], 0
+; CHECK-NEXT:    [[OR_COND:%.*]] = and i1 [[EXPECTED_FALSE]], [[EXPENSIVE]]
+; CHECK-NEXT:    br i1 [[OR_COND]], label [[FALSE:%.*]], label [[EXIT:%.*]], !prof !25
+; CHECK:       false:
+; CHECK-NEXT:    store i8 42, i8* [[P:%.*]], align 1
+; CHECK-NEXT:    br label [[EXIT]]
+; CHECK:       exit:
+; CHECK-NEXT:    ret void
+;
+entry:
+  %expected_false = icmp sgt i32 %x, -1
+  br i1 %expected_false, label %exit, label %likely, !prof !16
+
+likely:
+  %expensive = icmp eq i32 %y, 0
+  br i1 %expensive, label %false, label %exit
+
+false:
+  store i8 42, i8* %p, align 1
+  br label %exit
+
+exit:
+  ret void
+}
+
+
 !0 = !{!"branch_weights", i32 3, i32 5}
 !1 = !{!"branch_weights", i32 1, i32 1}
 !2 = !{!"branch_weights", i32 1, i32 2}
@@ -651,6 +1045,11 @@ exit:
 !12 = !{!"these_are_not_the_branch_weights_you_are_looking_for", i32 3, i32 5}
 !13 = !{!"branch_weights", i32 2, i32 3}
 !14 = !{!"branch_weights", i32 4, i32 7}
+!15 = !{!"branch_weights", i32 2000, i32 1}
+!16 = !{!"branch_weights", i32 1, i32 2000}
+!17 = !{!"branch_weights", i32 1999, i32 1}
+!18 = !{!"branch_weights", i32 1, i32 1999}
+!19 = !{!"branch_weights", i32 0, i32 0}
 
 ; CHECK: !0 = !{!"branch_weights", i32 5, i32 11}
 ; CHECK: !1 = !{!"branch_weights", i32 1, i32 3}


        


More information about the llvm-commits mailing list