assertion triggered since update to llvm 5

When zig updated to llvm 5 we started hitting this assertion:

zig: /home/andy/downloads/llvm-project/llvm/include/llvm/Support/Casting.h:106: static bool llvm::isa_impl_cl<To, const From*>::doit(const From*) [with To = llvm::Instruction; From = llvm::Value]: Assertion `Val && “isa<> used on a null pointer”’ failed.

I wonder if however this was caused by an invalid assertion, because up the stack is

#8 0x0000000004b58e68 in (anonymous namespace)::NewGVN::InstrToDFSNum (this=0x7fffffffaf80,
V=0x0) at /home/andy/downloads/llvm-project/llvm/lib/Transforms/Scalar/NewGVN.cpp:735
735 assert(isa(V) && “This should not be used for MemoryAccesses”);

With assertions off the code works fine.
Can anyone provide some guidance?

Here is a full backtrace:

zig: /home/andy/downloads/llvm-project/llvm/include/llvm/Support/Casting.h:106: static bool llvm::isa_impl_cl<To, const From*>::doit(const From*) [with To = llvm::Instruction; From = llvm::Value]: Assertion `Val && “isa<> used on a null pointer”’ failed.

Program received signal SIGABRT, Aborted.
0x00007ffff698f3d4 in raise ()
from /nix/store/s7dw1yngwiskqa2ac1bkc6m9g7740agg-glibc-2.25/lib/libc.so.6
(gdb) bt
#0 0x00007ffff698f3d4 in raise ()
from /nix/store/s7dw1yngwiskqa2ac1bkc6m9g7740agg-glibc-2.25/lib/libc.so.6
#1 0x00007ffff699083a in abort ()
from /nix/store/s7dw1yngwiskqa2ac1bkc6m9g7740agg-glibc-2.25/lib/libc.so.6
#2 0x00007ffff69881a7 in __assert_fail_base ()
from /nix/store/s7dw1yngwiskqa2ac1bkc6m9g7740agg-glibc-2.25/lib/libc.so.6
#3 0x00007ffff6988252 in __assert_fail ()
from /nix/store/s7dw1yngwiskqa2ac1bkc6m9g7740agg-glibc-2.25/lib/libc.so.6
#4 0x0000000002d70389 in llvm::isa_impl_cl<llvm::Instruction, llvm::Value const*>::doit (
Val=0x0) at /home/andy/downloads/llvm-project/llvm/include/llvm/Support/Casting.h:106
#5 0x0000000002d4f8af in llvm::isa_impl_wrap<llvm::Instruction, llvm::Value const*, llvm::Value const*>::doit (Val=@0x7fffffffa678: 0x0)
at /home/andy/downloads/llvm-project/llvm/include/llvm/Support/Casting.h:133
#6 0x0000000002ece9a3 in llvm::isa_impl_wrap<llvm::Instruction, llvm::Value const* const, llvm::Value const*>::doit (Val=@0x7fffffffa6b0: 0x0)
at /home/andy/downloads/llvm-project/llvm/include/llvm/Support/Casting.h:125
#7 0x0000000002ecd4f4 in llvm::isa<llvm::Instruction, llvm::Value const*> (
Val=@0x7fffffffa6b0: 0x0)
at /home/andy/downloads/llvm-project/llvm/include/llvm/Support/Casting.h:144
#8 0x0000000004b58e68 in (anonymous namespace)::NewGVN::InstrToDFSNum (this=0x7fffffffaf80,
V=0x0) at /home/andy/downloads/llvm-project/llvm/lib/Transforms/Scalar/NewGVN.cpp:735
#9 0x0000000004b6870d in (anonymous namespace)::NewGVN::touchAndErase<llvm::DenseMap<llvm::Value const*, llvm::SmallPtrSet<llvm::Value*, 2u> >, llvm::Value*> (this=0x7fffffffaf80, M=…,
Key=@0x7fffffffa790: 0x9154cf8)
at /home/andy/downloads/llvm-project/llvm/lib/Transforms/Scalar/NewGVN.cpp:1930
#10 0x0000000004b5d9b7 in (anonymous namespace)::NewGVN::markUsersTouched (this=0x7fffffffaf80,
V=0x9154cf8) at /home/andy/downloads/llvm-project/llvm/lib/Transforms/Scalar/NewGVN.cpp:1946
#11 0x0000000004b5f141 in (anonymous namespace)::NewGVN::performCongruenceFinding (
this=0x7fffffffaf80, I=0x9154cf8, E=0x91d7b70)
at /home/andy/downloads/llvm-project/llvm/lib/Transforms/Scalar/NewGVN.cpp:2269
#12 0x0000000004b62174 in (anonymous namespace)::NewGVN::valueNumberInstruction (
this=0x7fffffffaf80, I=0x9154cf8)
at /home/andy/downloads/llvm-project/llvm/lib/Transforms/Scalar/NewGVN.cpp:2801
#13 0x0000000004b63b4f in (anonymous namespace)::NewGVN::iterateTouchedInstructions (
this=0x7fffffffaf80)
at /home/andy/downloads/llvm-project/llvm/lib/Transforms/Scalar/NewGVN.cpp:3094
#14 0x0000000004b6431c in (anonymous namespace)::NewGVN::runGVN (this=0x7fffffffaf80)
at /home/andy/downloads/llvm-project/llvm/lib/Transforms/Scalar/NewGVN.cpp:3165
#15 0x0000000004b678db in (anonymous namespace)::NewGVNLegacyPass::runOnFunction (
this=0x910ea50, F=…)
at /home/andy/downloads/llvm-project/llvm/lib/Transforms/Scalar/NewGVN.cpp:3904
#16 0x00000000054d10fd in llvm::FPPassManager::runOnFunction (this=0x9102260, F=…)
at /home/andy/downloads/llvm-project/llvm/lib/IR/LegacyPassManager.cpp:1514
#17 0x0000000004f2a375 in (anonymous namespace)::CGPassManager::RunPassOnSCC (this=0x9100f00,
P=0x9102260, CurSCC=…, CG=…, CallGraphUpToDate=@0x7fffffffbc2f: true,
DevirtualizedCall=@0x7fffffffbccf: false)
at /home/andy/downloads/llvm-project/llvm/lib/Analysis/CallGraphSCCPass.cpp:149
#18 0x0000000004f2b349 in (anonymous namespace)::CGPassManager::RunAllPassesOnSCC (
this=0x9100f00, CurSCC=…, CG=…, DevirtualizedCall=@0x7fffffffbccf: false)
at /home/andy/downloads/llvm-project/llvm/lib/Analysis/CallGraphSCCPass.cpp:419
#19 0x0000000004f2b643 in (anonymous namespace)::CGPassManager::runOnModule (this=0x9100f00,
M=…) at /home/andy/downloads/llvm-project/llvm/lib/Analysis/CallGraphSCCPass.cpp:474
#20 0x00000000054d15c1 in (anonymous namespace)::MPPassManager::runOnModule (this=0x90f9970,
—Type to continue, or q to quit—
M=…) at /home/andy/downloads/llvm-project/llvm/lib/IR/LegacyPassManager.cpp:1591
#21 0x00000000054d1c73 in llvm::legacy::PassManagerImpl::run (this=0x90f9480, M=…)
at /home/andy/downloads/llvm-project/llvm/lib/IR/LegacyPassManager.cpp:1694
#22 0x00000000054d1e7f in llvm::legacy::PassManager::run (this=0x7fffffffc010, M=…)
at /home/andy/downloads/llvm-project/llvm/lib/IR/LegacyPassManager.cpp:1725
#23 0x0000000001d4017d in ZigLLVMTargetMachineEmitToFile (targ_machine_ref=0x9080d50,
module_ref=0x907e870, filename=0x90cf360 “./zig-cache/test.o”, file_type=LLVMObjectFile,
error_message=0x7fffffffc2f8, is_debug=false) at /home/andy/dev/zig/src/zig_llvm.cpp:166
#24 0x0000000001cd041d in do_code_gen (g=0x907a980) at /home/andy/dev/zig/src/codegen.cpp:4379
#25 0x0000000001cd4634 in codegen_build (g=0x907a980) at /home/andy/dev/zig/src/codegen.cpp:5484
#26 0x0000000001d1d564 in main (argc=4, argv=0x7fffffffca18)
at /home/andy/dev/zig/src/main.cpp:666

