[LLVMdev] FP emulation

Roman Levenstein romixlev at yahoo.com
Tue Oct 10 17:20:49 PDT 2006

> On Tue, 10 Oct 2006, Roman Levenstein wrote:
> >>> 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
> ok.
> > 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?
> I don't understand.  If you are writing out the .o file directly, you

> already know how to encode calls... can't you just encode it as the
> right sort of call? 

Yes, sure. I simply overlooked it, because it is too simple and obvious
;) I was thinking about doing it at a higher level, but this can be
done as well.

But I think that Andrew's approach as used in the Alpha backend will do
the job and it is rather easy to implement.

> What facilities are you using to emit the machine
> code, are  you using the llvm machine code emitter generator stuff
>(like PPC)?

At the moment, I do not emit real machine code. But I'm planning to do
it. If possible, I'll try to use the code emitter stuff of tblgen. But
I'm not sure if it can handle the insntruction encodings of my target.
This target uses variable length instruction encoding, where 2 bytes
are used for opcodes and encodings of memory references and some
registers are put between these two bytes. Therefore, the bit offsets
are not constant and depend on the type of instruction (e.g. rm, ri and
so on). Do you think it would be easy to express such encoding for
> >>> 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?
> Yes, if you tell the legalizer you want to custom expand everything,
> you 
> can do this.  In practice, there may be ones the legalizer doesn't
> know 
> how to custom expand yet, b ut that is an easy addition.
> > 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?
> As others have pointed out, you flag copy{to/from}reg nodes to the
> call.

OK. Andrew has explained how to do it. I'll give it a try.
> > 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?
> You should be able to handle this in the lowering stuff, you don't
> need anything complex here.

OK, I see. But I'd like to know how to introduce a new calling
convention so that it is visible at the source level. Basically, there
are some drivers existing for this system and I'd like to be able to
call some functions defined there. But these drivers are using very
custom calling convention. I thought that declaring functions like
follows could be the most appropriate solution:

extern __MySpecialDriverAttribute int read_from_device(int devid, int

But for doing this I need to define a custom attribute or a new calling
convention. Or do you see any other opportunity?
> >> 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]?
> Depending on how you defined the aliases, they aren't necessarily 
> transitive.  I'd like at the <yourtarget>GenRegisterInfo.inc file,
> and see 
> what it lists as the aliases for each reg.

Done. And I looked into the tblgen code. Tarnsitivity is not ensured by
tblgen in any form, since it does not compute it. What it ensures is
the commutativity of aliases, i.e. if A aliases B, then B aliases A. I
think it would make sense if tblgen would compute a transitive closure
automatically for alias sets, because I can hardly imagine
non-transitive aliasing semantics. If you think that this makes sense,
I could probably write a patch for tblgen to do that.
> > 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?
> The right way would be to expose the fact that these really are
> integer  registers, and just use integer registers for it.  

How and where can this fact be exposed? In register set descriptions?
Or may be telling to use i32 register class when we assign the register
class to f64 values?

> This 
> would be no problem except that the legalizer doesn't know how to
> convert f64 -> 2 x  i32 registers.  This could be added, 

Can you elaborate a bit more about how this can be added? Do you mean
that legalizer would always create two new virtual i32 registers for
each such f64 value, copy the parts of f64 into it and let the register
allocator later allocate some physical registers for it? 
Would it require adaptations only in the target-specific legalizer or
do you think that some changes in the common part (in Target directory)
of the legalizer are required?

> but a
> simpler approach to get you running faster is to add the bogus
> register set.

True. To get something that works as soon as possible, this is simpler.
But to produce a faster code, a more complex approach described above
could be a (big?) win.

- Roman

Do You Yahoo!?
Tired of spam?  Yahoo! Mail has the best spam protection around 

More information about the llvm-dev mailing list