<html>
<head>
<base href="http://llvm.org/bugs/" />
</head>
<body><table border="1" cellspacing="0" cellpadding="8">
<tr>
<th>Bug ID</th>
<td><a class="bz_bug_link
bz_status_NEW "
title="NEW --- - "add (i32 X, i32 -1)" in global initializer fails on x86-32 but not elsewhere"
href="http://llvm.org/bugs/show_bug.cgi?id=16565">16565</a>
</td>
</tr>
<tr>
<th>Summary</th>
<td>"add (i32 X, i32 -1)" in global initializer fails on x86-32 but not elsewhere
</td>
</tr>
<tr>
<th>Product</th>
<td>tools
</td>
</tr>
<tr>
<th>Version</th>
<td>trunk
</td>
</tr>
<tr>
<th>Hardware</th>
<td>PC
</td>
</tr>
<tr>
<th>OS</th>
<td>Linux
</td>
</tr>
<tr>
<th>Status</th>
<td>NEW
</td>
</tr>
<tr>
<th>Severity</th>
<td>normal
</td>
</tr>
<tr>
<th>Priority</th>
<td>P
</td>
</tr>
<tr>
<th>Component</th>
<td>llc
</td>
</tr>
<tr>
<th>Assignee</th>
<td>unassignedbugs@nondot.org
</td>
</tr>
<tr>
<th>Reporter</th>
<td>mseaborn@chromium.org
</td>
</tr>
<tr>
<th>CC</th>
<td>llvmbugs@cs.uiuc.edu
</td>
</tr>
<tr>
<th>Classification</th>
<td>Unclassified
</td>
</tr></table>
<p>
<div>
<pre>The following LLVM IR fails on x86-32:
$ cat negative_reloc.ll
@var = internal global i32 123, align 1
@negative_offset = internal global i32 add (i32 ptrtoint (i32* @negative_offset
to i32), i32 -1), align 4
$ build-64/Release+Asserts/bin/llc negative_reloc.ll -o tmp.o -filetype=obj
-mtriple=i686-linux-gnu
llc: /home/mseaborn/sw/llvm/lib/Target/X86/MCTargetDesc/X86AsmBackend.cpp:106:
virtual void {anonymous}::X86AsmBackend::applyFixup(const llvm::MCFixup&,
char*, unsigned int, uint64_t) const: Assertion `isIntN(Size * 8 + 1, Value) &&
"Value does not fit in the Fixup field"' failed.
It fails because it produces the following assembly:
$ build-64/Release+Asserts/bin/llc negative_reloc.ll -o -
-mtriple=i686-linux-gnu
...
negative_offset:
.long negative_offset+4294967295
...
[where 4294967295 = 0xffffffff]
The GNU assembler also complains about this assembly:
$ build-64/Release+Asserts/bin/llc negative_reloc.ll -o tmp.s
-mtriple=i686-linux-gnu
$ gcc -m32 -c tmp.s
tmp.s: Assembler messages:
tmp.s:12: Error: value of 4294967299 too large for field of 4 bytes at 4
[where 4294967299 = 0x100000003]
This happens because the assembler adds 0xffffffff to the offset of
"negative_offset" within the data section and gets an overflow.
However, the same code works fine on ARM:
$ build-64/Release+Asserts/bin/llc negative_reloc.ll -o tmp.o -filetype=obj
-mtriple=arm-linux-gnu
When the pointer is changed to be i64, the same code also works fine on x86-64:
$ cat negative_reloc_64.ll
@var = internal global i32 123, align 1
@negative_offset = internal global i64 add (i64 ptrtoint (i64* @negative_offset
to i64), i64 -1), align 4
$ build-64/Release+Asserts/bin/llc negative_reloc_64.ll -o tmp.o -filetype=obj
-mtriple=x86_64-linux-gnu
$ build-64/Release+Asserts/bin/llc negative_reloc_64.ll -o -
-mtriple=x86_64-linux-gnu
...
negative_offset:
.quad negative_offset-1
...
At the assembler level, the following minimal example reproduces the assertion
failure in LLVM's assembler and gives a clean error in GNU 'as':
.byte 1
negative_offset:
.long negative_offset + 0xffffffff
However, there's no equivalent check for 64-bit overflow. The following is
accepted by both LLVM and GNU 'as':
.byte 1
negative_offset:
.quad negative_offset + 0xffffffffffffffff
This overflow check is problematic because it breaks the equivalence between
"add (i32 X, i32 -1)" and "sub (i32 X, i32 1)". Whether this fails depends on
the offset of the variable within the data section.
Should we remove this overflow check? If not, the LLVM assembler should
presumably be consistent and apply the same check on ARM and for 64-bit values.
It shouldn't just be an assertion because these checks will be omitted in
release builds.
(See also: <a href="https://code.google.com/p/nativeclient/issues/detail?id=3548">https://code.google.com/p/nativeclient/issues/detail?id=3548</a>)</pre>
</div>
</p>
<hr>
<span>You are receiving this mail because:</span>
<ul>
<li>You are on the CC list for the bug.</li>
</ul>
</body>
</html>