Here’s the smallest zig test case to cause the problem:

export fn entry() {
var bytes: const u8 = “format”;
write(bytes);
}

pub fn write(bytes: const u8) {
var index: usize = 0;

var src_index: usize = 0;

while (src_index < bytes.len) {
const dest_space_left = 1 - index;
const b = bytes.len - src_index;
const copy_amt = if (dest_space_left < b) dest_space_left else b;
index += copy_amt;
src_index += copy_amt;
}
}

pub fn panic(msg: const u8) → noreturn { while (true) {} }

compile with ./zig build_obj test.zig --release-safe
This does the equivalent of -O3

The IR that it produces; ModuleID = ‘test’
source_filename = “test”
target datalayout = “e-m:e-i64:64-f80:128-n8:16:32:64-S128”
target triple = “x86_64-unknown-linux-gnu”

%“u8” = type { i8*, i64 }

@__zig_panic_implementation_provided = internal unnamed_addr constant i1 true, align 1
@0 = internal unnamed_addr constant i8* getelementptr inbounds ([6 x i8], [6 x i8]* @1, i64 0, i64 0), align 8
@1 = internal unnamed_addr constant [6 x i8] c"format", align 1
@2 = internal unnamed_addr constant { i8*, i64 } { i8* getelementptr inbounds ([6 x i8], [6 x i8]* @1, i64 0, i64 0), i64 6 }, align 8
@3 = internal unnamed_addr constant i8* getelementptr inbounds ([16 x i8], [16 x i8]* @4, i64 0, i64 0), align 8
@4 = internal unnamed_addr constant [16 x i8] c"integer overflow", align 1
@5 = internal unnamed_addr constant { i8*, i64 } { i8* getelementptr inbounds ([16 x i8], [16 x i8]* @4, i64 0, i64 0), i64 16 }, align 8

