Skip to content

GVN incorrectly changes a load into a bitcast #48826

@wsmoses

Description

@wsmoses
Bugzilla Link 49482
Resolution FIXED
Resolved on Jun 03, 2021 23:16
Version trunk
OS All
Blocks #48661 #48289
CC @jdoerfert,@tstellar,@wsmoses
Fixed by commit(s) 875891a 77b63ce

Extended Description

GVN has emits incorrect results when given an invariant.group

; ModuleID = 'tc.ll'
source_filename = "Main.cpp"
target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
target triple = "x86_64-unknown-linux-gnu"

%struct.c = type { double, double }

@.str = private unnamed_addr constant [4 x i8] c"%f\0A\00", align 1

; Function Attrs: norecurse uwtable mustprogress
define dso_local i32 @​main() local_unnamed_addr #​0 {
entry:
  %call = tail call noalias dereferenceable_or_null(12297664) i8* @​malloc(i64 12297664) #​3
  %0 = bitcast i8* %call to %struct.c*
  %call1 = tail call noalias dereferenceable_or_null(12297664) i8* @​malloc(i64 12297664) #​3
  br label %for.body

for.body:                                         ; preds = %for.body, %entry
  %indvars.iv = phi i64 [ 0, %entry ], [ %indvars.iv.next, %for.body ]
  %tr = trunc i64 %indvars.iv to i32
  %conv = sitofp i32 %tr to double
  %a = getelementptr inbounds %struct.c, %struct.c* %0, i64 %indvars.iv, i32 0
  store double %conv, double* %a, align 8
  %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
  %exitcond.not = icmp eq i64 %indvars.iv.next, 768604
  br i1 %exitcond.not, label %for.cond.cleanup, label %for.body, !llvm.loop !​2

for.cond.cleanup:                                 ; preds = %for.body
  %arrayidx7.i.i = getelementptr inbounds i8, i8* %call, i64 10489184
  %malloccall19.i = call noalias nonnull dereferenceable(16) dereferenceable_or_null(16) i8* @​malloc(i64 16) #​3, !noalias !​4
  %_malloccache.i = bitcast i8* %malloccall19.i to %struct.c**
  %malloccall23.i = call noalias nonnull dereferenceable(16) dereferenceable_or_null(16) i8* @​malloc(i64 16) #​3, !noalias !​4
  br label %for.body.i

for.body.i:                                       ; preds = %for.body.i, %for.cond.cleanup
  %iv.i = phi i64 [ 0, %for.cond.cleanup ], [ %iv.next.i, %for.body.i ]
  %1 = phi double [ 0.000000e+00, %for.cond.cleanup ], [ %add.i, %for.body.i ]
  %iv.next.i = add nuw nsw i64 %iv.i, 1
  %2 = bitcast i8* %arrayidx7.i.i to %struct.c*
  %3 = getelementptr inbounds %struct.c*, %struct.c** %_malloccache.i, i64 %iv.i
  store %struct.c* %2, %struct.c** %3, align 8, !invariant.group !​7
  %a10.i.i = getelementptr inbounds %struct.c, %struct.c* %2, i64 0, i32 0
  %4 = load double, double* %a10.i.i, align 8, !invariant.group !​8
  %sub.i.i = fsub double 1.000000e+00, %4
  %div11.i.i = fdiv double 1.000000e+00, %sub.i.i
  %add.i = fadd double %1, %div11.i.i
  %exitcond.i.not = icmp eq i64 %iv.next.i, 2
  br i1 %exitcond.i.not, label %diffe_Z1pP1cPd.exit, label %for.body.i, !llvm.loop !​9

diffe_Z1pP1cPd.exit:                              ; preds = %for.body.i
  %call4 = call i32 (i8*, ...) @​printf(i8* nonnull dereferenceable(1) getelementptr inbounds ([4 x i8], [4 x i8]* @.str, i64 0, i64 0), double %add.i)
  ret i32 0
}

; Function Attrs: inaccessiblememonly nofree nounwind willreturn
declare dso_local noalias noundef i8* @​malloc(i64 noundef) local_unnamed_addr #​1

; Function Attrs: nofree nounwind
declare dso_local noundef i32 @​printf(i8* nocapture noundef readonly, ...) local_unnamed_addr #​2

attributes #​0 = { norecurse uwtable mustprogress "frame-pointer"="none" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" }
attributes #​1 = { inaccessiblememonly nofree nounwind willreturn "frame-pointer"="none" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" }
attributes #​2 = { nofree nounwind "frame-pointer"="none" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" }
attributes #​3 = { nounwind }

!llvm.module.flags = !{#0}
!llvm.ident = !{#1}

!​0 = !{i32 1, !"wchar_size", i32 4}
!​1 = !{!"clang version 13.0.0 (git%github.com:llvm/llvm-project d163e75c81c1609855b98cbdffa0141c70d8578d)"}
!​2 = distinct !{#2, !​3}
!​3 = !{!"llvm.loop.mustprogress"}
!​4 = !{#5}
!​5 = distinct !{#5, !​6, !"diffe_Z1pP1cPd: %q"}
!​6 = distinct !{#6, !"diffe_Z1pP1cPd"}
!​7 = distinct !{}
!​8 = distinct !{}
!​9 = distinct !{#9, !​3}
$ /mnt/sabrent/wmoses/llvm13/build/bin/opt tc.ll | /mnt/sabrent/wmoses/llvm13/build/bin/lli -
-0.000003
$ /mnt/sabrent/wmoses/llvm13/build/bin/opt -gvn tc.ll | /mnt/sabrent/wmoses/llvm13/build/bin/lli -
2.000000

Removing one of the two invariant.groups appears to fix the incorrect behavior of gvn.

Metadata

Metadata

Assignees

Labels

bugzillaIssues migrated from bugzilla

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions