TryToShrinkGlobalToBoolean in GlobalOpt.cpp issue

Given some code:

static int x = 100;

int main() {
x = 101;
printf(“%d\n”, x);
}

results in:

%0 = load i1
%1 = select %0, 101, 100

  1. What architecture(s) does this benefit?
  2. What’s the best way to circumvent this in the backend (currently I am just not allowing this opt function to run)? I have tried a few setOperationAction methods to no result. Rather not just comment out core code because it makes porting more difficult.

-Ryan

Probably none of them.

The intent of this (very very old) optimization is to expose more value information to the mid-level optimizer, which enables secondary simplification. If this simplification doesn’t happen, then this is probably almost always a loss.

A better way to handle this is for GlobalOpt.cpp to tag the loads with the “new” range metadata: http://llvm.org/docs/LangRef.html#range-metadata

In addition to this not pessimizing code, this would allow the analysis to be more general: instead of identifying 1 or 2 constants, it could be generalized to N ranges.

-Chris

Thanks Chris.

-Ryan

If x is only touched in one function, I’d expect globlaopt to turn it into an alloca instead of leaving it global and shrinking it.
Did you oversimplify the real case where you see this for the sake of the example here?

Yes, the full test case is:

static int x = 100;
int y = whatever;

int main() {
x = -101;
y = whatever that’s not whatever above;
printf(“%d\n”, y);
printf(“%d\n”, x);
return 0;
}

You are correct, in the above test case the globalopt does not make the transformation… however, I think the original issue still stands, it really shouldn’t be doing it here either.

Yes, the full test case is:

static int x = 100;
int y = whatever;

int main() {
x = -101;
y = whatever that’s not whatever above;
printf(“%d\n”, y);
printf(“%d\n”, x);
return 0;
}

You are correct, in the above test case the globalopt does not make the transformation….

I’m more annoyed that it does not turn x into an alloca. With this code:

$ cat /tmp/test.c

static int x = 100;
int y = 2;
int main() {
x = -101;
y = 1;
printf(“%d\n”, y);
printf(“%d\n”, x);
return 0;
}
$ clang -O3 -S -emit-llvm -o - /tmp/test.c
; ModuleID = ‘/tmp/test.c’
source_filename = “/tmp/test.c”
target datalayout = “e-m:o-i64:64-f80:128-n8:16:32:64-S128”
target triple = “x86_64-apple-macosx10.12.0”

@y = global i32 2, align 4
@x = internal unnamed_addr global i1 false, align 4
@.str = private unnamed_addr constant [4 x i8] c"%d\0A\00", align 1

; Function Attrs: nounwind ssp uwtable
define i32 @main() #0 {
store i1 true, i1* @x, align 4
store i32 1, i32* @y, align 4, !tbaa !2
%1 = tail call i32 (i8*, …) @printf(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @.str, i64 0, i64 0), i32 1)
%2 = load i1, i1* @x, align 4
%3 = select i1 %2, i32 -101, i32 100
%4 = tail call i32 (i8*, …) @printf(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @.str, i64 0, i64 0), i32 %3)
ret i32 0
}

however, I think the original issue still stands, it really shouldn’t be doing it here either.

Yes.

Hi,

Printf could call main. If it did so, demotion to a local would be illegal.

You can either compile in c++ mode (which mandates that main is not recursive) or add ‘-force-attribute=main:norecurse’ to get this behaviour.

James

Hi James,