Improve cmm/assembly for pattern matches with two constants.
For a pattern like:
f_test :: Int#->Int#
f_test a = case a of
1# -> 33#
7# -> 34#
_ -> -1#
GHC currently generates code that works best if the default branch is taken most often.
Pseudo-Code
if (a >= 8)
return -1;
else {
if (a < 7) {
if(a != 1)
return -1;
else
return 33;
}
else
return 34;
}
CMM:
c1cr: // global
if (%MO_S_Ge_W64(R2, 8)) goto c1co; else goto u1cu;
u1cu: // global
if (%MO_S_Lt_W64(R2, 7)) goto u1cv; else goto c1cq;
u1cv: // global
if (R2 != 1) goto c1co; else goto c1cp;
c1co: // global
R1 = (-1);
call (P64[Sp])(R1) args: 8, res: 0, upd: 8;
c1cp: // global
R1 = 33;
call (P64[Sp])(R1) args: 8, res: 0, upd: 8;
c1cq: // global
R1 = 34;
call (P64[Sp])(R1) args: 8, res: 0, upd: 8;
}
Wouldn't the following be better?
if(a == 1)
return 33
else if(a == 7)
return 34
else
return -1
I would expect that to
-
Improve the cases:
* a = 1
* a < 7
-
Be the same for:
* a = 7
-
Be worse for
* a > 8
This would be especially nice for the cases where the default branch is raising a pattern match exception. Which is a code path I wouldn't expect to be taken often nor be very performance sensitive.
Even if we keep the current logic there is room for improvement. GHC currently creates the following assembly:
_c1cr:
cmpq $8,%r14
jge _c1co
_u1cu:
cmpq $7,%r14
jl _u1cv
_c1cq:
movl $34,%ebx
jmp *(%rbp)
_u1cv:
cmpq $1,%r14
jne _c1co
_c1cp:
movl $33,%ebx
jmp *(%rbp)
_c1co:
movq $-1,%rbx
jmp *(%rbp)
It would be nice if we could remove one comparison at least.
_c1cr:
cmpq $7,%r14
jg _c1co
_u1cu:
;No longer neccesary cmpq $7,%r14
jl _u1cv
_c1cq:
movl $34,%ebx
jmp *(%rbp)
_u1cv:
cmpq $1,%r14
jne _c1co
_c1cp:
movl $33,%ebx
jmp *(%rbp)
_c1co:
movq $-1,%rbx
jmp *(%rbp)
Trac metadata
Trac field | Value |
---|---|
Version | 8.2.2 |
Type | Task |
TypeOfFailure | OtherFailure |
Priority | normal |
Resolution | Unresolved |
Component | Compiler (CodeGen) |
Test case | |
Differential revisions | |
BlockedBy | |
Related | |
Blocking | |
CC | |
Operating system | |
Architecture |