Misoptimization: `EarlyCSEPass` uses replaces `powi.f16` with `float` result
tgross35 opened this issue · 1 comments
It looks like EarlyCSEPass is transformin the following:
%_6 = alloca [48 x i8], align 8
%_3 = alloca [2 x i8], align 2
%0 = call half @llvm.powi.f16.i32(half 0xH3C00, i32 1) ; 0xH3C00 = 1.0f16
store half %0, ptr %_3, align 2
%1 = load half, ptr %_3, align 2
%_4 = fcmp oeq half %1, 0xH3C00
br i1 %_4, label %bb1, label %bb2Into this:
%_6 = alloca [48 x i8], align 8
%_3 = alloca [2 x i8], align 2
store float 1.000000e+00, ptr %_3, align 2
%0 = load half, ptr %_3, align 2
%_4 = fcmp oeq half %0, 0xH3C00
br i1 %_4, label %bb1, label %bb2And later InstCombine folds further into:
%_6 = alloca [48 x i8], align 8
%_3 = alloca [2 x i8], align 2
store float 1.000000e+00, ptr %_3, align 2
br i1 false, label %bb1, label %bb2EarlyCSE seems to be doing an incorrect transformation: the result of powi.f16(1.0, 1) should be half 1.0 (0x3c00), but it is returning float 1.0 (0x3f800000). This is incorrect and an OOB write.
This comes from the following rust code, which asserts only when optimizations are enabled:
#![feature(f16)]
#![allow(unused)]
#[inline(never)]
pub fn check_pow(a: f16) {
assert_eq!(1.0f16.powi(1), 1.0);
}
pub fn main() {
check_pow(1.0);
println!("finished");
}Link to compiler explorer: https://rust.godbolt.org/z/zsbzzxGvj
I'm not sure how to reduce to a llc example since the passes appear different. I have been testing on aarch64 since x86 has other f16 ABI bugs, but I don't think this is limited to aarch64.
Reproducer: https://godbolt.org/z/jhM834G3z
define half @test() {
%x = call half @llvm.powi.f16.i32(half 0xH3C00, i32 1)
ret half %x
}
opt: /root/llvm-project/llvm/lib/IR/Value.cpp:507: void llvm::Value::doRAUW(llvm::Value*, llvm::Value::ReplaceMetadataUses): Assertion `New->getType() == getType() && "replaceAllUses of value with new value of different type!"' failed.
PLEASE submit a bug report to https://github.com/llvm/llvm-project/issues/ and include the crash backtrace.
Stack dump:
0. Program arguments: /opt/compiler-explorer/clang-assertions-trunk/bin/opt -o /app/output.s -S -passes=early-cse <source>
1. Running pass "function(early-cse<>)" on module "<source>"
2. Running pass "early-cse<>" on function "test"
#0 0x0000000004e9b948 llvm::sys::PrintStackTrace(llvm::raw_ostream&, int) (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x4e9b948)
#1 0x0000000004e990bc SignalHandler(int) Signals.cpp:0:0
#2 0x000078ad4b442520 (/lib/x86_64-linux-gnu/libc.so.6+0x42520)
#3 0x000078ad4b4969fc pthread_kill (/lib/x86_64-linux-gnu/libc.so.6+0x969fc)
#4 0x000078ad4b442476 gsignal (/lib/x86_64-linux-gnu/libc.so.6+0x42476)
#5 0x000078ad4b4287f3 abort (/lib/x86_64-linux-gnu/libc.so.6+0x287f3)
#6 0x000078ad4b42871b (/lib/x86_64-linux-gnu/libc.so.6+0x2871b)
#7 0x000078ad4b439e96 (/lib/x86_64-linux-gnu/libc.so.6+0x39e96)
#8 0x0000000004cce094 llvm::Value::doRAUW(llvm::Value*, llvm::Value::ReplaceMetadataUses) (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x4cce094)
#9 0x0000000003ae3b58 (anonymous namespace)::EarlyCSE::processNode(llvm::DomTreeNodeBase<llvm::BasicBlock>*) EarlyCSE.cpp:0:0
#10 0x0000000003ae5a85 (anonymous namespace)::EarlyCSE::run() EarlyCSE.cpp:0:0
#11 0x0000000003ae81f8 llvm::EarlyCSEPass::run(llvm::Function&, llvm::AnalysisManager<llvm::Function>&) (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x3ae81f8)
#12 0x0000000002ac11be llvm::detail::PassModel<llvm::Function, llvm::EarlyCSEPass, llvm::AnalysisManager<llvm::Function>>::run(llvm::Function&, llvm::AnalysisManager<llvm::Function>&) (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x2ac11be)
#13 0x0000000004c9f2d8 llvm::PassManager<llvm::Function, llvm::AnalysisManager<llvm::Function>>::run(llvm::Function&, llvm::AnalysisManager<llvm::Function>&) (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x4c9f2d8)
#14 0x0000000000dc9bee llvm::detail::PassModel<llvm::Function, llvm::PassManager<llvm::Function, llvm::AnalysisManager<llvm::Function>>, llvm::AnalysisManager<llvm::Function>>::run(llvm::Function&, llvm::AnalysisManager<llvm::Function>&) (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0xdc9bee)
#15 0x0000000004c9dd46 llvm::ModuleToFunctionPassAdaptor::run(llvm::Module&, llvm::AnalysisManager<llvm::Module>&) (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x4c9dd46)
#16 0x0000000000dca1fe llvm::detail::PassModel<llvm::Module, llvm::ModuleToFunctionPassAdaptor, llvm::AnalysisManager<llvm::Module>>::run(llvm::Module&, llvm::AnalysisManager<llvm::Module>&) (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0xdca1fe)
#17 0x0000000004c9bf10 llvm::PassManager<llvm::Module, llvm::AnalysisManager<llvm::Module>>::run(llvm::Module&, llvm::AnalysisManager<llvm::Module>&) (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x4c9bf10)
#18 0x00000000008db1d2 llvm::runPassPipeline(llvm::StringRef, llvm::Module&, llvm::TargetMachine*, llvm::TargetLibraryInfoImpl*, llvm::ToolOutputFile*, llvm::ToolOutputFile*, llvm::ToolOutputFile*, llvm::StringRef, llvm::ArrayRef<llvm::PassPlugin>, llvm::ArrayRef<std::function<void (llvm::PassBuilder&)>>, llvm::opt_tool::OutputKind, llvm::opt_tool::VerifierKind, bool, bool, bool, bool, bool, bool, bool) (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x8db1d2)
#19 0x00000000008ce0fc optMain (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x8ce0fc)
#20 0x000078ad4b429d90 (/lib/x86_64-linux-gnu/libc.so.6+0x29d90)
#21 0x000078ad4b429e40 __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x29e40)
#22 0x00000000008c556e _start (/opt/compiler-explorer/clang-assertions-trunk/bin/opt+0x8c556e)
Program terminated with signal: SIGSEGV
Compiler returned: 139
There is a bug in constant folding.