[LLVMdev] [PATCH] Teaching ScalarEvolution to handle IV=add(zext(trunc(IV)), Step)
Matthew Curtis
mcurtis at codeaurora.org
Tue Dec 18 09:56:49 PST 2012
Dan,
Thanks for the response ...
On 12/17/2012 1:53 PM, Dan Gohman wrote:
> On Mon, Dec 10, 2012 at 2:13 PM, Matthew Curtis <mcurtis at codeaurora.org> wrote:
>> Hello all,
>>
>> I wanted to get some feedback on this patch for ScalarEvolution.
>>
>> It addresses a performance problem I am seeing for simple benchmark.
>>
>> Starting with this C code:
>>
>> 01: signed char foo(void)
>> 02: {
>> 03: const int count = 8000;
>> 04: signed char result = 0;
>> 05: int j;
>> 06:
>> 07: for (j = 0; j < count; ++j) {
>> 08: result += (result_t)(3);
>> 09: }
>> 10:
>> 11: return result;
>> 12: }
> FWIW, this code is probably not doing what it was intended to do; it's
> result is implementation-defined or an implementation-defined signal is
> raised (6.3.1.3).
Yes. The code is somewhat contrived. It's a much simplified equivalent
of a benchmark. :)
>> I end up with this IR feeding into Induction Variable Simplification:
>>
>> 01: define signext i8 @foo() nounwind readnone {
>> 02: entry:
>> 03: br label %for.body
>> 04:
>> 05: for.body: ; preds = %entry,
>> %for.body
>> 06: %j.04 = phi i32 [ 0, %entry ], [ %inc, %for.body ]
>> 07: %result.03 = phi i32 [ 0, %entry ], [ %add, %for.body ]
>> 08: %conv2 = and i32 %result.03, 255
>> 09: %add = add nsw i32 %conv2, 3
>> 10: %inc = add nsw i32 %j.04, 1
>> 11: %cmp = icmp slt i32 %inc, 8000
>> 12: br i1 %cmp, label %for.body, label %for.end
>> 13:
>> 14: for.end: ; preds = %for.body
>> 15: %conv1 = trunc i32 %add to i8
>> 16: ret i8 %conv1
>> 17: }
> I'm confused about how you got this IR from that C testcase. What is
> result_t? Did you do anything special?
Sorry, result_t is signed char. I was experimenting with other result
types and mistakenly copied an intermediate version of the code.
The IR was produced with an internal build of clang for hexagon (with
-O2). The IR produced by the current clang trunk is not quite the same.
>> Unfortunately, the 'and' on line 8 prevents Scalar Evolution from
>> being able to create an expression for '%add' that it knows how to
>> evaluate.
>>
>> The patch detects this pattern in createNodeForPHI and creates an
>> equivalent expression that can be evaluated.
>>
>> Note that SCEV translates the 'and' into
>> ZeroExtend(Truncate(%result.03, i8), i32)
>>
>> So in terms of SCEV expressions, we essentially have
>> %add[n] = Add(ZeroExtend(Truncate(%add[n-1], i8), i32), 3)
>>
>> (BTW, I'm no scholar here, just a layman, so my terminology is
>> probably all wrong).
> Going with your LLVM IR testcase, this looks right so far.
>
>> The patch basically moves the ZeroExtend and Truncate outside of the
>> recurrence, though it must take into account that for iteration n, the
>> ZeroExtend and Truncate apply to the value at iteration n-1.
>>
>> For a constant step this is accomplished by subtracting one step from
>> the recurrence, performing the Truncate and ZeroExtend, and then
>> adding the step to the result. In other words:
>>
>> %add[n] = Add(
>> ZeroExtend(
>> Truncate(
>> Minus(AddRec(Start=0,Step=3)[n], 3),
>> i8),
>> i32),
>> 3)
>>
>> It's a little more complicated when the Step is another recurrence,
>> but essentially the same.
> Something is wrong here. On the first iteration, the %add value is 3.
> On the first iteration, your replacement expression's value is 256.
>
> Dan
Here's how I'm evaluating the expression (in my head):
00: Add(ZeroExtend(Truncate(Minus(AddRec(Start=0,Step=3)[n],3), i8), i32),3)
|
01: Add(ZeroExtend(Truncate(Minus(AddRec(Start=0,Step=3)[0],3), i8), i32),3)
|
02: Add(ZeroExtend(Truncate(Minus(3,3), i8), i32),3)
|
03: Add(ZeroExtend(Truncate(0, i8), i32),3)
|
04: Add(ZeroExtend(0, i32),3)
|
05: Add(0,3)
|
06: 3
Thanks again.
Matthew Curtis
--
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation
More information about the llvm-dev
mailing list