Open tarassh opened 5 years ago
if I change array to uint8_t res[4]
- works fine.
Thanks for reporting this! I can reproduce the behavior you describe and confirm it is a bug.
I'll try to investigate more deeply later this week, but I notice that inlining your u32_to_u8arr2
function causes the computation to produce the expected output:
#include <stdint.h>
struct In { int16_t flag; };
struct Out { int dummy; };
void pred16x16_128_dc(uint8_t *src, uint32_t v, int stride)
{
src[0*stride] = v & 0xFF;
src[1*stride] = (v >> 8) & 0xFF;
src[2*stride] = (v >> 16) & 0xFF;
src[3*stride] = (v >> 24) & 0xFF;
src[4 + 0*stride] = v & 0xFF;
src[4 + 1*stride] = (v >> 8) & 0xFF;
src[4 + 2*stride] = (v >> 16) & 0xFF;
src[4 + 3*stride] = (v >> 24) & 0xFF;
}
void print_luma(uint8_t *luma) {
printf("%Zx %Zx %Zx %Zx", luma[0], luma[1], luma[2], luma[3]);
printf("%Zx %Zx %Zx %Zx", luma[4], luma[5], luma[6], luma[7]);
}
void compute(struct In *input, struct Out *output){
int prediction_mode = input->flag;
uint8_t res[8];
int scalar = 0;
if (prediction_mode == 1) {
pred16x16_128_dc(res, 0x10101010, 1);
scalar = 0x10101010;
}
if (prediction_mode == 2) {
pred16x16_128_dc(res, 0x20202020, 1);
scalar = 0x20202020;
}
printf("Mode %Zd", prediction_mode);
printf("Scalar %Zx", scalar);
print_luma(res);
}
This points to the bug being somewhere in the frontend of the compiler, possibly related to some known bugs when passing arrays to function parameters. (#52 documents a bug when passing arrays of structs). So, it's possible that the C compiler is also not handling passing arrays as function pointers properly.
@maxhowald thanks for the response. This code is small snippet of a bigger algorithm which has dozens of branches. Yes I see that inlining u32_to_u8arr2
fixes the problem. Would be nice at least to understand how to write the code to avoid unpredictable behavior.
Update: after a bit more experimenting, I notice that changing the line:
u32_to_u8arr2(res+0, dcsplat, stride);
to
u32_to_u8arr2(res, dcsplat, stride);
in your example code causes the output to behave as expected.
So we have a more minimal test case:
#include <stdint.h>
struct In { int16_t flag; };
struct Out { int dummy; };
void set_val(uint8_t *arr, uint8_t val, int idx) {
arr[idx] = val;
}
void set_val_indirect(uint8_t *arr, uint8_t val, int idx) {
set_val(arr + 0, val, idx);
}
void compute(struct In *input, struct Out *output){
int mode = input->flag;
uint8_t res[8];
if (mode == 1) {
set_val_indirect(res, 0x10, 0);
}
if (mode == 2) {
set_val_indirect(res, 0x20, 0);
}
// res[0] should be 0x10 or 0x20 depending on the input
printf("%Zx %Zx %Zx %Zx", res[0], res[1], res[2], res[3]);
}
Changing arr + 0
to arr
or arr + 1
causes the output of the printf statement to be as expected.
For some reason, the arr + 0 access is being miscompiled, but only in nested / conditional function calls.
I think this points to a bug somewhere in the frontend C compiler, possibly here or here.
I'll try to investigate this a bit more soon, but perhaps you can use the above as a workaround in the meantime.
test_multiple_if.c
input.txt
prints out:
should print
if you comment out
you will get expected result. Same thing with input value
2
Problem: We have incorrect behavior if the code has more than one if statement which operates with array types. Same thing if we replace it with
if else if
constructionAs you can see, scalar types are ok.