; Function Attrs: nobuiltin nounwind
define void @entry() #0 !dbg !16 {
Entry:
%bytes = alloca %“u8”, align 8
%0 = bitcast %“u8”* %bytes to i8*, !dbg !31
call void @llvm.memcpy.p0i8.p0i8.i64(i8* %0, i8* bitcast ({ i8*, i64 }* @2 to i8*), i64 16, i32 8, i1 false), !dbg !31
call void @llvm.dbg.declare(metadata %“u8”* %bytes, metadata !22, metadata !32), !dbg !31
call fastcc void @write(%“u8”* byval %bytes), !dbg !33
ret void, !dbg !35
}

; Function Attrs: cold nobuiltin noreturn nounwind
define linkonce coldcc void @__zig_panic(i8* nonnull readonly, i64) #1 !dbg !36 {
Entry:
%2 = alloca %“u8”, align 8
%message_ptr = alloca i8*, align 8
%message_len = alloca i64, align 8
store i8* %0, i8** %message_ptr, align 8
call void @llvm.dbg.declare(metadata i8** %message_ptr, metadata !41, metadata !32), !dbg !44
store i64 %1, i64* %message_len, align 8
call void @llvm.dbg.declare(metadata i64* %message_len, metadata !42, metadata !32), !dbg !45
%3 = load i64, i64* %message_len, align 8, !dbg !46
%4 = load i8*, i8** %message_ptr, align 8, !dbg !50
%5 = getelementptr inbounds %“u8”, %“u8”* %2, i32 0, i32 0, !dbg !50
%6 = getelementptr inbounds i8, i8* %4, i64 0, !dbg !50
store i8* %6, i8** %5, align 8, !dbg !50
%7 = getelementptr inbounds %“u8”, %“u8”* %2, i32 0, i32 1, !dbg !50
%8 = sub nsw i64 %3, 0, !dbg !50
store i64 %8, i64* %7, align 8, !dbg !50
call fastcc void @panic(%“u8”* byval %2), !dbg !51
unreachable, !dbg !51
}

; Function Attrs: nobuiltin nounwind
define internal fastcc void @write(%“u8”* byval nonnull readonly) unnamed_addr #0 !dbg !52 {
Entry:
%index = alloca i64, align 8
%src_index = alloca i64, align 8
%dest_space_left = alloca i64, align 8
%b = alloca i64, align 8
%copy_amt = alloca i64, align 8
call void @llvm.dbg.declare(metadata %“u8”* %0, metadata !57, metadata !32), !dbg !70
store i64 0, i64* %index, align 8, !dbg !71
call void @llvm.dbg.declare(metadata i64* %index, metadata !58, metadata !32), !dbg !71
store i64 0, i64* %src_index, align 8, !dbg !72
call void @llvm.dbg.declare(metadata i64* %src_index, metadata !61, metadata !32), !dbg !72
br label %WhileCond, !dbg !73

WhileCond: ; preds = %OverflowOk6, %Entry
%1 = load i64, i64* %src_index, align 8, !dbg !74
%2 = getelementptr inbounds %“u8”, %“u8”* %0, i32 0, i32 1, !dbg !75
%3 = load i64, i64* %2, align 8, !dbg !75
%4 = icmp ult i64 %1, %3, !dbg !76
br i1 %4, label %WhileBody, label %WhileEnd, !dbg !76

