LLVM tries to remove labels used in blockaddress()

Hi,

i ran into a problem when using blockaddress() with a label in another function. It seems to me that LLVM tries to remove the label used in blockaddress because it seems like it is not used, but in fact it may be used somewhere with a indirectbr.

I attached a small test-case that produces this error. (The original problem is much more complicated, so i hope the reduced example, which has no indirectbr but produces an error nevertheless, will suffice.)

I compile the code with:
# llvm-as -o main.bc main.ll
# llc -o main.s main.bc

and get:
# While deleting: label %test_label
# An asserting value handle still pointed to this value!
# UNREACHABLE executed at Value.cpp:522!
# 0 llc 0x0000000000c67cdf
# 1 llc 0x0000000000c684fd
# 2 libpthread.so.0 0x00002b24f70db0f0
# 3 libc.so.6 0x00002b24f7ed2435 gsignal + 53
# 4 libc.so.6 0x00002b24f7ed3c40 abort + 384
# 5 llc 0x0000000000c488f4 llvm::llvm_unreachable_internal(char const*, char const*, unsigned int) + 356
# 6 llc 0x0000000000c0eb49 llvm::ValueHandleBase::ValueIsDeleted(llvm::Value*) + 1721
# 7 llc 0x0000000000c0f9cd llvm::Value::~Value() + 749
# 8 llc 0x0000000000b870a5 llvm::BasicBlock::~BasicBlock() + 421
# 9 llc 0x0000000000a2eaaf
# 10 llc 0x0000000000bfb0a6 llvm::FPPassManager::runOnFunction(llvm::Function&) + 534
# 11 llc 0x0000000000bfb281 llvm::FunctionPassManagerImpl::run(llvm::Function&) + 129
# 12 llc 0x0000000000bfb4ae llvm::FunctionPassManager::run(llvm::Function&) + 110
# 13 llc 0x000000000052cf24 main + 3556
# 14 libc.so.6 0x00002b24f7ebda3d __libc_start_main + 253
# 15 llc 0x000000000052ac29
# Stack dump:
# 0. Program arguments: llc -o main.s -f main.bc
# 1. Running pass 'Remove unreachable blocks from the CFG' on function '@test_fun'

I'm using the current svn version (revision 98542). An earlier revision simply generated asm-code, where the appropriate label was missing, thus causing gcc to fail when i wanted to compile the asm-file.

Regards,
Sebastian

main.ll (277 Bytes)

Hi,

i ran into a problem when using blockaddress() with a label in another function. It seems to me that LLVM tries to remove the label used in blockaddress because it seems like it is not used, but in fact it may be used somewhere with a indirectbr.

I attached a small test-case that produces this error. (The original problem is much more complicated, so i hope the reduced example, which has no indirectbr but produces an error nevertheless, will suffice.)

This is because of new checking code I added, specifically to catch bugs like:

An earlier revision simply generated asm-code, where the appropriate label was missing, thus causing gcc to fail when i wanted to compile the asm-file.

Here is a slightly reduced testcase:

define i8* @test1() nounwind {
entry:
  ret i8* blockaddress(@test_fun, %test_label)
}

define i32 @test_fun() nounwind {
entry:
  ret i32 -1
test_label:
  br label %ret
ret:
  ret i32 -1
}

The basic problem is that we codegen test1, which generates a reference to test_label, then we codegen test_func. The optimization passes that run before the code generator (UnreachableBlockElim & CodeGenPrepare) zap dead blocks, so test_label was being deleted.

The code generator doesn't want dead blocks coming into it for various reasons, so removing them is important. I guess we'll have to do something like buffer up the unemitted labels and emit them at the end of the file (in a meaningless location). This should provide correct code, but is somewhat gross.

Bob/Dan, do you guys have any other ideas on how to handle this?

-Chris

I see. But the block does not necessarily contain dead code.

My original problem is more like this:

define i32 @main() {
entry:
  %target = bitcast i8* blockaddress(@test_fun, %test_label) to i8*

  call i32 @test_fun(i8* %target)

  ret i32 0
}

