marmot playground

Run arrives with marmot’s wasm build. The stages are real.

Sum loop: The loop from the home page: watch it become vector code.

Diagnostics

marmot build: no errors.

MLIR, with the go dialect

Go operations (go.*) still say what Go means. 54 lines

  llvm.func @main.Sum(%a0: !llvm.struct<(ptr, i64, i64)>) -> i32 attributes {no_unwind, passthrough = [["frame-pointer", "non-leaf"]]} {
    %v3 = llvm.extractvalue %a0[1] : !llvm.struct<(ptr, i64, i64)>
    %v4 = llvm.mlir.constant(0 : i32) : i32
    %v5 = llvm.mlir.constant(-1 : i64) : i64
    llvm.br ^bb1(%v4, %v5 : i32, i64)
  ^bb1(%v1: i32, %v2: i64):
    %v6 = llvm.mlir.constant(1 : i64) : i64
    %v7 = llvm.add %v2, %v6 : i64
    %v8 = llvm.icmp "slt" %v7, %v3 : i64
    llvm.cond_br %v8, ^bb2, ^bb3
  ^bb2:
    %v9 = llvm.extractvalue %a0[0] : !llvm.struct<(ptr, i64, i64)>
    %v10 = llvm.extractvalue %a0[1] : !llvm.struct<(ptr, i64, i64)>
    %v11 = go.index %v9[%v7] len %v10, i32 : i64
    %v12 = llvm.load %v11 {alignment = 4 : i64, go.unsafe} : !llvm.ptr -> i32
    %v13 = llvm.add %v1, %v12 : i32
    llvm.br ^bb1(%v13, %v7 : i32, i64)
  ^bb3:
    llvm.return %v1 : i32
  }

  llvm.func @main.main() attributes {no_unwind, passthrough = [["frame-pointer", "non-leaf"]]} {
    %v1 = go.new @"type:[4]int32", !llvm.array<4 x i32>
    %v2 = llvm.mlir.constant(4 : i64) : i64
    %v3 = llvm.mlir.constant(0 : i64) : i64
    %v4 = llvm.getelementptr inbounds %v1[%v3] : (!llvm.ptr, i64) -> !llvm.ptr, i32
    %v5 = llvm.mlir.constant(1 : i32) : i32
    llvm.store %v5, %v4 {alignment = 4 : i64, go.unsafe} : i32, !llvm.ptr
    %v6 = llvm.mlir.constant(4 : i64) : i64
    %v7 = llvm.mlir.constant(1 : i64) : i64
    %v8 = llvm.getelementptr inbounds %v1[%v7] : (!llvm.ptr, i64) -> !llvm.ptr, i32
    %v9 = llvm.mlir.constant(2 : i32) : i32
    llvm.store %v9, %v8 {alignment = 4 : i64, go.unsafe} : i32, !llvm.ptr
    %v10 = llvm.mlir.constant(4 : i64) : i64
    %v11 = llvm.mlir.constant(2 : i64) : i64
    %v12 = llvm.getelementptr inbounds %v1[%v11] : (!llvm.ptr, i64) -> !llvm.ptr, i32
    %v13 = llvm.mlir.constant(3 : i32) : i32
    llvm.store %v13, %v12 {alignment = 4 : i64, go.unsafe} : i32, !llvm.ptr
    %v14 = llvm.mlir.constant(4 : i64) : i64
    %v15 = llvm.mlir.constant(3 : i64) : i64
    %v16 = llvm.getelementptr inbounds %v1[%v15] : (!llvm.ptr, i64) -> !llvm.ptr, i32
    %v17 = llvm.mlir.constant(4 : i32) : i32
    llvm.store %v17, %v16 {alignment = 4 : i64, go.unsafe} : i32, !llvm.ptr
    %v18 = llvm.mlir.constant(4 : i64) : i64
    %v19 = llvm.mlir.constant(0 : i64) : i64
    %v20 = go.slice %v1[%v19 : %v18] cap %v18, i32 len_bound unsigned : i64 -> !llvm.struct<(ptr, i64, i64)>
    %v21 = llvm.call @main.Sum(%v20) : (!llvm.struct<(ptr, i64, i64)>) -> i32
    llvm.call @runtime.printlock() : () -> ()
    %v22 = llvm.sext %v21 : i32 to i64
    llvm.call @runtime.printint(%v22) : (i64) -> ()
    llvm.call @runtime.printnl() : () -> ()
    llvm.call @runtime.printunlock() : () -> ()
    llvm.return
  }

LLVM IR, -O 2

Vector types: a loop works on several values at a time. 104 lines

define i32 @main.Sum({ ptr, i64, i64 } %0) local_unnamed_addr #1 !dbg !20 {
  %2 = extractvalue { ptr, i64, i64 } %0, 1
  %3 = icmp sgt i64 %2, 0
  br i1 %3, label %iter.check, label %._crit_edge

