; LLVM IR from nonstriater/Learn-Algorithms :: 9 Algorithms Job Interview/codes/1 string/revert_by_word.ll (reverse)

; Unoptimized IR (clang -disable-llvm-passes):
target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128"
target triple = "x86_64-unknown-linux-gnu"

; Function Attrs: nounwind uwtable
define dso_local void @_reverse(ptr noundef %0, ptr noundef %1) #0 {
  %3 = alloca ptr, align 8
  %4 = alloca ptr, align 8
  %5 = alloca i8, align 1
  store ptr %0, ptr %3, align 8, !tbaa !5
  store ptr %1, ptr %4, align 8, !tbaa !5
  %6 = load ptr, ptr %3, align 8, !tbaa !5
  %7 = icmp eq ptr %6, null
  br i1 %7, label %11, label %8

8:                                                ; preds = %2
  %9 = load ptr, ptr %4, align 8, !tbaa !5
  %10 = icmp eq ptr %9, null
  br i1 %10, label %11, label %12

11:                                               ; preds = %8, %2
  br label %29

12:                                               ; preds = %8
  br label %13

13:                                               ; preds = %17, %12
  %14 = load ptr, ptr %3, align 8, !tbaa !5
  %15 = load ptr, ptr %4, align 8, !tbaa !5
  %16 = icmp ult ptr %14, %15
  br i1 %16, label %17, label %29

17:                                               ; preds = %13
  call void @llvm.lifetime.start.p0(i64 1, ptr %5) #2
  %18 = load ptr, ptr %3, align 8, !tbaa !5
  %19 = load i8, ptr %18, align 1, !tbaa !9
  store i8 %19, ptr %5, align 1, !tbaa !9
  %20 = load ptr, ptr %4, align 8, !tbaa !5
  %21 = load i8, ptr %20, align 1, !tbaa !9
  %22 = load ptr, ptr %3, align 8, !tbaa !5
  store i8 %21, ptr %22, align 1, !tbaa !9
  %23 = load i8, ptr %5, align 1, !tbaa !9
  %24 = load ptr, ptr %4, align 8, !tbaa !5
  store i8 %23, ptr %24, align 1, !tbaa !9
  %25 = load ptr, ptr %3, align 8, !tbaa !5
  %26 = getelementptr inbounds i8, ptr %25, i32 1
  store ptr %26, ptr %3, align 8, !tbaa !5
  %27 = load ptr, ptr %4, align 8, !tbaa !5
  %28 = getelementptr inbounds i8, ptr %27, i32 -1
  store ptr %28, ptr %4, align 8, !tbaa !5
  call void @llvm.lifetime.end.p0(i64 1, ptr %5) #2
  br label %13, !llvm.loop !10

29:                                               ; preds = %13, %11
  ret void
}

; Function Attrs: nocallback nofree nosync nounwind willreturn memory(argmem: readwrite)
declare void @llvm.lifetime.start.p0(i64 immarg, ptr nocapture) #1

; Function Attrs: nocallback nofree nosync nounwind willreturn memory(argmem: readwrite)
declare void @llvm.lifetime.end.p0(i64 immarg, ptr nocapture) #1

attributes #0 = { nounwind uwtable "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cmov,+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" }
attributes #1 = { nocallback nofree nosync nounwind willreturn memory(argmem: readwrite) }
attributes #2 = { nounwind }

!llvm.module.flags = !{!0, !1, !2, !3}
!llvm.ident = !{!4}

!0 = !{i32 1, !"wchar_size", i32 4}
!1 = !{i32 8, !"PIC Level", i32 2}
!2 = !{i32 7, !"PIE Level", i32 2}
!3 = !{i32 7, !"uwtable", i32 2}
!4 = !{!"clang version 19.1.0 (git@github.com:llvm/llvm-project.git a4bf6cd7cfb1a1421ba92bca9d017b49936c55e4)"}
!5 = !{!6, !6, i64 0}
!6 = !{!"any pointer", !7, i64 0}
!7 = !{!"omnipotent char", !8, i64 0}
!8 = !{!"Simple C/C++ TBAA"}
!9 = !{!7, !7, i64 0}
!10 = distinct !{!10, !11}
!11 = !{!"llvm.loop.mustprogress"}


; Optimized IR (opt -passes='default<O3>'):
target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128"
target triple = "x86_64-unknown-linux-gnu"

; Function Attrs: nofree norecurse nosync nounwind memory(readwrite, inaccessiblemem: none) uwtable
define dso_local void @_reverse(ptr noundef %0, ptr noundef %1) local_unnamed_addr #0 {
  %3 = ptrtoint ptr %0 to i64
  %4 = ptrtoint ptr %1 to i64
  %5 = icmp ne ptr %0, null
  %6 = icmp ult ptr %0, %1
  %or.cond16 = and i1 %5, %6
  br i1 %or.cond16, label %iter.check, label %.loopexit

iter.check:                                       ; preds = %2
  %7 = ptrtoint ptr %1 to i64
  %8 = ptrtoint ptr %0 to i64
  %9 = add i64 %7, -1
  %10 = add i64 %8, 1
  %umax21 = tail call i64 @llvm.umax.i64(i64 %9, i64 %10)
  %11 = xor i64 %8, -1
  %12 = add i64 %umax21, %11
  %13 = icmp ne i64 %12, 0
  %umin22 = zext i1 %13 to i64
  %14 = sub i64 %12, %umin22
  %15 = lshr i64 %14, 1
  %16 = add nuw i64 %15, %umin22
  %17 = add i64 %16, 1
  %min.iters.check = icmp ult i64 %17, 4
  br i1 %min.iters.check, label %.lr.ph.preheader, label %vector.memcheck

vector.memcheck:                                  ; preds = %iter.check
  %18 = add i64 %4, -1
  %19 = add i64 %3, 1
  %umax = tail call i64 @llvm.umax.i64(i64 %18, i64 %19)
  %20 = xor i64 %3, -1
  %21 = add i64 %umax, %20
  %22 = icmp ne i64 %21, 0
  %umin = zext i1 %22 to i64
  %23 = sub i64 %21, %umin
  %24 = lshr i64 %23, 1
  %25 = add nuw i64 %24, %umin
  %26 = getelementptr i8, ptr %0, i64 %25
  %scevgep = getelementptr i8, ptr %26, i64 1
  %27 = sub i64 0, %25
  %scevgep19 = getelementptr i8, ptr %1, i64 %27
  %scevgep20 = getelementptr i8, ptr %1, i64 1
  %bound0 = icmp ugt ptr %scevgep20, %0
  %bound1 = icmp ult ptr %scevgep19, %scevgep
  %found.conflict = and i1 %bound0, %bound1
  br i1 %found.conflict, label %.lr.ph.preheader, label %vector.main.loop.iter.check

vector.main.loop.iter.check:                      ; preds = %vector.memcheck
  %min.iters.check23 = icmp ult i64 %17, 16
  br i1 %min.iters.check23, label %vec.epilog.ph, label %vector.ph

vector.ph:                                        ; preds = %vector.main.loop.iter.check
  %n.vec = and i64 %17, -16
  %invariant.gep = getelementptr i8, ptr %1, i64 -15
  br label %vector.body

