#5173: Implement forward substitution of constants in the Cmm mini-inliner
---------------------------------+------------------------------------------
Reporter: tibbe | Owner:
Type: bug | Status: patch
Priority: normal | Component: Compiler
Version: 7.0.3 | Keywords:
Testcase: | Blockedby:
Os: Unknown/Multiple | Blocking:
Architecture: Unknown/Multiple | Failure: None/Unknown
---------------------------------+------------------------------------------
Comment(by tibbe):
For completeness, here's some real code that benefits from this
optimization:
{{{
stH_ret()
{ update_frame: <none>
has static closure: False type: 0
desc: 0
tag: 32
stack: [Just _ssK::I64]
srt: _no_srt_
}
cv1:
_cv5::I64 = I64[R1 + 7];
_cv7::I64 = 1;
_cv9::I64 = I64[Sp + 8];
_cvb::I64 = 1;
_cvd::I64 = 8;
_cvf::I64 = _cvd::I64 * 8;
_cvh::I64 = (_cv5::I64 + 24) + (_cv7::I64 << 3);
_cvj::I64 = (_cv9::I64 + 24) + (_cvb::I64 << 3);
foreign "ccall"
MO_Memcpy((_cvj::I64, PtrHint), (_cvh::I64, PtrHint),
(_cvf::I64,),
(8,))[_unsafe_call_];
I64[_cv9::I64] = stg_MUT_ARR_PTRS_DIRTY_info;
_cvl::I64 = (_cv9::I64 + 24) + (I64[_cv9::I64 + 8] << 3);
_cvn::I64 = _cvb::I64 >> 7;
foreign "ccall"
MO_Memset((_cvl::I64 + _cvn::I64, PtrHint), (1,),
((_cvb::I64 + _cvd::I64 >> 7) - _cvn::I64 + 1,),
(8,))[_unsafe_call_];
R1 = ghczmprim_GHCziUnit_Z0T_closure+1;
Sp = Sp + 16;
jump (I64[Sp + 0]) ();
}
}}}
(`MO_Memcpy` and `MO_Memset` are `CallishMachOp`s that I'm currently
adding. These `MachOp`s will generate unrolled loops in the backend, if
the number of iterations is statically known.)
Note how `_cvb` and `_cvd` are both constant and used more than once.
Here's the optimized version, without forward substitution of constants:
{{{
stH_ret()
{ [const 1;, const 32;]
}
cv1:
_cv9::I64 = I64[Sp + 8];
_cvb::I64 = 1;
_cvd::I64 = 8;
_cvh::I64 = I64[R1 + 7] + 32;
foreign "ccall"
MO_Memcpy(((_cv9::I64 + 24) + (_cvb::I64 << 3), PtrHint),
(_cvh::I64, PtrHint), (_cvd::I64 << 3,),
(8,))[_unsafe_call_];
I64[_cv9::I64] = stg_MUT_ARR_PTRS_DIRTY_info;
_cvn::I64 = _cvb::I64 >> 7;
foreign "ccall"
MO_Memset(((_cv9::I64 + 24) + ((I64[_cv9::I64 + 8] << 3) +
_cvn::I64),
PtrHint),
(1,), ((_cvb::I64 + _cvd::I64 >> 7) + (1 -
_cvn::I64),),
(8,))[_unsafe_call_];
R1 = GHC.Unit.()_closure+1;
Sp = Sp + 16;
jump (I64[Sp + 0]) ();
}
}}}
`_cv7` has been inlined, as it was used exactly once, but `_cvb` and
`_cvd` haven't.
Here's the optimized version with forward substitution of constants:
{{{
stH_ret()
{ [const 1;, const 32;]
}
cv1:
_cv9::I64 = I64[Sp + 8];
_cvh::I64 = I64[R1 + 7] + 32;
foreign "ccall"
MO_Memcpy((_cv9::I64 + 32, PtrHint), (_cvh::I64, PtrHint),
(64,),
(8,))[_unsafe_call_];
I64[_cv9::I64] = stg_MUT_ARR_PTRS_DIRTY_info;
_cvn::I64 = 0;
foreign "ccall"
MO_Memset(((_cv9::I64 + 24) + ((I64[_cv9::I64 + 8] << 3) +
_cvn::I64),
PtrHint),
(1,), (0 - _cvn::I64 + 1,), (8,))[_unsafe_call_];
R1 = GHC.Unit.()_closure+1;
Sp = Sp + 16;
jump (I64[Sp + 0]) ();
}
}}}
The code is better, but not perfect. The remaining reference to a register
with a constant value is due to the mini-inliner only inlining constants,
not expressions that could be folded into a constant.
I'll leave this as future work for now.
--
Ticket URL: <http://hackage.haskell.org/trac/ghc/ticket/5173#comment:5>
GHC <http://www.haskell.org/ghc/>
The Glasgow Haskell Compiler
_______________________________________________
Glasgow-haskell-bugs mailing list
[email protected]
http://www.haskell.org/mailman/listinfo/glasgow-haskell-bugs