Troubleshooting Internal Garbage Collection

Hello,

I’ve made some fair progress on a target for 6502 family CPUs recently, but I’ve run into an error I’m not sure how to address. I’ve ruminated over it for about a week now, trying various things and not having any success. It seems to scale with the number of routines in my .ll file, which I am trying to run through llc. I get the following stack dump from an assertion:

llc: LeaksContext.h:50: void llvm::LeakDetectorImpl::addGarbage(const T*) [with T = void]: Assertion `Ts.count(o) == 0 && “Object already in set!”’ failed.
0 llc 0x08d2cde8
1 llc 0x08d2d344
2 0xb7762400 __kernel_sigreturn + 0
3 0xb7762424 __kernel_vsyscall + 16
4 libc.so.6 0xb746a98f gsignal + 79
5 libc.so.6 0xb746c2d5 abort + 373
6 libc.so.6 0xb74636a5
7 libc.so.6 0xb7463757
8 llc 0x08180167
9 llc 0x08c32bec llvm::LeakDetector::addGarbageObjectImpl(void*) + 380
10 llc 0x088a8ec5 llvm::MachineInstr::MachineInstr(llvm::MCInstrDesc const&, llvm::DebugLoc, bool) + 245
11 llc 0x08899daf llvm::MachineFunction::CreateMachineInstr(llvm::MCInstrDesc const&, llvm::DebugLoc, bool) + 111
12 llc 0x0871b4a0 llvm::InstrEmitter::EmitMachineNode(llvm::SDNode*, bool, bool, llvm::DenseMap<llvm::SDValue, unsigned int, llvm::DenseMapInfollvm::SDValue >&) + 512
13 llc 0x0866dfbd llvm::ScheduleDAGSDNodes::EmitSchedule(llvm::MachineBasicBlock::bundle_iterator<llvm::MachineInstr, llvm::ilist_iteratorllvm::MachineInstr >&) + 1325
14 llc 0x086ea97f llvm::SelectionDAGISel::CodeGenAndEmitDAG() + 1439
15 llc 0x086ecdf6 llvm::SelectionDAGISel::SelectBasicBlock(llvm::ilist_iterator<llvm::Instruction const>, llvm::ilist_iterator<llvm::Instruction const>, bool&) + 198
16 llc 0x086f3cf0 llvm::SelectionDAGISel::SelectAllBasicBlocks(llvm::Function const&) + 2176
17 llc 0x086f5850 llvm::SelectionDAGISel::runOnMachineFunction(llvm::MachineFunction&) + 1392
18 llc 0x088a0aca llvm::MachineFunctionPass::runOnFunction(llvm::Function&) + 186
19 llc 0x08c42fa3 llvm::FPPassManager::runOnFunction(llvm::Function&) + 659
20 llc 0x08c4302c llvm::FPPassManager::runOnModule(llvm::Module&) + 76
21 llc 0x08c42c60 llvm::MPPassManager::runOnModule(llvm::Module&) + 592
22 llc 0x08c46528 llvm::PassManagerImpl::run(llvm::Module&) + 168
23 llc 0x08c46636 llvm::PassManager::run(llvm::Module&) + 38
24 llc 0x0818513a main + 4026
25 libc.so.6 0xb74546b3 __libc_start_main + 243
26 llc 0x08195e8d
Stack dump:
0. Program arguments: /home/MathOnNapkins/Documents/Programming/llvm-3.2/Release+Asserts/bin/llc -march=x65 -debug -filetype=asm ./test.ll

  1. Running pass ‘Function Pass Manager’ on module ‘./test.ll’.
  2. Running pass ‘x65 DAG->DAG Pattern Instruction Selection’ on function ‘@foo_and32

For reference, I see this with both llvm 3.1 and 3.2. I have not tried the svn trunk, though.

The test *.ll file contains a number of small test routines, and I’ll include it in the body as well:

define i32 @foo_add32(i32 %alpha) nounwind
{
%result = add nsw i32 %alpha, 262145

ret i32 %result
}

define i32 @foo_sub32(i32 %alpha) nounwind
{
%result = sub i32 %alpha, 262147

ret i32 %result
}

define i32 @test_or32(i32 %alpha) nounwind
{
%result = or i32 %alpha, 262148

ret i32 %result
}

define i32 @foo_xor32(i32 %alpha) nounwind
{

%result = xor i32 %alpha, 262149

ret i32 %result
}

define i32 @foo_and32(i32 %alpha) nounwind
{

%result = and i32 %alpha, 262150

ret i32 %result
}

; Testing commutivity of add operation.
define i32 @foo_reverse_add32(i32 %alpha) nounwind
{
%result = add nsw i32 262151, %alpha

ret i32 %result
}

Previously, I had been testing with only one routine per test .ll file, but I thought I’d reached a point where I could test multiple operations at once and understand the output. The odd part about this is that the likelihood of seeing the above assertion scales with the number of functions in the .ll file. If I have one or two functions, I never see it. With three, I see it sporadically. With four or five, I see it about 80% of the time. I don’t understand why it would only assert some of the time, as the inputs are not changing. Could it be a problem with my system itself, or perhaps I’m running low on RAM? If anybody has any insight on how to troubleshoot this kind of problem, i’d be very grateful.

Also, I have not overriden runOnMachineFunction() in my XXXISelDagToDag.cpp file, so this is happening somewhat out of my control. Should I attempt to override it? I noticed that only a couple targets actually override runOnMachineFunction() for that particular pass (MIPS, I think is one).

Sincerely,

~MathOnNapkins / Dave

Hi David,

> Previously, I had been testing with only one routine per test .ll file, but I

thought I'd reached a point where I could test multiple operations at once and
understand the output. The odd part about this is that the likelihood of seeing
the above assertion scales with the number of functions in the .ll file. If I
have one or two functions, I never see it. With three, I see it sporadically.
With four or five, I see it about 80% of the time. I don't understand why it
would only assert some of the time, as the inputs are not changing.

memory corruption or uninitialized variable maybe? Try running under valgrind.

Ciao, Duncan.

  Could it be

Thanks for the suggestion, Duncan.

I recently figured out that it had to do with how I was removing the pseudo instruction in my overridden expandPostRAPseudo() implementation.

// member function’s signature

bool TheInstrInfo::expandPostRAPseudo(MachineBasicBlock::iterator p_mi)

// works

bb.erase(p_mi);

// produces the assertion / memory leak.
p_mi->removeFromParent();

I should have looked more closely at the targets that implemented expandPostRAPseudo() and saw how they got rid of the pseudo instruction. In particular, the successful line was lifted from bool Mips16InstrInfo::expandPostRAPseudo(…). Some targets don’t eliminate the pseudo, but rather reconfigure it to be native.

In any case, I don’t quite understand why these two seemingly (to me) equivalent lines of code cause different behavior at run time. For reference, each of my pseudo instructions expands to 2 or more native instructions. p_mi->removeFromParent() seems to be used in other targets ( but not expandPostRAPseudo() ) without issue… shrug.

Sincerely,

~ MathOnNapkins / David

removeFromParent just unlinks it from the basic block and returns the removed instruction. It does not delete it.

HI Craig,

That makes perfect sense then. headdesk. Assumptions are very bad. Still… I wonder why it was asserting only some of the time, though.

Sincerely,

~ MathOnNapkins / David