Skip to content

quot with a power of two is not optimized to a shift

The follow code:

module Test where

f :: Int -> Int
f n = n `quot` 2

results in the following core:

Test.f :: GHC.Types.Int -> GHC.Types.Int
Test.f =
  \ (n_aeH :: GHC.Types.Int) ->
    case n_aeH of _ { GHC.Types.I# ww_aiQ ->
    GHC.Types.I# (GHC.Prim.quotInt# ww_aiQ 2)
    }

which in turn generates this Cmm

sjI_ret()
        { Just sjI_info:
                   const 0;
                   const 32;
        }
    cjX:
        Hp = Hp + 16;
        if (Hp > I64[BaseReg + 144]) goto ck3;
        _sjH::I64 = %MO_S_Quot_W64(I64[R1 + 7], 2);
        I64[Hp - 8] = PicBaseReg + GHC.Types.I#_con_info;
        I64[Hp + 0] = _sjH::I64;
        R1 = Hp - 7;
        Sp = Sp + 8;
        jump (I64[Sp + 0]); // [R1]
    ck1: jump (I64[BaseReg - 16]); // [R1]
    ck3:
        I64[BaseReg + 192] = 16;
        goto ck1;
}

which finally ends up as this assembly:

sjI_info:
_cjX:
	addq $16,%r12
	cmpq 144(%r13),%r12
	ja _ck3
	movl $2,%ecx
	movq 7(%rbx),%rax
	cqto
	idivq %rcx
	movq %rax,%rbx
	leaq GHC.Types.I#_con_info(%rip),%rax
	movq %rax,-8(%r12)
	movq %rbx,0(%r12)
	leaq -7(%r12),%rbx
	addq $8,%rbp
	jmp *0(%rbp)

Ideally this should have turned into a shift, not a division. compiler/nativeGen/X86/CodeGen.hs lacks any peephole optimizations for division.

Trac metadata
Trac field Value
Version 7.8.2
Type Bug
TypeOfFailure OtherFailure
Priority normal
Resolution Unresolved
Component Compiler
Test case
Differential revisions
BlockedBy
Related
Blocking
CC
Operating system
Architecture
To upload designs, you'll need to enable LFS and have an admin enable hashed storage. More information