WhileBody: ; preds = %WhileCond
%5 = load i64, i64* %index, align 8, !dbg !77
%6 = call { i64, i1 } @llvm.usub.with.overflow.i64(i64 1, i64 %5), !dbg !78
%7 = extractvalue { i64, i1 } %6, 0, !dbg !78
%8 = extractvalue { i64, i1 } %6, 1, !dbg !78
br i1 %8, label %OverflowFail, label %OverflowOk, !dbg !78

WhileEnd: ; preds = %WhileCond
ret void, !dbg !79

Then: ; preds = %OverflowOk2
%9 = load i64, i64* %dest_space_left, align 8, !dbg !80
br label %EndIf, !dbg !81

Else: ; preds = %OverflowOk2
%10 = load i64, i64* %b, align 8, !dbg !82
br label %EndIf, !dbg !81

EndIf: ; preds = %Else, %Then
%11 = phi i64 [ %9, %Then ], [ %10, %Else ], !dbg !81
store i64 %11, i64* %copy_amt, align 8, !dbg !83
call void @llvm.dbg.declare(metadata i64* %copy_amt, metadata !68, metadata !32), !dbg !83
%12 = load i64, i64* %index, align 8, !dbg !84
%13 = load i64, i64* %copy_amt, align 8, !dbg !86
%14 = call { i64, i1 } @llvm.uadd.with.overflow.i64(i64 %12, i64 %13), !dbg !87
%15 = extractvalue { i64, i1 } %14, 0, !dbg !87
%16 = extractvalue { i64, i1 } %14, 1, !dbg !87
br i1 %16, label %OverflowFail3, label %OverflowOk4, !dbg !87

OverflowFail: ; preds = %WhileBody
%17 = load i8*, i8** getelementptr inbounds ({ i8*, i64 }, { i8*, i64 }* @5, i32 0, i32 0), align 8, !dbg !78
%18 = load i64, i64* getelementptr inbounds ({ i8*, i64 }, { i8*, i64 }* @5, i32 0, i32 1), align 8, !dbg !78
call coldcc void @__zig_panic(i8* %17, i64 %18), !dbg !78
unreachable, !dbg !78

OverflowOk: ; preds = %WhileBody
store i64 %7, i64* %dest_space_left, align 8, !dbg !88
call void @llvm.dbg.declare(metadata i64* %dest_space_left, metadata !63, metadata !32), !dbg !88
%19 = getelementptr inbounds %“u8”, %“u8”* %0, i32 0, i32 1, !dbg !89
%20 = load i64, i64* %19, align 8, !dbg !89
%21 = load i64, i64* %src_index, align 8, !dbg !90
%22 = call { i64, i1 } @llvm.usub.with.overflow.i64(i64 %20, i64 %21), !dbg !91
%23 = extractvalue { i64, i1 } %22, 0, !dbg !91
%24 = extractvalue { i64, i1 } %22, 1, !dbg !91
br i1 %24, label %OverflowFail1, label %OverflowOk2, !dbg !91

OverflowFail1: ; preds = %OverflowOk
%25 = load i8*, i8** getelementptr inbounds ({ i8*, i64 }, { i8*, i64 }* @5, i32 0, i32 0), align 8, !dbg !91
%26 = load i64, i64* getelementptr inbounds ({ i8*, i64 }, { i8*, i64 }* @5, i32 0, i32 1), align 8, !dbg !91
call coldcc void @__zig_panic(i8* %25, i64 %26), !dbg !91
unreachable, !dbg !91

OverflowOk2: ; preds = %OverflowOk
store i64 %23, i64* %b, align 8, !dbg !92
call void @llvm.dbg.declare(metadata i64* %b, metadata !66, metadata !32), !dbg !92
%27 = load i64, i64* %dest_space_left, align 8, !dbg !93
%28 = load i64, i64* %b, align 8, !dbg !94
%29 = icmp ult i64 %27, %28, !dbg !95
br i1 %29, label %Then, label %Else, !dbg !95

OverflowFail3: ; preds = %EndIf
%30 = load i8*, i8** getelementptr inbounds ({ i8*, i64 }, { i8*, i64 }* @5, i32 0, i32 0), align 8, !dbg !87
%31 = load i64, i64* getelementptr inbounds ({ i8*, i64 }, { i8*, i64 }* @5, i32 0, i32 1), align 8, !dbg !87
call coldcc void @__zig_panic(i8* %30, i64 %31), !dbg !87
unreachable, !dbg !87

OverflowOk4: ; preds = %EndIf
store i64 %15, i64* %index, align 8, !dbg !87
%32 = load i64, i64* %src_index, align 8, !dbg !96
%33 = load i64, i64* %copy_amt, align 8, !dbg !97
%34 = call { i64, i1 } @llvm.uadd.with.overflow.i64(i64 %32, i64 %33), !dbg !98
%35 = extractvalue { i64, i1 } %34, 0, !dbg !98
%36 = extractvalue { i64, i1 } %34, 1, !dbg !98
br i1 %36, label %OverflowFail5, label %OverflowOk6, !dbg !98