iter.check:                                       ; preds = %1
  %4 = extractvalue { ptr, i64, i64 } %0, 0
  %min.iters.check = icmp ult i64 %2, 4
  br i1 %min.iters.check, label %vec.epilog.scalar.ph.preheader, label %vector.main.loop.iter.check

vector.main.loop.iter.check:                      ; preds = %iter.check
  %min.iters.check8 = icmp ult i64 %2, 16
  br i1 %min.iters.check8, label %vec.epilog.ph, label %vector.ph

vector.ph:                                        ; preds = %vector.main.loop.iter.check
  %n.mod.vf = and i64 %2, 12
  %n.vec = and i64 %2, 9223372036854775792
  br label %vector.body

vector.body:                                      ; preds = %vector.body, %vector.ph
  %index = phi i64 [ 0, %vector.ph ], [ %index.next, %vector.body ]
  %vec.phi = phi <4 x i32> [ zeroinitializer, %vector.ph ], [ %9, %vector.body ]
  %vec.phi9 = phi <4 x i32> [ zeroinitializer, %vector.ph ], [ %10, %vector.body ]
  %vec.phi10 = phi <4 x i32> [ zeroinitializer, %vector.ph ], [ %11, %vector.body ]
  %vec.phi11 = phi <4 x i32> [ zeroinitializer, %vector.ph ], [ %12, %vector.body ]
  %5 = getelementptr inbounds nuw i32, ptr %4, i64 %index
  %6 = getelementptr inbounds nuw i8, ptr %5, i64 16
  %7 = getelementptr inbounds nuw i8, ptr %5, i64 32
  %8 = getelementptr inbounds nuw i8, ptr %5, i64 48
  %wide.load = load <4 x i32>, ptr %5, align 4
  %wide.load12 = load <4 x i32>, ptr %6, align 4
  %wide.load13 = load <4 x i32>, ptr %7, align 4
  %wide.load14 = load <4 x i32>, ptr %8, align 4
  %9 = add <4 x i32> %wide.load, %vec.phi
  %10 = add <4 x i32> %wide.load12, %vec.phi9
  %11 = add <4 x i32> %wide.load13, %vec.phi10
  %12 = add <4 x i32> %wide.load14, %vec.phi11
  %index.next = add nuw i64 %index, 16
  %13 = icmp eq i64 %index.next, %n.vec
  br i1 %13, label %middle.block, label %vector.body

middle.block:                                     ; preds = %vector.body
  %bin.rdx = add <4 x i32> %10, %9
  %bin.rdx15 = add <4 x i32> %11, %bin.rdx
  %bin.rdx16 = add <4 x i32> %12, %bin.rdx15
  %14 = tail call i32 @llvm.vector.reduce.add.v4i32(<4 x i32> %bin.rdx16)
  %cmp.n = icmp eq i64 %2, %n.vec
  br i1 %cmp.n, label %._crit_edge, label %vec.epilog.iter.check

vec.epilog.iter.check:                            ; preds = %middle.block
  %min.epilog.iters.check = icmp eq i64 %n.mod.vf, 0
  br i1 %min.epilog.iters.check, label %vec.epilog.scalar.ph.preheader, label %vec.epilog.ph, !prof !29

vec.epilog.ph:                                    ; preds = %vector.main.loop.iter.check, %vec.epilog.iter.check
  %vec.epilog.resume.val = phi i64 [ %n.vec, %vec.epilog.iter.check ], [ 0, %vector.main.loop.iter.check ]
  %bc.merge.rdx = phi i32 [ %14, %vec.epilog.iter.check ], [ 0, %vector.main.loop.iter.check ]
  %n.vec18 = and i64 %2, 9223372036854775804
  %15 = insertelement <4 x i32> <i32 poison, i32 0, i32 0, i32 0>, i32 %bc.merge.rdx, i64 0
  br label %vec.epilog.vector.body

vec.epilog.vector.body:                           ; preds = %vec.epilog.vector.body, %vec.epilog.ph
  %index19 = phi i64 [ %vec.epilog.resume.val, %vec.epilog.ph ], [ %index.next22, %vec.epilog.vector.body ]
  %vec.phi20 = phi <4 x i32> [ %15, %vec.epilog.ph ], [ %17, %vec.epilog.vector.body ]
  %16 = getelementptr inbounds nuw i32, ptr %4, i64 %index19
  %wide.load21 = load <4 x i32>, ptr %16, align 4
  %17 = add <4 x i32> %wide.load21, %vec.phi20
  %index.next22 = add nuw i64 %index19, 4
  %18 = icmp eq i64 %index.next22, %n.vec18
  br i1 %18, label %vec.epilog.middle.block, label %vec.epilog.vector.body

vec.epilog.middle.block:                          ; preds = %vec.epilog.vector.body
  %19 = tail call i32 @llvm.vector.reduce.add.v4i32(<4 x i32> %17)
  %cmp.n23 = icmp eq i64 %2, %n.vec18
  br i1 %cmp.n23, label %._crit_edge, label %vec.epilog.scalar.ph.preheader

