Clang seems to assume that the addresses of extern global variables are non-zero. However, I cannot find this assumption documented in the LLVM language reference nor does llc seem to optimize based on this assumption.
Is this optimization just happening in the clang frontend or is it baked into LLVM? (I am generating LLVM-IR and have a niche use case where I require an extern global null pointer).
To illustrate the above, consider the following code:
#include <stdio.h>
extern int x;
int main() {
int *p = &x;
if (p == 0) printf("hello");
}
Under clang-15 -O3 -emit-llvm -S test.c
the printf
is eliminated. Not so if we run clang-15 -emit-llvm -S test.c
(to get unoptimized IR which includes the printf) and then llc-15 -O3 test.ll
to compile the rest of the way to assembly. For the sake of completeness, I’ll include the following, which is the intermediate code on my system seen by llc:
; ModuleID = 'test.c'
source_filename = "test.c"
target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
target triple = "x86_64-pc-linux-gnu"
@x = external global i32, align 4
@.str = private unnamed_addr constant [6 x i8] c"hello\00", align 1
; Function Attrs: noinline nounwind optnone uwtable
define dso_local i32 @main() #0 {
%1 = alloca i32, align 4
%2 = alloca ptr, align 8
store i32 0, ptr %1, align 4
store ptr @x, ptr %2, align 8
%3 = load ptr, ptr %2, align 8
%4 = icmp eq ptr %3, null
br i1 %4, label %5, label %7
5: ; preds = %0
%6 = call i32 (ptr, ...) @printf(ptr noundef @.str)
br label %7
7: ; preds = %5, %0
%8 = load i32, ptr %1, align 4
ret i32 %8
}
declare i32 @printf(ptr noundef, ...) #1
attributes #0 = { noinline nounwind optnone uwtable "frame-pointer"="all" "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" }
attributes #1 = { "frame-pointer"="all" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" }
!llvm.module.flags = !{!0, !1, !2, !3, !4}
!llvm.ident = !{!5}
!0 = !{i32 1, !"wchar_size", i32 4}
!1 = !{i32 7, !"PIC Level", i32 2}
!2 = !{i32 7, !"PIE Level", i32 2}
!3 = !{i32 7, !"uwtable", i32 2}
!4 = !{i32 7, !"frame-pointer", i32 2}
!5 = !{!"Ubuntu clang version 15.0.7"}