define i32 @test_fun(i8* %target) {
entry:
  indirectbr i8* %target, [label %test_label]

test_label:
; assume some code here...
  br label %ret

ret:
  ret i32 -1
}

The code after test_label can be reached, but this example produces also an error.

Regards,
Sebastian

Hi,

i ran into a problem when using blockaddress() with a label in another function. It seems to me that LLVM tries to remove the label used in blockaddress because it seems like it is not used, but in fact it may be used somewhere with a indirectbr.

I attached a small test-case that produces this error. (The original problem is much more complicated, so i hope the reduced example, which has no indirectbr but produces an error nevertheless, will suffice.)

This is because of new checking code I added, specifically to catch bugs like:

An earlier revision simply generated asm-code, where the appropriate label was missing, thus causing gcc to fail when i wanted to compile the asm-file.

Here is a slightly reduced testcase:

define i8* @test1() nounwind {
entry:
  ret i8* blockaddress(@test_fun, %test_label)
}

define i32 @test_fun() nounwind {
entry:
  ret i32 -1
test_label:
  br label %ret
ret:
  ret i32 -1
}

The basic problem is that we codegen test1, which generates a reference to test_label, then we codegen test_func. The optimization passes that run before the code generator (UnreachableBlockElim & CodeGenPrepare) zap dead blocks, so test_label was being deleted.

I'm not sure I understand completely. We should be able to rely on the indirectbr label arguments to identify blocks that are live. You can have a blockaddress anywhere, but indirectbr is only defined within a function so there's no ordering problem if you're looking at the indirectbr.

The code generator doesn't want dead blocks coming into it for various reasons, so removing them is important. I guess we'll have to do something like buffer up the unemitted labels and emit them at the end of the file (in a meaningless location). This should provide correct code, but is somewhat gross.

Bob/Dan, do you guys have any other ideas on how to handle this?

Is the problem when you've got a blockaddress that references a dead label in a different function? If that's the case, the blockaddress value can be an undef.

An earlier revision simply generated asm-code, where the appropriate label was missing, thus causing gcc to fail when i wanted to compile the asm-file.

Here is a slightly reduced testcase:

define i8* @test1() nounwind {
entry:
  ret i8* blockaddress(@test_fun, %test_label)
}

define i32 @test_fun() nounwind {
entry:
  ret i32 -1
test_label:
  br label %ret
ret:
  ret i32 -1
}

The basic problem is that we codegen test1, which generates a reference to test_label, then we codegen test_func. The optimization passes that run before the code generator (UnreachableBlockElim & CodeGenPrepare) zap dead blocks, so test_label was being deleted.

I'm not sure I understand completely. We should be able to rely on the indirectbr label arguments to identify blocks that are live. You can have a blockaddress anywhere, but indirectbr is only defined within a function so there's no ordering problem if you're looking at the indirectbr.

The problem is that test1 is codegen'd and the reference to test_label is emitted to the .s file. By the time test_func is codegen'd, the block is deleted, so the definition isn't emitted. I'll fix this.

The code generator doesn't want dead blocks coming into it for various reasons, so removing them is important. I guess we'll have to do something like buffer up the unemitted labels and emit them at the end of the file (in a meaningless location). This should provide correct code, but is somewhat gross.

Bob/Dan, do you guys have any other ideas on how to handle this?

Is the problem when you've got a blockaddress that references a dead label in a different function? If that's the case, the blockaddress value can be an undef.

But the reference has already been emitted to the .s file. I'll take care of this by just queuing up labels and emitting them at the end of the function they correspond to.

-Chris

This is a related, but different (and more important!) issue. I think I have a solution for both problems, thanks for pointing this out.

-Chris

Oh, I get it. Yuck. I can’t think of any better solutions ATM.

I see. But the block does not necessarily contain dead code.

This case is now fixed in r98566, I will fix the 'dead block' case in a bit.

-Chris

Works like a charm! Thanks for the fast help. :slight_smile:

- Sebastian

Works like a charm! Thanks for the fast help. :slight_smile:

I committed the last bits of this in r98595, please let me know if you see any other issues with addr of block.

-Chris