vec.epilog.scalar.ph.preheader:                   ; preds = %iter.check, %vec.epilog.iter.check, %vec.epilog.middle.block
  %.ph = phi i64 [ 0, %iter.check ], [ %n.vec, %vec.epilog.iter.check ], [ %n.vec18, %vec.epilog.middle.block ]
  %.ph25 = phi i32 [ 0, %iter.check ], [ %14, %vec.epilog.iter.check ], [ %19, %vec.epilog.middle.block ]
  br label %vec.epilog.scalar.ph

vec.epilog.scalar.ph:                             ; preds = %vec.epilog.scalar.ph.preheader, %vec.epilog.scalar.ph
  %20 = phi i64 [ %25, %vec.epilog.scalar.ph ], [ %.ph, %vec.epilog.scalar.ph.preheader ]
  %21 = phi i32 [ %24, %vec.epilog.scalar.ph ], [ %.ph25, %vec.epilog.scalar.ph.preheader ]
  %22 = getelementptr inbounds nuw i32, ptr %4, i64 %20
  %23 = load i32, ptr %22, align 4
  %24 = add i32 %23, %21
  %25 = add nuw nsw i64 %20, 1
  %exitcond.not = icmp eq i64 %25, %2
  br i1 %exitcond.not, label %._crit_edge, label %vec.epilog.scalar.ph

._crit_edge:                                      ; preds = %vec.epilog.scalar.ph, %middle.block, %vec.epilog.middle.block, %1
  %.lcssa3 = phi i32 [ 0, %1 ], [ %19, %vec.epilog.middle.block ], [ %14, %middle.block ], [ %24, %vec.epilog.scalar.ph ]
  ret i32 %.lcssa3
}

define void @main.main() local_unnamed_addr #3 !dbg !35 {
main.Sum.exit:
  %0 = tail call ptr @runtime.newobject(ptr nonnull @"type:[4]int32") #5
  tail call void @runtime.printlock() #5
  tail call void @runtime.printint(i64 10) #5
  tail call void @runtime.printnl() #5
  tail call void @runtime.printunlock() #5
  ret void
}

arm64 machine code

Vector instructions, on wide registers. 76 lines

main.Sum:
  cmp x1, #0x1
  b.lt 0x1c <ltmp0+0x1c>
  cmp x1, #0x4
  b.hs 0x28 <ltmp0+0x28>
  mov x9, #0x0                ; =0
  mov w8, #0x0                ; =0
  b 0xd4 <ltmp0+0xd4>
  mov w8, #0x0                ; =0
  mov x0, x8
  ret
  cmp x1, #0x10
  b.hs 0x3c <ltmp0+0x3c>
  mov x9, #0x0                ; =0
  mov w8, #0x0                ; =0
  b 0x9c <ltmp0+0x9c>
  and x10, x1, #0xc
  and x9, x1, #0x7ffffffffffffff0
  add x8, x0, #0x20
  movi.2d v0, #0000000000000000
  and x11, x1, #0x7ffffffffffffff0
  movi.2d v1, #0000000000000000
  movi.2d v2, #0000000000000000
  movi.2d v3, #0000000000000000
  ldp q4, q5, [x8, #-0x20]
  ldp q6, q7, [x8], #0x40
  add.4s v0, v4, v0
  add.4s v1, v5, v1
  add.4s v2, v6, v2
  add.4s v3, v7, v3
  subs x11, x11, #0x10
  b.ne 0x5c <ltmp0+0x5c>
  add.4s v0, v1, v0
  add.4s v0, v2, v0
  add.4s v0, v3, v0
  addv.4s s0, v0
  fmov w8, s0
  cmp x1, x9
  b.eq 0xec <ltmp0+0xec>
  cbz x10, 0xd4 <ltmp0+0xd4>
  mov x10, x9
  and x9, x1, #0x7ffffffffffffffc
  movi.2d v0, #0000000000000000
  mov.s v0[0], w8
  sub x8, x10, x9
  add x10, x0, x10, lsl #2
  ldr q1, [x10], #0x10
  add.4s v0, v1, v0
  adds x8, x8, #0x4
  b.ne 0xb4 <ltmp0+0xb4>
  addv.4s s0, v0
  fmov w8, s0
  cmp x1, x9
  b.eq 0xec <ltmp0+0xec>
  sub x10, x1, x9
  add x9, x0, x9, lsl #2
  ldr w11, [x9], #0x4
  add w8, w11, w8
  subs x10, x10, #0x1
  b.ne 0xdc <ltmp0+0xdc>
  mov x0, x8
  ret

main.main:
  stp x29, x30, [sp, #-0x10]!
  mov x29, sp
  adrp x0, 0x0 <ltmp0>
  ldr x0, [x0]
  bl 0x12c <_main.main+0x10>
  bl 0x130 <_main.main+0x14>
  mov w0, #0xa                ; =10
  bl 0x138 <_main.main+0x1c>
  bl 0x13c <_main.main+0x20>
  bl 0x140 <_main.main+0x24>
  ldp x29, x30, [sp], #0x10
  ret