[LLVMdev] FP emulation
Roman Levenstein
romixlev at yahoo.com
Tue Oct 10 01:30:53 PDT 2006
Hi,
>> My target supports only f64 at the moment.
>> Question: How can I tell LLVM that float is the same as double on my
>> target? May be by assigning the same register class to both MVT::f32
?> and MVT::f64?
>Just don't assign a register class for the f32 type. This is what the
>X86 backend does when it is in "floating point stack mode". This will
>implicitly promote everything to f64.
OK. This is even easier than I expected :)
> > 1. Since these FP emulation functions takes operands on registers
> and
> > produce operands on registers without any further side-effects,
> they
> > look pretty much like real instructions. Thus I have the idea to
> > represent them in the tblgen instruction descriptions like
> > pseudo-instructions, where constraints define which concrete
> physical
> > %dX registers are to use. This would enfore correct register
> > allocation.
> >
> > For example:
> > def FSUB64: I<0x11, (ops), "fsub64", [(set d0, (fsub d0, d1))]>,
> > Imp<[d0,d1],[d0,d1]>; // Uses d0, d1 and defines d0,d1
> >
> > This seems to work, at least on simple test files.
>
> That should be a robust solution.
>
> > But I would also need a way to convert such a FSUB64
> pseudo-instruction
> > into the assembler function call, e.g. "call __fsub64". At the
> moment I
> > don't quite understand at which stage and how I should do it
> (lowering,
> > selection, combining??? ). What would be the easiest way to map it
> to
> > such a call instruction?
>
> Why not just make the asm string be "call __fsub64"?
Well, of course it would be the best solution. But the interesting part
is that I need to generate the machine code directly because for
different reasons use of a system assembler is not an option. As a
result, I need to do this conversion in the target backend and later
generate object code directly. But when and how this conversion "fsub64
insn -> call __fsub64" insn should be done? What is your advice?
> > One issue with the described approach is a pretty inefficient code
> > resulting after the register allocation. For example, there are a
> lot
> > of instructions of the form "mov %d0, %d0", copying the register
> into
> > itself. My guess is that the following happens:
> Make sure to implement TargetInstrInfo::isMoveInstr. This will allow
> the coallescer to eliminate these.
Very good point. Now I see how to improve this part.
> > Does this idea of representing the emulated FP operation calls as
> > instructions as described above make some sense? Or do you see
> easier
> > or more useful ways to do it?
>
> That is a reasonable way to do it. Another reasonable way would be
> to lower them in the instruction selector itself though the use of
> custom expanders. In practice, using instructions with "call foo"
in > them instead of lowering to calls may be simpler.
Hmm, let me see. Just to check that I understand your proposal
correctly:
You mean I don't need to define any FP operations as machine
instructions at all. Instead, I basically tell that I will expand all
FP operations myself and then I simply expand them into the following
sequence of instructions:
mov arg1, %d0 // enfore register constraint
mov arg2, %d1 // enfore register constraint
call __fsub64
Is it correct understanding? If yes, how do I explain that arguments
are to be passed on the concrete physical registers like %d0 and %d1
and result comes on %d0? Do I need to allocate virtual regs for them
and pre-assign physical regs somehow?
Or my be I have to define a new calling convention that would enforce
it?
Actually, how can this be done with LLVM? I mean, if I want to
introduce a new calling convention, what do I need to do in backend to
define and register it? Is it required to change the frontend to make
it visible at the source program level?
>Also, if you *know*
> that these calls don't clobber the normal set of callee clobbered
> registers, using the asm string is the right way to go.
> > 2. In reality, the processor has only 32bit regs. Therefore, any
>> f64 value should be mapped to two 32bit registers. What is the best
>> way to achieve it? I guess this is a well-known kind of problem.
> Ah, this is trickier. :) We have a robust solution in the integer
> side, but don't allow the FP side to use it.
>
> For the time being, I'd suggest defining an "fp register set" which
> just aliases the integer register set (i.e. say that d0 overlaps
> r0+r1).
OK. I almost did this way already. But I introduced two FP register
sets. One for fp32 (for the future) and one for fp64. fp32 aliases the
integer register set. fp64 aliases the fp32 register set, but not the
integer register set explicitly. I thought that aliases are transitive?
Or do I have to mention all aliases explicitly, e.g. for %d0 I need to
say [%s0,%s1,%GR0,%GR1]?
But a more interesting question is this:
The scheme above assumes that there is a "hardwired" mapping between FP
registers and concerete pairs of integer registers. In many cases this
is enough, since the emulated operations indeed expect parameters on
predefined pairs of 32bit integer registers. But when it comes to other
uses of FP registers (mainly for storing some values) there is no this
limitation that a concrete pair of integer registers should be used.
Actually, any combination of two 32bit integer registers would do. How
this can be modelled and represented to regalloc, if at all? One guess
it to define one FP reg for each possible combination of two integer
registers, which would lead to definition N*(N-1) FP registers, where N
is the number of integer registers (And I have only 8 integer regs).
But it seems to be not very elegant for my taste,or?
> > So far I was thinking about introducing some pseudo f64 registers,
> i.e.
> > %dX used above, and working with them in the instruction
> descriptions.
> > And then at the later stages, probably after lowering and
> selection,
> > expand them into pairs of load or store operations.
>
> If you tell the register allocator about the "aliases", it should do
> the right thing for you. Take a look at how aliasing in the X86
> register set is handled in X86RegisterInfo.td.
Can you elaborate a bit? Does it mean that I don't need to define fp64
loads from memory or fp64 stores to memory and reg<-reg tranfers for
64bit ops, because all that will be done automatically using pairs of
32bit instructions? So far, I had the impression I need to use fp64
regs in the instruction descriptions explicitly. But in this case
generated selected instructions operation on these 64bit regs and there
is a problem how to expand them into pairs of 32bit instructions.
-Roman
__________________________________________________
Do You Yahoo!?
Tired of spam? Yahoo! Mail has the best spam protection around
http://mail.yahoo.com
More information about the llvm-dev
mailing list