Two new 'llvmnotes'

Hi all,

For anyone interested, I posted two new ideas for changes to the LLVM IR. The first is basically a cleanup, the second is a major new feature:

Eliminating the 'Void' Type:
http://nondot.org/sabre/LLVMNotes/EliminatingVoid.txt

Aggregates as First Class Values:
http://nondot.org/sabre/LLVMNotes/FirstClassAggregates.txt

Thanks to Dan Gohman for convincing me that aggregates as first class values is really possible, I think it is a great idea.

-Chris

I would certainly make use of this in my frontend.

I suggest the names "getfield" and "setfield" for the two operations, since (to me anyway) "insert" implies adding something new, as opposed to overwriting an existing value.

Chris Lattner wrote:

I would certainly make use of this in my frontend.

I suggest the names "getfield" and "setfield" for the two operations,

I agree that 'get/insertvalue' are pretty generic, and am welcome to suggestions. Get/set *field* imply that this applies only to structs, but it also works with arrays. I would actually prefer get/insert *element* but insertelement is already taken.

since (to me anyway) "insert" implies adding something new, as opposed
to overwriting an existing value.

The logic for using insert is that it replaces an element and produces the new aggregate as a whole, it doesn't update something in place (which set implies, at least to me). 'insert' is also useful because of its analogy with 'insertelement', the vector instruction.

One nice thing about get/setvalue is that they are short :slight_smile:

-Chris

Chris Lattner wrote:

I would certainly make use of this in my frontend.

I suggest the names "getfield" and "setfield" for the two operations,

I agree that 'get/insertvalue' are pretty generic, and am welcome to suggestions. Get/set *field* imply that this applies only to structs, but it also works with arrays. I would actually prefer get/insert *element* but insertelement is already taken.

What's wrong with using insert/extractelement for arrays and structs as well as vectors? They're all sequence types.

Nick

Vector insert/extract element take (potentially variable) Value*'s for the index and only allows one index. Aggregate get/set take constants and are variadic.

-Chris

Forbidding variable indices for arrays would seem to rather reduce their utility (precisely to that of a homogenous struct). Granted, lowering makes updating an indexed value much uglier, but it would seem to be an already-solved problem for vector lowering. Is it completely impractical to use the same rule as GEP?

— Gordon

I’m not exactly sure what variable indices would mean for an array. It’s not in memory, so you can’t get an address of the element (or else you could just use GEP). Imagine a small array (say two elements) in registers. Most ISAs don’t allow dynamic register indexing, so I don’t think that there is much utility to be lost by not supporting dynamic indices. OTOH, having the array in registers isn’t gonna fly if you need to index it in a dynamic way anyhow.

If you have variable indices, you can't trivially scalarize them. If you need variable indices, memory is still available. In practice, arrays as first-class aggregates probably won't be very useful, but are good to include for orthogonality.

-Chris

Chris Lattner wrote:

Aggregates as First Class Values:
http://nondot.org/sabre/LLVMNotes/FirstClassAggregates.txt
  

Thinking more about this...I kinda wish it was available right *now*, because I sure could use it. I've been working on functions returning structures today, and in the current IR I basically have two choices: Either return the struct using multiple return values (which means flattening any nested structs inside the struct to be returned, since AFAICT return values have to be first class, and then re-assembling the structure at the call site), or passing an extra argument which points to the struct to be filled in.

In my opinion, that's a level of detail that the frontend really shouldn't have to know or care about. The code generator should be able to make that decision based on the platform ABI and other target-specific criteria, and the frontend has no business worrying about any of these issues.

-- Talin

Hi Chris,

Eliminating the 'Void' Type:
http://nondot.org/sabre/LLVMNotes/EliminatingVoid.txt

might not some ABI's require some special stuff when
returning a struct, regardless of whether the struct
is empty or not? If so this might add a cost if you
use {} for void.

Also, there are an infinite number of different ways of
returning void: return {} or {{}} or {{{}}} etc, not
to mention returning zero length arrays. I guess that's
life.

Aggregates as First Class Values:
http://nondot.org/sabre/LLVMNotes/FirstClassAggregates.txt

Does this mean that vector types can be removed in favour
of ordinary arrays? If not, maybe at least vectors should
be changed to derive from array types, and no longer be
primitive types. This would make it easier to fix a bunch
of problems with vector types, for example that the primitive
size of <4 x i1> is 4 bits but in fact it's codegened like
[4 x i1], which takes up 4 bytes. It might also reduce the
amount of special vector code.

Your plan means that you can have loads and stores where
you don't know the size of the value being loaded/stored
(unless you have target data). I don't know if it matters.

You say "I suggest that aggregates be passed just like 'byval'
arguments by default". Wouldn't it make more sense to pass
in registers (or stack elements if you run out of registers)?

Note that MVT::ValueType is no longer adequate once you have
structs and arrays.

Ciao,

Duncan.

Hi Chris,

Eliminating the 'Void' Type:
http://nondot.org/sabre/LLVMNotes/EliminatingVoid.txt

might not some ABI's require some special stuff when
returning a struct, regardless of whether the struct
is empty or not? If so this might add a cost if you
use {} for void.

