Why isn’t GNAT (v14 and older, checked on godbolt) able to constant fold the following loop, given that all the necessary information is known up front?
function Foo return Integer is
Accm : Integer := 0;
begin
for X in 1..100 loop
Accm := @ + X*2;
end loop;
return Accm;
end Foo;
-O{1,2,3,s}
all produces similar code and don’t eliminate the overflow checking like one would expect:
_ada_foo:
mov edx, 2 # ivtmp.9,
xor eax, eax # <retval>
.L5:
add eax, edx # tmp104, ivtmp.9
jno .L7 #,
push rax #
mov esi, 5 #,
mov edi, OFFSET FLAT:.LC0 #,
call __gnat_rcheck_CE_Overflow_Check #
.L7:
add edx, 2 # ivtmp.9,
cmp edx, 202 # ivtmp.9,
jne .L5 #,
ret
Reduction expressions like [for X in 1..100 => X*2]'Reduce("+", 0)
seem to be lowered to the above as well, no constant folding either.
Am I missing a simple compiler switch apart from pragma Suppress (Overflow_Check)
and -gnatp
that forces GNAT to not give up quite so easily? I don’t want to annotate every simple use case when the compiler should be able to detect these automatically at compile-time similar to the two example languages below.
Rust:
fn foo() -> i32 {
let mut accm : i32 = 0;
for x in 1..=100 {
accm += x*2;
}
accm
}
fn foo() -> i32 {
(1..=100).map(|x| x*2).sum()
}
D:
int foo() {
int accm = 0;
foreach (x; 1..101)
accm += x*2;
return accm;
}
int foo() => iota(1, 101).map!"a*2".sum;
Backed by GCC or LLVM, these compile down to mov eax, 10100
despite enabled overflow checking, no special flags apart from -O[s]
needed.