OverflowFail5: ; preds = %OverflowOk4
%37 = load i8*, i8** getelementptr inbounds ({ i8*, i64 }, { i8*, i64 }* @5, i32 0, i32 0), align 8, !dbg !98
%38 = load i64, i64* getelementptr inbounds ({ i8*, i64 }, { i8*, i64 }* @5, i32 0, i32 1), align 8, !dbg !98
call coldcc void @__zig_panic(i8* %37, i64 %38), !dbg !98
unreachable, !dbg !98

OverflowOk6: ; preds = %OverflowOk4
store i64 %35, i64* %src_index, align 8, !dbg !98
br label %WhileCond, !dbg !73
}

; Function Attrs: nobuiltin noreturn nounwind
define internal fastcc void @panic(%“u8”* byval nonnull readonly) unnamed_addr #2 !dbg !99 {
Entry:
call void @llvm.dbg.declare(metadata %“u8”* %0, metadata !101, metadata !32), !dbg !102
br label %WhileCond, !dbg !103

WhileCond: ; preds = %WhileCond, %Entry
br label %WhileCond, !dbg !103
}

; Function Attrs: argmemonly nounwind
declare void @llvm.memcpy.p0i8.p0i8.i64(i8* nocapture writeonly, i8* nocapture readonly, i64, i32, i1) #3

; Function Attrs: nounwind readnone speculatable
declare void @llvm.dbg.declare(metadata, metadata, metadata) #4

; Function Attrs: nounwind readnone speculatable
declare { i64, i1 } @llvm.usub.with.overflow.i64(i64, i64) #4

; Function Attrs: nounwind readnone speculatable
declare { i64, i1 } @llvm.uadd.with.overflow.i64(i64, i64) #4

attributes #0 = { nobuiltin nounwind }
attributes #1 = { cold nobuiltin noreturn nounwind }
attributes #2 = { nobuiltin noreturn nounwind }
attributes #3 = { argmemonly nounwind }
attributes #4 = { nounwind readnone speculatable }

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