vector.body:                                      ; preds = %vector.body, %vector.ph
  %index = phi i64 [ 0, %vector.ph ], [ %index.next, %vector.body ]
  %next.gep = getelementptr i8, ptr %0, i64 %index
  %offset.idx = sub i64 0, %index
  %wide.load = load <16 x i8>, ptr %next.gep, align 1, !tbaa !5, !alias.scope !8, !noalias !11
  %gep = getelementptr i8, ptr %invariant.gep, i64 %offset.idx
  %wide.load25 = load <16 x i8>, ptr %gep, align 1, !tbaa !5, !alias.scope !11
  %reverse = shufflevector <16 x i8> %wide.load25, <16 x i8> poison, <16 x i32> <i32 15, i32 14, i32 13, i32 12, i32 11, i32 10, i32 9, i32 8, i32 7, i32 6, i32 5, i32 4, i32 3, i32 2, i32 1, i32 0>
  store <16 x i8> %reverse, ptr %next.gep, align 1, !tbaa !5, !alias.scope !8, !noalias !11
  %reverse26 = shufflevector <16 x i8> %wide.load, <16 x i8> poison, <16 x i32> <i32 15, i32 14, i32 13, i32 12, i32 11, i32 10, i32 9, i32 8, i32 7, i32 6, i32 5, i32 4, i32 3, i32 2, i32 1, i32 0>
  store <16 x i8> %reverse26, ptr %gep, align 1, !tbaa !5, !alias.scope !11
  %index.next = add nuw i64 %index, 16
  %28 = icmp eq i64 %index.next, %n.vec
  br i1 %28, label %middle.block, label %vector.body, !llvm.loop !13

middle.block:                                     ; preds = %vector.body
  %cmp.n = icmp eq i64 %17, %n.vec
  br i1 %cmp.n, label %.loopexit, label %vec.epilog.iter.check

vec.epilog.iter.check:                            ; preds = %middle.block
  %29 = sub i64 0, %n.vec
  %ind.end31 = getelementptr i8, ptr %1, i64 %29
  %ind.end29 = getelementptr i8, ptr %0, i64 %n.vec
  %n.vec.remaining = and i64 %17, 12
  %min.epilog.iters.check = icmp eq i64 %n.vec.remaining, 0
  br i1 %min.epilog.iters.check, label %.lr.ph.preheader, label %vec.epilog.ph

vec.epilog.ph:                                    ; preds = %vector.main.loop.iter.check, %vec.epilog.iter.check
  %vec.epilog.resume.val = phi i64 [ %n.vec, %vec.epilog.iter.check ], [ 0, %vector.main.loop.iter.check ]
  %n.vec28 = and i64 %17, -4
  %ind.end = getelementptr i8, ptr %0, i64 %n.vec28
  %30 = sub i64 0, %n.vec28
  %ind.end30 = getelementptr i8, ptr %1, i64 %30
  %invariant.gep43 = getelementptr i8, ptr %1, i64 -3
  br label %vec.epilog.vector.body

vec.epilog.vector.body:                           ; preds = %vec.epilog.vector.body, %vec.epilog.ph
  %index33 = phi i64 [ %vec.epilog.resume.val, %vec.epilog.ph ], [ %index.next41, %vec.epilog.vector.body ]
  %next.gep34 = getelementptr i8, ptr %0, i64 %index33
  %offset.idx35 = sub i64 0, %index33
  %wide.load37 = load <4 x i8>, ptr %next.gep34, align 1, !tbaa !5, !alias.scope !17, !noalias !20
  %gep44 = getelementptr i8, ptr %invariant.gep43, i64 %offset.idx35
  %wide.load38 = load <4 x i8>, ptr %gep44, align 1, !tbaa !5, !alias.scope !20
  %reverse39 = shufflevector <4 x i8> %wide.load38, <4 x i8> poison, <4 x i32> <i32 3, i32 2, i32 1, i32 0>
  store <4 x i8> %reverse39, ptr %next.gep34, align 1, !tbaa !5, !alias.scope !17, !noalias !20
  %reverse40 = shufflevector <4 x i8> %wide.load37, <4 x i8> poison, <4 x i32> <i32 3, i32 2, i32 1, i32 0>
  store <4 x i8> %reverse40, ptr %gep44, align 1, !tbaa !5, !alias.scope !20
  %index.next41 = add nuw i64 %index33, 4
  %31 = icmp eq i64 %index.next41, %n.vec28
  br i1 %31, label %vec.epilog.middle.block, label %vec.epilog.vector.body, !llvm.loop !22

