Missing code depending on a #ifdef within the .ll file

Hi all,
I have managed to compile libpng using wllvm and obtain the IR of pngpixel ( small tool which is part of libpng ).

libpng has a function called png_check_IHDR:

void /* PRIVATE */
png_check_IHDR(png_const_structrp png_ptr,
png_uint_32 width, png_uint_32 height, int bit_depth,
int color_type, int interlace_type, int compression_type,
int filter_type)
{
int error = 0;

/* Check for width and height valid values */
if (width == 0)
{
png_warning(png_ptr, “Image width is zero in IHDR”);
error = 1;
}
else if (width > PNG_UINT_31_MAX)
{
png_warning(png_ptr, “Invalid image width in IHDR”);
error = 1;
}
else
{
# ifdef PNG_SET_USER_LIMITS_SUPPORTED
if (width > png_ptr->user_width_max)
# else
if (width > PNG_USER_WIDTH_MAX)
# endif
{
png_warning(png_ptr, “Image width exceeds user limit in IHDR”);
error = 1;
}
}

}

Unfortunately the relative IR does not seem to have the branch highlighted in bold:

; Function Attrs: nounwind uwtable
define void @png_check_IHDR(%struct.png_struct_def* noalias %png_ptr, i32 %width, i32 %height, i32 %bit_depth, i32 %color_type, i32 %interlace_type, i32 %compression_type, i32 %filter_type) #5 {
%1 = icmp eq i32 %width, 0
br i1 %1, label %.thread, label %2

.thread: ; preds = %0
tail call void @png_warning(%struct.png_struct_def* %png_ptr, i8* getelementptr inbounds ([28 x i8], [28 x i8]* @.str50, i64 0, i64 0)) #15
br label %5

; :2: ; preds = %0
%3 = icmp slt i32 %width, 0
br i1 %3, label %4, label %5

; :4: ; preds = %2
tail call void @png_warning(%struct.png_struct_def* %png_ptr, i8* getelementptr inbounds ([28 x i8], [28 x i8]* @.str51, i64 0, i64 0)) #15
br label %5

; :5: ; preds = %4, %2, %.thread
%error.1 = phi i32 [ 1, %4 ], [ 0, %2 ], [ 1, %.thread ]
%6 = getelementptr inbounds %struct.png_struct_def, %struct.png_struct_def* %png_ptr, i64 0, i32 132
%7 = load i32, i32* %6, align 4, !tbaa !22
%8 = icmp ult i32 %7, %width ; if (width > PNG_UINT_31_MAX)
br i1 %8, label %9, label %10

; :9: ; preds = %5
tail call void @png_warning(%struct.png_struct_def* %png_ptr, i8* getelementptr inbounds ([39 x i8], [39 x i8]* @.str53, i64 0, i64 0)) #15
br label %10

; :10: ; preds = %9, %5
%error.3 = phi i32 [ 1, %9 ], [ %error.1, %5 ]
%11 = icmp eq i32 %height, 0 ; first check on the height
br i1 %11, label %.thread27, label %12

Does anybody know why the else branch is completely missing?

Thanks,
Alberto

Not sure I understand the question - but usually a compiler would, on one compilation, only compile one versoin of the code with one set of defines.

There could be invalid code (it could literally be junk - or it could be code that’s only valid when the define is true/false, etc) in an unreachable ifdef, so it doesn’t make sense to compile it.

Hi David,
My question is: why both #ifdef and #else branches are missing? I think at least one of the two should be present… In fact there is a case where the width could be greater then
PNG_USER_WIDTH_MAX but not greater then PNG_UINT_31_MAX. That’s why I was expecting at least one of the two…

Thanks
Alberto

I’m sorry, I don’t understand the question - the source code shows 3 calls to png_warning (one of them from the if block you’re interested in), and the IR shows 3 calls to png_warning - so it looks like the body of the if block is included in the IR you’ve shown?

if (width == 0)

became

%1 = icmp eq i32 %width, 0

which is straightforward; and

else if (width > PNG_UINT_31_MAX)

became (assuming the constant is 0x7fffffff)

%3 icmp slt i32 %width, 0

(note this is a signed comparison with 0, which is equivalent to the comparison in the source)

and finally

if (width > png_ptr->user_width_max)

became

%8 = icmp ult i32 %7, %width

after loading the png_ptr field into %7 in the previous instruction.

Does that help?

–paulr

Hi Paul and David,
yes I have just realised that the third check was the one I was looking for… For some reason I was only looking for PNG_USER_WIDTH_MAX.

Now it is all clear :slight_smile:

Thanks again
Alberto