WebAssembly / interface-types

Other
641 stars 57 forks source link

Discussing `record.lift/lower` for multi-dimensional records #108

Open Hywan opened 4 years ago

Hywan commented 4 years ago

Discussing about this version of the proposal (the latest at the time of writing): https://github.com/WebAssembly/interface-types/blob/5af0606baceab6c5ecc8bd247fae944998c2aa61/proposals/interface-types/working-notes/Instructions.md#stringlower_memory

I want to discuss about the record.lift instruction (same ideas for record.lower). Let's assume the following type, that could represent a Point:

;; Point { x: i32, y: i32 }
(@interface type (record (field i32) (field i32)))

Then the set of instructions would look like the following:

Instruction Stack Comment
arg.get 0 [i32(7)] Load x
arg.get 1 [i32(7), i32(42)] Load y
record.lift 0 [record([7, 42])] Tada, our record

My question is what happens with a multi-dimensional record? Let's assume the Line type:

;; Line { p1: Point, p2: Point }
(@interace type
  (record
    (field
      record (field i32) (field i32))
    (field
      record (field i32) (field i32))))

Then the set of instructions would look like as follows:

Instruction Stack Comment
arg.get 0 [i32(7)] Load x for p1
arg.get 1 [i32(7), i32(42)] Load y for p1
arg.get 2 [i32(7), i32(42), i32(153)] Load x for p2
arg.get 3 [i32(7), i32(42), i32(153), i32(256)] Load y for p2
record.lift 0 [record([record([7, 42]), record([153, 256])])] Tada, our record

Is this correct? Should we have all the fields “flattened”, and the record.lift instruction rebuild everything? Or do we expect the following:

Instruction Stack Comment
arg.get 0 [i32(7)] Load x for p1
arg.get 1 [i32(7), i32(42)] Load y for p1
record.lift ?? [record([i32(7), i32(42)])] Record for p1
arg.get 2 [record([i32(7), i32(42)]), i32(153)] Load x for p2
arg.get 3 [record([i32(7), i32(42)]), i32(153), i32(256)] Load y for p2
record.lift ?? [record([i32(7), i32(42)]), record([i32(153), i32(256)])] Record for p2
record.lift 0 [record([record([7, 42]), record([153, 256])])] Tada, our final record

In this case, we load intermediate Point records. But since record.lift requires a record type index, what would it be? It would mean that record type must be flattened too, something like:

(@interface type $point (record (field i32) (field i32)))
(@interface type $line (record (field (record type $point) (record type $point))))

The same observation can be applied to record.lower.

I hope my question isn't too trivial. With the Covid-19 situation, I have difficulties to follow every discussions of this WG.

Thanks!

fgmccabe commented 4 years ago
  1. Record.lift/lower (not my preferred names for these ops) wrap and unwrap interface value types. I.e., they go from a sequence of IT values on the stack <-> a single IT value. Multi-dimensional records as you put it would follow this pattern too. Each lift/lower wraps/unwraps a single record.
  2. Although it can seem expensive to push entries on the stack, be aware that in most implementations a push/pop operation does not actually result in any code being executed. Think of it as a systematic way of supporting multi-operand instructions.

On Tue, Apr 7, 2020 at 5:23 AM Ivan Enderlin notifications@github.com wrote:

Discussing about this version of the proposal (the latest at the time of writing): https://github.com/WebAssembly/interface-types/blob/5af0606baceab6c5ecc8bd247fae944998c2aa61/proposals/interface-types/working-notes/Instructions.md#stringlower_memory

I want to discuss about the record.lift instruction (same ideas for record.lower). Let's assume the following type, that could represent a Point:

;; Point { x: i32, y: i32 }

(@interface type (record (field i32) (field i32)))

Then the set of instructions would look like the following: Instruction Stack Comment arg.get 0 [i32(7)] Load x arg.get 1 [i32(7), i32(42)] Load y record.lift 0 [record([7, 42])] Tada, our record

My question is what happens with a multi-dimensional record? Let's assume the Line type:

;; Line { p1: Point, p2: Point }

(@interace type

(record

(field

  record (field i32) (field i32))

(field

  record (field i32) (field i32))))

Then the set of instructions would look like as follows: Instruction Stack Comment arg.get 0 [i32(7)] Load x for p1 arg.get 1 [i32(7), i32(42)] Load y for p1 arg.get 2 [i32(7), i32(42), i32(153)] Load x for p2 arg.get 3 [i32(7), i32(42), i32(153), i32(256)] Load y for p2 record.lift 0 [record([record([7, 42]), record([153, 256])])] Tada, our record

Is this correct? Should we have all the fields “flattened”, and the record.lift instruction rebuild everything? Or do we expect the following: Instruction Stack Comment arg.get 0 [i32(7)] Load x for p1 arg.get 1 [i32(7), i32(42)] Load y for p1 record.lift ?? [record([i32(7), i32(42)])] Record for p1 arg.get 2 [record([i32(7), i32(42)]), i32(153)] Load x for p2 arg.get 3 [record([i32(7), i32(42)]), i32(153), i32(256)] Load y for p2 record.lift ?? [record([i32(7), i32(42)]), record([i32(153), i32(256)])] Record for p2 record.lift 0 [record([record([7, 42]), record([153, 256])])] Tada, our final record

In this case, we load intermediate Point records. But since record.lift requires a record type index, what would it be? It would mean that record type must be flattened too, something like:

(@interface type $point (record (field i32) (field i32)))

(@interface type $line (record (field (record type $point) (record type $point))))

The same observation can be applied to record.lower.

I hope my question isn't too trivial. With the Covid-19 situation, I have difficulties to follow every discussions of this WG.

Thanks!

— You are receiving this because you are subscribed to this thread. Reply to this email directly, view it on GitHub https://github.com/WebAssembly/interface-types/issues/108, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAQAXUAI6UP3RHPFFZ33UJTRLMLKVANCNFSM4MDCGGMQ .

-- Francis McCabe SWE

syrusakbary commented 4 years ago
  1. Record.lift/lower (not my preferred names for these ops) wrap and unwrap interface value types. I.e., they go from a sequence of IT values on the stack <-> a single IT value.

Agreed, it took me some time to grasp what were the methods for. I think record.wrap, record.unwrap might be a bit clearer. Thoughts?

fgmccabe commented 4 years ago

Prefer pack and unpack but not super committed to that