vec.epilog.middle.block:                          ; preds = %vec.epilog.vector.body
  %cmp.n42 = icmp eq i64 %17, %n.vec28
  br i1 %cmp.n42, label %.loopexit, label %.lr.ph.preheader

.lr.ph.preheader:                                 ; preds = %vec.epilog.middle.block, %vector.memcheck, %iter.check, %vec.epilog.iter.check
  %.015.ph = phi ptr [ %0, %iter.check ], [ %0, %vector.memcheck ], [ %ind.end29, %vec.epilog.iter.check ], [ %ind.end, %vec.epilog.middle.block ]
  %.01114.ph = phi ptr [ %1, %iter.check ], [ %1, %vector.memcheck ], [ %ind.end31, %vec.epilog.iter.check ], [ %ind.end30, %vec.epilog.middle.block ]
  br label %.lr.ph

.lr.ph:                                           ; preds = %.lr.ph.preheader, %.lr.ph
  %.015 = phi ptr [ %34, %.lr.ph ], [ %.015.ph, %.lr.ph.preheader ]
  %.01114 = phi ptr [ %35, %.lr.ph ], [ %.01114.ph, %.lr.ph.preheader ]
  %32 = load i8, ptr %.015, align 1, !tbaa !5
  %33 = load i8, ptr %.01114, align 1, !tbaa !5
  store i8 %33, ptr %.015, align 1, !tbaa !5
  store i8 %32, ptr %.01114, align 1, !tbaa !5
  %34 = getelementptr inbounds i8, ptr %.015, i64 1
  %35 = getelementptr inbounds i8, ptr %.01114, i64 -1
  %36 = icmp ult ptr %34, %35
  br i1 %36, label %.lr.ph, label %.loopexit, !llvm.loop !23

.loopexit:                                        ; preds = %.lr.ph, %middle.block, %vec.epilog.middle.block, %2
  ret void
}

; Function Attrs: nocallback nofree nosync nounwind speculatable willreturn memory(none)
declare i64 @llvm.umax.i64(i64, i64) #1

attributes #0 = { nofree norecurse nosync nounwind memory(readwrite, inaccessiblemem: none) uwtable "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cmov,+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" }
attributes #1 = { nocallback nofree nosync nounwind speculatable willreturn memory(none) }

!llvm.module.flags = !{!0, !1, !2, !3}
!llvm.ident = !{!4}

!0 = !{i32 1, !"wchar_size", i32 4}
!1 = !{i32 8, !"PIC Level", i32 2}
!2 = !{i32 7, !"PIE Level", i32 2}
!3 = !{i32 7, !"uwtable", i32 2}
!4 = !{!"clang version 19.1.0 (git@github.com:llvm/llvm-project.git a4bf6cd7cfb1a1421ba92bca9d017b49936c55e4)"}
!5 = !{!6, !6, i64 0}
!6 = !{!"omnipotent char", !7, i64 0}
!7 = !{!"Simple C/C++ TBAA"}
!8 = !{!9}
!9 = distinct !{!9, !10}
!10 = distinct !{!10, !"LVerDomain"}
!11 = !{!12}
!12 = distinct !{!12, !10}
!13 = distinct !{!13, !14, !15, !16}
!14 = !{!"llvm.loop.mustprogress"}
!15 = !{!"llvm.loop.isvectorized", i32 1}
!16 = !{!"llvm.loop.unroll.runtime.disable"}
!17 = !{!18}
!18 = distinct !{!18, !19}
!19 = distinct !{!19, !"LVerDomain"}
!20 = !{!21}
!21 = distinct !{!21, !19}
!22 = distinct !{!22, !14, !15, !16}
!23 = distinct !{!23, !14, !15}


; Effective O3 passes: GlobalDCEPass,GlobalOptPass,InferFunctionAttrsPass,InstCombinePass,JumpThreadingPass,LICMPass,LoopLoadEliminationPass,LoopRotatePass,LoopSimplifyPass,LoopUnrollPass,LoopVectorizePass,PostOrderFunctionAttrsPass,SROAPass,SimplifyCFGPass,TailCallElimPass