Sure, in which case they'd need to use some special attribute, or use stret for the struct return case. This is no different than today.

Aggregates as First Class Values:
http://nondot.org/sabre/LLVMNotes/FirstClassAggregates.txt

Does this mean that vector types can be removed in favour
of ordinary arrays?

Not as a first step, but probably as a second step. For the first step, I don't want to allow arithmetic on aggregate values. We can generalize this after the basics are in place.

If not, maybe at least vectors should
be changed to derive from array types, and no longer be
primitive types. This would make it easier to fix a bunch
of problems with vector types, for example that the primitive
size of <4 x i1> is 4 bits but in fact it's codegened like
[4 x i1], which takes up 4 bytes. It might also reduce the
amount of special vector code.

Array and Vector types share a common base class (SequentialType). I agree that simplifying layout would be a big benefit.

Your plan means that you can have loads and stores where
you don't know the size of the value being loaded/stored
(unless you have target data). I don't know if it matters.

I'm not sure what you mean. Isn't this the same as loading a pointer (whose size depends on TD)?

You say "I suggest that aggregates be passed just like 'byval'
arguments by default". Wouldn't it make more sense to pass
in registers (or stack elements if you run out of registers)?

an aggregate with the 'inreg' attribute could be passed that way.

Note that MVT::ValueType is no longer adequate once you have
structs and arrays.

In the codegen, they are always lowered to their elements by SDISel, so they don't make it into the dag. This code is already almost all in place.

-Chris

Hi Talin,

Chris Lattner wrote:

Aggregates as First Class Values:
http://nondot.org/sabre/LLVMNotes/FirstClassAggregates.txt

Thinking more about this...I kinda wish it was available right *now*,
because I sure could use it. I've been working on functions returning
structures today, and in the current IR I basically have two choices:
Either return the struct using multiple return values (which means
flattening any nested structs inside the struct to be returned, since
AFAICT return values have to be first class, and then re-assembling the
structure at the call site), or passing an extra argument which points
to the struct to be filled in.

I'm planning to start working on this after the 2.3 release branch is
created. Would you be interested in helping?

In my opinion, that's a level of detail that the frontend really
shouldn't have to know or care about. The code generator should be able
to make that decision based on the platform ABI and other
target-specific criteria, and the frontend has no business worrying
about any of these issues.

If you just need a convenient way to deal with relatively small
numbers of values grouped together in an efficient manner, this
new feature will be very useful.

If you need to generate code to be directly linked with C code
that uses arbitrary struct argument or return types, this feature
will be only a small step. Front-ends will still need to know
quite a lot about how structs are handled in the ABI if they want
to be compatible with other C compilers.

Dan

Dan Gohman wrote:

Hi Talin,

Chris Lattner wrote:
    

Aggregates as First Class Values:
http://nondot.org/sabre/LLVMNotes/FirstClassAggregates.txt

Thinking more about this...I kinda wish it was available right *now*,
because I sure could use it. I've been working on functions returning
structures today, and in the current IR I basically have two choices:
Either return the struct using multiple return values (which means
flattening any nested structs inside the struct to be returned, since
AFAICT return values have to be first class, and then re-assembling the
structure at the call site), or passing an extra argument which points
to the struct to be filled in.
    
I'm planning to start working on this after the 2.3 release branch is
created. Would you be interested in helping?
  

Possibly; I know a lot more about frontends than backends though.

In my opinion, that's a level of detail that the frontend really
shouldn't have to know or care about. The code generator should be able
to make that decision based on the platform ABI and other
target-specific criteria, and the frontend has no business worrying
about any of these issues.
    
If you just need a convenient way to deal with relatively small
numbers of values grouped together in an efficient manner, this
new feature will be very useful.

If you need to generate code to be directly linked with C code
that uses arbitrary struct argument or return types, this feature
will be only a small step. Front-ends will still need to know
quite a lot about how structs are handled in the ABI if they want
to be compatible with other C compilers.
  

Well, one of my goals is to support a robust FFI - programmers in my language should be able to declare "native" functions that use the C ABI. However, these native declarations can require a certain number of additional annotations, and there's no requirement that functions that aren't declared as native be compatible with the C ABI.

Hi,

Aggregates as First Class Values:

it seems to me that having this would make the byval parameter attribute
partly obsolete? Will there be semantic differences between passing a struct
directly and a pointer to a struct byval?

I can see that byval can be used on pointers to other things, but is that
really useful? I can't see any use for compiling C code, are there other
languages that have a direct use for a byval attribute?

Gr.

Matthijs

Byval and passing a first class aggregate have the same semantics. However, byval is very efficient for large aggregates and first-class aggregates is efficient for small ones.

-Chris

Byval and passing a first class aggregate have the same semantics.
However, byval is very efficient for large aggregates and first-class
aggregates is efficient for small ones.

I was making the assumption that having the same semantics actually means
being equivalent and thus resulting in the same generated code. Since, AFAICS,
the LLVM IR mainly conveys semantics, what do both ways of writing this imply
for the generated code, then?

Gr.

Matthij

'byval' is address exposed in the IR, and is thus living in memory. First class aggregates are not address exposed. Think of them as being implicitly scalarized to their elements with each element held in registers.

-Chris