LLC crashed in ImplicitNullChecks Pass when compiling an LLVM IR file. An implicit null check metadata triggers the crash, without the “make.implicit” metadata, compile ended successfully.
Crash stack trace:
#10 0x0000555557b47a15 getParent(llvm::Value const*)
#11 0x0000555557b41f76 notDifferentParent(llvm::Value const*, llvm::Value const*)
#12 0x0000555557b41ec7 llvm::BasicAAResult::alias(llvm::MemoryLocation const&, llvm::MemoryLocation const&, llvm::AAQueryInfo&, llvm::Instruction const*)
#13 0x0000555557b3e429 llvm::AAResults::Model< llvm::BasicAAResult>::alias(llvm::MemoryLocation const&, llvm::MemoryLocation const&, llvm::AAQueryInfo&, llvm::Instruction const*)
#14 0x0000555557b34f42 llvm::AAResults::alias(llvm::MemoryLocation const&, llvm::MemoryLocation const&, llvm::AAQueryInfo&, llvm::Instruction const*)
#15 0x0000555557b34d6e llvm::AAResults::alias(llvm::MemoryLocation const&, llvm::MemoryLocation const&)
#16 0x00005555579dad95 llvm::AAResults::isNoAlias(llvm::MemoryLocation const&, llvm::MemoryLocation const&)
#17 0x00005555581da867 (anonymous namespace)::ImplicitNullChecks::areMemoryOpsAliased(llvm::MachineInstr const&, llvm::MachineInstr const*) const
#18 0x00005555581d9d23 (anonymous namespace)::ImplicitNullChecks::isSuitableMemoryOp(llvm::MachineInstr const&, unsigned int, llvm::ArrayRef< llvm::MachineInstr*>)
#19 0x00005555581d8fa4 (anonymous namespace)::ImplicitNullChecks::analyzeBlockForNullChecks(llvm::MachineBasicBlock&, llvm::SmallVectorImpl<(anonymous namespace)::ImplicitNullChecks::NullCheck>&)
#20 0x00005555581d8ab2 (anonymous namespace)::ImplicitNullChecks::runOnMachineFunction(llvm::MachineFunction&)
344 for (MachineMemOperand *MMO1 : MI.memoperands()) {
345 // MMO1 should have a value due it comes from operation we’d like to use
346 // as implicit null check.
347 assert(MMO1->getValue() && “MMO1 should have a Value!”);
348 for (MachineMemOperand *MMO2 : PrevMI->memoperands()) {
349 if (const PseudoSourceValue *PSV = MMO2->getPseudoValue()) {
350 if (PSV->mayAlias(MFI))
351 return AR_MayAlias;
352 continue;
353 }
354 if (!AA->isNoAlias(
355 MemoryLocation::getAfter(MMO1->getValue(), MMO1->getAAInfo()),
356 MemoryLocation::getAfter(MMO2->getValue(), MMO2->getAAInfo())))
357 return AR_MayAlias;
358 }
359 }
360 return AR_NoAlias;
361 }
In lib/CodeGen/ImplicitNullChecks.cpp line 356 (17.0.6),
MMO2->getValue() returns NULL pointer, and MMO2->getValue()->getParent() is invoked without checking the pointer value. I can see there is an assertion in line 347 to make sure MMO1->getValue() is not NULL, but no check for MMO2->getValue().
I am not able to share the full IR due to our policy. And I don’t have a small reproducer currently.
I can only share IR snippet and some information dumped from gdb.
IR snippet:
label_28:
%405 = phi %struct_type_1* [ null, %not_null70 ], [ %404, %397 ]
%406 = load i8*, i8** %24
%407 = load i8*, i8** @ _global_data
%408 = tail call i32 @ library_function_1(i8* %406, i8* %407, i32 0)
%409 = trunc i32 %408 to i1
%410 = getelementptr inbounds i8, i8* %0, i32 989
%411 = zext i1 %409 to i8
store i8 %411, i8* %410
%412 = load i32, i32* %49
%413 = load i32, i32* %54
%414 = select i1 %409, i32 %412, i32 %413
%415 = icmp eq %struct_type_1* %405, null
br i1 %415, label %is_null73, label %not_null72, !make.implicit !10not_null72:
%416 = getelementptr inbounds %struct_type_1, %struct_type_1* %405, i64 0, i32 80
store i32 %414, i32* %416
%417 = load i32, i32* %i20
%418 = load %struct_type_2*, %struct_type_2** %285
%419 = getelementptr inbounds %struct_type_2, %struct_type_2* %418, i64 0, i32 2
%420 = load i32, i32* %419
%421 = icmp ult i32 %417, %420
br i1 %421, label %label_30, label %label_31is_null73:
call void @ library_function_2(i8* %4, i8* %0, i32 2439845, i32 0)
unreachable
GDB
MI.dump()
MOV32mr killed renamable $rbp, 1, $noreg, 288, $noreg, killed renamable $eax :: (store (s32) into %ir.416)PrevMI->dump()
renamable $eax = MOV32rm killed renamable $rax, 1, $noreg, 0, $noreg :: (load (s32))
$8 = voidMMO1->getValue()->dump()
%416 = getelementptr inbounds %struct_type_1, %struct_type_1* %405, i64 0, i32 80MMO2->getValue()
NULL
Although I can add a check in line 354 to check the return of MMO2->getValue() and make the compilation pass. But I am not sure whether this is a proper fix since I don’t know if MMO2->getValue() is expected to be NULL.
The “areMemoryOpsAliased” function is introduced by commit eef785c1a5eef982428be5c1c7a2fc8d7bdf1c84. I would really appreciate your thoughts and feed back on this @serguei-katkov @sanjoyd