You can sort of fake it with a pixel shader, but it requires an extra pass. I don't claim this is a great approach, BUT it will work:
Create two low-res render targets - say, 1/8th of your framebuffer size - and render each of your lights. Render to the first target, with the second bound to a sampler. In your PS, sample the second target, set a bit in the result corresponding to the light's ID, and write it to the first (gl_Color, output var or whatever). CPU side, swap the two targets and repeat for each light.
When you're done, you'll have a texture where every texel has a bit set for the lights that touch it.
This isn't nearly as flexible as using compute, especially async compute, but it'll take some pressure off of the lighting pass.