!0 = !{i32 2, !“Debug Info Version”, i32 3}
!1 = distinct !DICompileUnit(language: DW_LANG_C99, file: !2, producer: “zig 0.0.0”, isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !3, globals: !12)
!2 = !DIFile(filename: “test”, directory: “.”)
!3 = !{!4}
!4 = !DICompositeType(tag: DW_TAG_enumeration_type, name: “GlobalLinkage”, scope: !5, file: !5, line: 138, baseType: !6, size: 8, align: 8, elements: !7)
!5 = !DIFile(filename: “builtin.zig”, directory: “/home/andy/dev/zig/build-llvm5-debug/zig-cache”)
!6 = !DIBasicType(name: “u3”, size: 8, encoding: DW_ATE_unsigned)
!7 = !{!8, !9, !10, !11}
!8 = !DIEnumerator(name: “Internal”, value: 0)
!9 = !DIEnumerator(name: “Strong”, value: 1)
!10 = !DIEnumerator(name: “Weak”, value: 2)
!11 = !DIEnumerator(name: “LinkOnce”, value: 3)
!12 = !{!13}
!13 = !DIGlobalVariableExpression(var: !14)
!14 = distinct !DIGlobalVariable(name: “__zig_panic_implementation_provided”, linkageName: “__zig_panic_implementation_provided”, scope: !5, file: !5, line: 201, type: !15, isLocal: true, isDefinition: true)
!15 = !DIBasicType(name: “bool”, size: 8, encoding: DW_ATE_boolean)
!16 = distinct !DISubprogram(name: “entry”, scope: !17, file: !17, type: !18, isLocal: false, isDefinition: true, isOptimized: true, unit: !1, variables: !21)
!17 = !DIFile(filename: “test.zig”, directory: “/home/andy/dev/zig/build-llvm5-debug”)
!18 = !DISubroutineType(types: !19)
!19 = !{!20}
!20 = !DIBasicType(name: “void”, encoding: DW_ATE_unsigned)
!21 = !{!22}
!22 = !DILocalVariable(name: “bytes”, scope: !23, file: !17, line: 2, type: !24)
!23 = distinct !DILexicalBlock(scope: !16, file: !17, line: 1, column: 19)
!24 = !DICompositeType(tag: DW_TAG_structure_type, name: “u8”, size: 128, align: 64, elements: !25)
!25 = !{!26, !29}
!26 = !DIDerivedType(tag: DW_TAG_member, name: “ptr”, scope: !24, baseType: !27, size: 64, align: 64)
!27 = !DIDerivedType(tag: DW_TAG_pointer_type, name: “&u8”, baseType: !28, size: 64, align: 64)
!28 = !DIBasicType(name: “u8”, size: 8, encoding: DW_ATE_unsigned_char)
!29 = !DIDerivedType(tag: DW_TAG_member, name: “len”, scope: !24, baseType: !30, size: 64, align: 64, offset: 64)
!30 = !DIBasicType(name: “usize”, size: 64, encoding: DW_ATE_unsigned)
!31 = !DILocation(line: 2, column: 5, scope: !23)
!32 = !DIExpression()
!33 = !DILocation(line: 3, column: 10, scope: !34)
!34 = distinct !DILexicalBlock(scope: !23, file: !17, line: 2, column: 5)
!35 = !DILocation(line: 1, column: 19, scope: !16)
!36 = distinct !DISubprogram(name: “__zig_panic”, scope: !37, file: !37, line: 7, type: !38, isLocal: false, isDefinition: true, scopeLine: 7, isOptimized: true, unit: !1, variables: !40)
!37 = !DIFile(filename: “zigrt.zig”, directory: “/home/andy/dev/zig/build-llvm5-debug/lib/zig/std/special”)
!38 = !DISubroutineType(types: !39)
!39 = !{!20, !27, !30}
!40 = !{!41, !42}
!41 = !DILocalVariable(name: “message_ptr”, arg: 1, scope: !36, file: !37, line: 7, type: !27)
!42 = !DILocalVariable(name: “message_len”, arg: 2, scope: !43, file: !37, line: 7, type: !30)
!43 = distinct !DILexicalBlock(scope: !36, file: !37, line: 7, column: 30)
!44 = !DILocation(line: 7, column: 30, scope: !36)
!45 = !DILocation(line: 7, column: 54, scope: !43)
!46 = !DILocation(line: 12, column: 48, scope: !47)
!47 = distinct !DILexicalBlock(scope: !48, file: !37, line: 11, column: 54)
!48 = distinct !DILexicalBlock(scope: !49, file: !37, line: 7, column: 86)
!49 = distinct !DILexicalBlock(scope: !43, file: !37, line: 7, column: 54)
!50 = !DILocation(line: 12, column: 43, scope: !47)
!51 = !DILocation(line: 12, column: 31, scope: !47)
!52 = distinct !DISubprogram(name: “write”, scope: !17, file: !17, line: 6, type: !53, isLocal: true, isDefinition: true, scopeLine: 6, isOptimized: true, unit: !1, variables: !56)
!53 = !DISubroutineType(types: !54)
!54 = !{!20, !55}
!55 = !DIDerivedType(tag: DW_TAG_pointer_type, name: “&const u8”, baseType: !24, size: 64, align: 64)
!56 = !{!57, !58, !61, !63, !66, !68}
!57 = !DILocalVariable(name: “bytes”, arg: 1, scope: !52, file: !17, line: 6, type: !24)
!58 = !DILocalVariable(name: “index”, scope: !59, file: !17, line: 7, type: !30)
!59 = distinct !DILexicalBlock(scope: !60, file: !17, line: 6, column: 33)
!60 = distinct !DILexicalBlock(scope: !52, file: !17, line: 6, column: 14)
!61 = !DILocalVariable(name: “src_index”, scope: !62, file: !17, line: 9, type: !30)
!62 = distinct !DILexicalBlock(scope: !59, file: !17, line: 7, column: 5)
!63 = !DILocalVariable(name: “dest_space_left”, scope: !64, file: !17, line: 12, type: !30)
!64 = distinct !DILexicalBlock(scope: !65, file: !17, line: 11, column: 35)
!65 = distinct !DILexicalBlock(scope: !62, file: !17, line: 9, column: 5)
!66 = !DILocalVariable(name: “b”, scope: !67, file: !17, line: 13, type: !30)
!67 = distinct !DILexicalBlock(scope: !64, file: !17, line: 12, column: 9)
!68 = !DILocalVariable(name: “copy_amt”, scope: !69, file: !17, line: 14, type: !30)
!69 = distinct !DILexicalBlock(scope: !67, file: !17, line: 13, column: 9)
!70 = !DILocation(line: 6, column: 14, scope: !52)
!71 = !DILocation(line: 7, column: 5, scope: !59)
!72 = !DILocation(line: 9, column: 5, scope: !62)
!73 = !DILocation(line: 11, column: 5, scope: !65)
!74 = !DILocation(line: 11, column: 12, scope: !65)
!75 = !DILocation(line: 11, column: 29, scope: !65)
!76 = !DILocation(line: 11, column: 22, scope: !65)
!77 = !DILocation(line: 12, column: 37, scope: !64)
!78 = !DILocation(line: 12, column: 35, scope: !64)
!79 = !DILocation(line: 11, column: 5, scope: !60)
!80 = !DILocation(line: 14, column: 51, scope: !69)
!81 = !DILocation(line: 14, column: 26, scope: !69)
!82 = !DILocation(line: 14, column: 72, scope: !69)
!83 = !DILocation(line: 14, column: 9, scope: !69)
!84 = !DILocation(line: 15, column: 9, scope: !85)
!85 = distinct !DILexicalBlock(scope: !69, file: !17, line: 14, column: 9)
!86 = !DILocation(line: 15, column: 18, scope: !85)
!87 = !DILocation(line: 15, column: 15, scope: !85)
!88 = !DILocation(line: 12, column: 9, scope: !64)
!89 = !DILocation(line: 13, column: 24, scope: !67)
!90 = !DILocation(line: 13, column: 31, scope: !67)
!91 = !DILocation(line: 13, column: 29, scope: !67)
!92 = !DILocation(line: 13, column: 9, scope: !67)
!93 = !DILocation(line: 14, column: 30, scope: !69)
!94 = !DILocation(line: 14, column: 48, scope: !69)
!95 = !DILocation(line: 14, column: 46, scope: !69)
!96 = !DILocation(line: 16, column: 9, scope: !85)
!97 = !DILocation(line: 16, column: 22, scope: !85)
!98 = !DILocation(line: 16, column: 19, scope: !85)
!99 = distinct !DISubprogram(name: “panic”, scope: !17, file: !17, line: 20, type: !53, isLocal: true, isDefinition: true, scopeLine: 20, isOptimized: true, unit: !1, variables: !100)
!100 = !{!101}
!101 = !DILocalVariable(name: “msg”, arg: 1, scope: !99, file: !17, line: 20, type: !24)
!102 = !DILocation(line: 20, column: 14, scope: !99)
!103 = !DILocation(line: 20, column: 45, scope: !104)
!104 = distinct !DILexicalBlock(scope: !105, file: !17, line: 20, column: 43)
!105 = distinct !DILexicalBlock(scope: !99, file: !17, line: 20, column: 14)
is the following, however clang 5 with assertions on does not hit the assertion when run on this IR:

Any pointers would be appreciated.

What do you think about this patch?

— a/llvm/lib/Transforms/Scalar/NewGVN.cpp
+++ b/llvm/lib/Transforms/Scalar/NewGVN.cpp
@@ -732,7 +732,7 @@ private:
MemoryPhi *getMemoryAccess(const BasicBlock *) const;
template <class T, class Range> T *getMinDFSOfRange(const Range &) const;
unsigned InstrToDFSNum(const Value *V) const {

  • assert(isa(V) && “This should not be used for MemoryAccesses”);
  • assert(V == nullptr || (isa(V) && “This should not be used for MemoryAccesses”));
    return InstrDFS.lookup(V);
    }

Can you please open a bug on bugzilla and attach the ir testcase? Your fix doesn’t look right (just hiding the assertion failure)

I think I forgot to mention, the IR does not reproduce the problem. It has to be using the LLVM API. Some kind of in-memory state that gets fixed when serialized and deserialized with IR.

So, 90% of the time I’ve seen this, it was memory corruption, usually use after free. I know I fixed one after 5.0 branched.
You should compile with address sanitizer enabled, and I suspect you will find the issue quicky.
If not, we really need ir that reproduces it.

Valgrind is strictly better than address sanitizer, is that right? It runs valgrind-clean:

[nix-shell:~/dev/zig/build-llvm5-debug]$ valgrind ./zig build-obj test.zig --release-safe
==4585== Memcheck, a memory error detector
==4585== Copyright (C) 2002-2015, and GNU GPL’d, by Julian Seward et al.
==4585== Using Valgrind-3.12.0 and LibVEX; rerun with -h for copyright info
==4585== Command: ./zig build-obj test.zig --release-safe
==4585==
zig: /home/andy/downloads/llvm-project/llvm/include/llvm/Support/Casting.h:106: static bool llvm::isa_impl_cl<To, const From*>::doit(const From*) [with To = llvm::Instruction; From = llvm::Value]: Assertion `Val && “isa<> used on a null pointer”’ failed.
==4585==
==4585== Process terminating with default action of signal 6 (SIGABRT)
==4585== at 0xAF8D3D4: raise (in /nix/store/s7dw1yngwiskqa2ac1bkc6m9g7740agg-glibc-2.25/lib/libc-2.25.so)
==4585== by 0xAF8E839: abort (in /nix/store/s7dw1yngwiskqa2ac1bkc6m9g7740agg-glibc-2.25/lib/libc-2.25.so)
==4585== by 0xAF861A6: __assert_fail_base (in /nix/store/s7dw1yngwiskqa2ac1bkc6m9g7740agg-glibc-2.25/lib/libc-2.25.so)
==4585== by 0xAF86251: __assert_fail (in /nix/store/s7dw1yngwiskqa2ac1bkc6m9g7740agg-glibc-2.25/lib/libc-2.25.so)
==4585== by 0x2D70538: llvm::isa_impl_cl<llvm::Instruction, llvm::Value const*>::doit(llvm::Value const*) (Casting.h:106)
==4585== by 0x2D4FA5E: llvm::isa_impl_wrap<llvm::Instruction, llvm::Value const*, llvm::Value const*>::doit(llvm::Value const* const&) (Casting.h:133)
==4585== by 0x2ECEB52: llvm::isa_impl_wrap<llvm::Instruction, llvm::Value const* const, llvm::Value const*>::doit(llvm::Value const* const&) (Casting.h:125)
==4585== by 0x2ECD6A3: bool llvm::isa<llvm::Instruction, llvm::Value const*>(llvm::Value const* const&) (Casting.h:144)
==4585== by 0x4B59017: (anonymous namespace)::NewGVN::InstrToDFSNum(llvm::Value const*) const (NewGVN.cpp:735)
==4585== by 0x4B688BC: void (anonymous namespace)::NewGVN::touchAndErase<llvm::DenseMap<llvm::Value const*, llvm::SmallPtrSet<llvm::Value*, 2u>, llvm::DenseMapInfo<llvm::Value const*>, llvm::detail::DenseMapPair<llvm::Value const*, llvm::SmallPtrSet<llvm::Value*, 2u> > >, llvm::Value*>(llvm::DenseMap<llvm::Value const*, llvm::SmallPtrSet<llvm::Value*, 2u>, llvm::DenseMapInfo<llvm::Value const*>, llvm::detail::DenseMapPair<llvm::Value const*, llvm::SmallPtrSet<llvm::Value*, 2u> > >&, llvm::Value* const&) (NewGVN.cpp:1930)
==4585== by 0x4B5DB66: (anonymous namespace)::NewGVN::markUsersTouched(llvm::Value*) (NewGVN.cpp:1946)
==4585== by 0x4B5F2F0: (anonymous namespace)::NewGVN::performCongruenceFinding(llvm::Instruction*, llvm::GVNExpression::Expression const*) (NewGVN.cpp:2269)

The test case that triggers the assertion yields IR that clang from the same build can compile without hitting the assertion. I don’t think an IR test case to trigger this necessarily exists.

What path would I go down to come up with this IR?

Dump the IR before newgvn and run through opt -newgvn. It should crash. I’m not familiar with your frontend but you might want to use -mllvm -opt-bisect-limit.

Interesting. I seem to remember fixing a bug where we were accidentally adding null users for real, but i honestly can’t remember if it ever made it into trunk or was just in a local dev branch of mine.

In any case, you should be able to catch whatever is doing this by adding an assert in addAdditionalUsers.

void NewGVN::addAdditionalUsers(Value *To, Value *User) const {
assert(User && To != User);
if (isa(To))
AdditionalUsers[To].insert(User);
}

That should crash when it tries to add the null value in the first place.

If it’s the bug i remember, you will find it is doing this while adding additional users in makePossiblePhiOfOps.
(If so, i believe that bug is already fixed).

Thanks for the suggestion! I added -mllvm support to my frontend, did your
suggestion, and now I have LLVM IR that causes the crash.
Reported here: https://bugs.llvm.org/show_bug.cgi?id=34651

This is with 5.0.0. I don't have a build of master lying around to test
against.

Thanks. This is a dupe of PR 34452.

Thanks Daniel. I appreciate your patience and guiding me through the troubleshooting process. I look forward to 5.0.1.

I haven’t actually tried to backport any newgvn stuff into the llvm 5 branch (because i don’t have any “llvm stable” customer users until you came along).
I’ll have to see how behind trunk the version is.

Being that it’s experimental anyway, i may ask the release manager if i can just shove the latest version in there (they are self contained)

No, it isn't. It doesn't handle stack use for example.

Joerg