(module
  (memory $0 1)
  (export "memory" (memory $0))

  (func $sq (export "sq") (param $h i32) (param $f i32) (param $double i32) (param $repeat i32)
    (local $tmp i64)
    
    (local $f0 i64)
    (local $f1 i64)
    (local $f2 i64)
    (local $f3 i64)
    (local $f4 i64)
    (local $f5 i64)
    (local $f6 i64)
    (local $f7 i64)
    (local $f8 i64)
    (local $f9 i64)

    (local $h0 i64)
    (local $h1 i64)
    (local $h2 i64)
    (local $h3 i64)
    (local $h4 i64)
    (local $h5 i64)
    (local $h6 i64)
    (local $h7 i64)
    (local $h8 i64)
    (local $h9 i64)
    
    (local $carry0 i64)
    (local $carry1 i64)
    (local $carry2 i64)
    (local $carry3 i64)
    (local $carry4 i64)
    (local $carry5 i64)
    (local $carry6 i64)
    (local $carry7 i64)
    (local $carry8 i64)
    (local $carry9 i64)

    (local $f0_2 i64)
    (local $f1_2 i64)
    (local $f2_2 i64)
    (local $f3_2 i64)
    (local $f4_2 i64)
    (local $f5_2 i64)
    (local $f6_2 i64)
    (local $f7_2 i64)

    (local $f5_38 i64)
    (local $f6_19 i64)
    (local $f7_38 i64)
    (local $f8_19 i64)
    (local $f9_38 i64)

    (local $f0f0 i64)
    (local $f0f1_2 i64)
    (local $f0f2_2 i64)
    (local $f0f3_2 i64)
    (local $f0f4_2 i64)
    (local $f0f5_2 i64)
    (local $f0f6_2 i64)
    (local $f0f7_2 i64)
    (local $f0f8_2 i64)
    (local $f0f9_2 i64)
    (local $f1f1_2 i64)
    (local $f1f2_2 i64)
    (local $f1f3_4 i64)
    (local $f1f4_2 i64)
    (local $f1f5_4 i64)
    (local $f1f6_2 i64)
    (local $f1f7_4 i64)
    (local $f1f8_2 i64)
    (local $f1f9_76 i64)
    (local $f2f2 i64)
    (local $f2f3_2 i64)
    (local $f2f4_2 i64)
    (local $f2f5_2 i64)
    (local $f2f6_2 i64)
    (local $f2f7_2 i64)
    (local $f2f8_38 i64)
    (local $f2f9_38 i64)
    (local $f3f3_2 i64)
    (local $f3f4_2 i64)
    (local $f3f5_4 i64)
    (local $f3f6_2 i64)
    (local $f3f7_76 i64)
    (local $f3f8_38 i64)
    (local $f3f9_76 i64)
    (local $f4f4 i64)
    (local $f4f5_2 i64)
    (local $f4f6_38 i64)
    (local $f4f7_38 i64)
    (local $f4f8_38 i64)
    (local $f4f9_38 i64)
    (local $f5f5_38 i64)
    (local $f5f6_38 i64)
    (local $f5f7_76 i64)
    (local $f5f8_38 i64)
    (local $f5f9_76 i64)
    (local $f6f6_19 i64)
    (local $f6f7_38 i64)
    (local $f6f8_38 i64)
    (local $f6f9_38 i64)
    (local $f7f7_38 i64)
    (local $f7f8_38 i64)
    (local $f7f9_76 i64)
    (local $f8f8_19 i64)
    (local $f8f9_38 i64)
    (local $f9f9_38 i64)

    (set_local $f0 (i64.load32_u offset=0  (get_local $f)))
    (set_local $f1 (i64.load32_u offset=4  (get_local $f)))
    (set_local $f2 (i64.load32_u offset=8  (get_local $f)))
    (set_local $f3 (i64.load32_u offset=12 (get_local $f)))
    (set_local $f4 (i64.load32_u offset=16 (get_local $f)))
    (set_local $f5 (i64.load32_u offset=20 (get_local $f)))
    (set_local $f6 (i64.load32_u offset=24 (get_local $f)))
    (set_local $f7 (i64.load32_u offset=28 (get_local $f)))
    (set_local $f8 (i64.load32_u offset=32 (get_local $f)))
    (set_local $f9 (i64.load32_u offset=36 (get_local $f)))

    (block $end
        (loop $again
            (set_local $f0 (i64.extend32_s (get_local $f0)))
            (set_local $f1 (i64.extend32_s (get_local $f1)))
            (set_local $f2 (i64.extend32_s (get_local $f2)))
            (set_local $f3 (i64.extend32_s (get_local $f3)))
            (set_local $f4 (i64.extend32_s (get_local $f4)))
            (set_local $f5 (i64.extend32_s (get_local $f5)))
            (set_local $f6 (i64.extend32_s (get_local $f6)))
            (set_local $f7 (i64.extend32_s (get_local $f7)))
            (set_local $f8 (i64.extend32_s (get_local $f8)))
            (set_local $f9 (i64.extend32_s (get_local $f9)))

            (set_local $f0_2 (i64.mul (i64.const 2 (get_local $f0))))
            (set_local $f1_2 (i64.mul (i64.const 2 (get_local $f1))))
            (set_local $f2_2 (i64.mul (i64.const 2 (get_local $f2))))
            (set_local $f3_2 (i64.mul (i64.const 2 (get_local $f3))))
            (set_local $f4_2 (i64.mul (i64.const 2 (get_local $f4))))
            (set_local $f5_2 (i64.mul (i64.const 2 (get_local $f5))))
            (set_local $f6_2 (i64.mul (i64.const 2 (get_local $f6))))
            (set_local $f7_2 (i64.mul (i64.const 2 (get_local $f7))))

            (set_local $f5_38 (i64.mul (i64.const 38 (get_local $f5))))
            (set_local $f6_19 (i64.mul (i64.const 19 (get_local $f6))))
            (set_local $f7_38 (i64.mul (i64.const 38 (get_local $f7))))
            (set_local $f8_19 (i64.mul (i64.const 19 (get_local $f8))))
            (set_local $f9_38 (i64.mul (i64.const 38 (get_local $f9))))
            
            (set_local $f0f0    (i64.mul (get_local $f0)   (get_local $f0)))
            (set_local $f0f1_2  (i64.mul (get_local $f0_2) (get_local $f1)))
            (set_local $f0f2_2  (i64.mul (get_local $f0_2) (get_local $f2)))
            (set_local $f0f3_2  (i64.mul (get_local $f0_2) (get_local $f3)))
            (set_local $f0f4_2  (i64.mul (get_local $f0_2) (get_local $f4)))
            (set_local $f0f5_2  (i64.mul (get_local $f0_2) (get_local $f5)))
            (set_local $f0f6_2  (i64.mul (get_local $f0_2) (get_local $f6)))
            (set_local $f0f7_2  (i64.mul (get_local $f0_2) (get_local $f7)))
            (set_local $f0f8_2  (i64.mul (get_local $f0_2) (get_local $f8)))
            (set_local $f0f9_2  (i64.mul (get_local $f0_2) (get_local $f9)))
            (set_local $f1f1_2  (i64.mul (get_local $f1_2) (get_local $f1)))
            (set_local $f1f2_2  (i64.mul (get_local $f1_2) (get_local $f2)))
            (set_local $f1f3_4  (i64.mul (get_local $f1_2) (get_local $f3_2)))
            (set_local $f1f4_2  (i64.mul (get_local $f1_2) (get_local $f4)))
            (set_local $f1f5_4  (i64.mul (get_local $f1_2) (get_local $f5_2)))
            (set_local $f1f6_2  (i64.mul (get_local $f1_2) (get_local $f6)))
            (set_local $f1f7_4  (i64.mul (get_local $f1_2) (get_local $f7_2)))
            (set_local $f1f8_2  (i64.mul (get_local $f1_2) (get_local $f8)))
            (set_local $f1f9_76 (i64.mul (get_local $f1_2) (get_local $f9_38)))
            (set_local $f2f2    (i64.mul (get_local $f2)   (get_local $f2)))
            (set_local $f2f3_2  (i64.mul (get_local $f2_2) (get_local $f3)))
            (set_local $f2f4_2  (i64.mul (get_local $f2_2) (get_local $f4)))
            (set_local $f2f5_2  (i64.mul (get_local $f2_2) (get_local $f5)))
            (set_local $f2f6_2  (i64.mul (get_local $f2_2) (get_local $f6)))
            (set_local $f2f7_2  (i64.mul (get_local $f2_2) (get_local $f7)))
            (set_local $f2f8_38 (i64.mul (get_local $f2_2) (get_local $f8_19)))
            (set_local $f2f9_38 (i64.mul (get_local $f2) (get_local $f9_38)))
            (set_local $f3f3_2  (i64.mul (get_local $f3_2) (get_local $f3)))
            (set_local $f3f4_2  (i64.mul (get_local $f3_2) (get_local $f4)))
            (set_local $f3f5_4  (i64.mul (get_local $f3_2) (get_local $f5_2)))
            (set_local $f3f6_2  (i64.mul (get_local $f3_2) (get_local $f6)))
            (set_local $f3f7_76 (i64.mul (get_local $f3_2) (get_local $f7_38)))
            (set_local $f3f8_38 (i64.mul (get_local $f3_2) (get_local $f8_19)))
            (set_local $f3f9_76 (i64.mul (get_local $f3_2) (get_local $f9_38)))
            (set_local $f4f4    (i64.mul (get_local $f4)   (get_local $f4)))
            (set_local $f4f5_2  (i64.mul (get_local $f4_2) (get_local $f5)))
            (set_local $f4f6_38 (i64.mul (get_local $f4_2) (get_local $f6_19)))
            (set_local $f4f7_38 (i64.mul (get_local $f4)   (get_local $f7_38)))
            (set_local $f4f8_38 (i64.mul (get_local $f4_2) (get_local $f8_19)))
            (set_local $f4f9_38 (i64.mul (get_local $f4)   (get_local $f9_38)))
            (set_local $f5f5_38 (i64.mul (get_local $f5)   (get_local $f5_38)))
            (set_local $f5f6_38 (i64.mul (get_local $f5_2) (get_local $f6_19)))
            (set_local $f5f7_76 (i64.mul (get_local $f5_2) (get_local $f7_38)))
            (set_local $f5f8_38 (i64.mul (get_local $f5_2) (get_local $f8_19)))
            (set_local $f5f9_76 (i64.mul (get_local $f5_2) (get_local $f9_38)))
            (set_local $f6f6_19 (i64.mul (get_local $f6)   (get_local $f6_19)))
            (set_local $f6f7_38 (i64.mul (get_local $f6)   (get_local $f7_38)))
            (set_local $f6f8_38 (i64.mul (get_local $f6_2) (get_local $f8_19)))
            (set_local $f6f9_38 (i64.mul (get_local $f6)   (get_local $f9_38)))
            (set_local $f7f7_38 (i64.mul (get_local $f7)   (get_local $f7_38)))
            (set_local $f7f8_38 (i64.mul (get_local $f7_2) (get_local $f8_19)))
            (set_local $f7f9_76 (i64.mul (get_local $f7_2) (get_local $f9_38)))
            (set_local $f8f8_19 (i64.mul (get_local $f8)   (get_local $f8_19)))
            (set_local $f8f9_38 (i64.mul (get_local $f8)   (get_local $f9_38)))
            (set_local $f9f9_38 (i64.mul (get_local $f9)   (get_local $f9_38)))

            (set_local $h0 (i64.add (get_local $f0f0)   (i64.add (get_local $f1f9_76) (i64.add (get_local $f2f8_38) (i64.add (get_local $f3f7_76) (i64.add (get_local $f4f6_38) (get_local $f5f5_38)))))))
            (set_local $h1 (i64.add (get_local $f0f1_2) (i64.add (get_local $f2f9_38) (i64.add (get_local $f3f8_38) (i64.add (get_local $f4f7_38) (get_local $f5f6_38))))))
            (set_local $h2 (i64.add (get_local $f0f2_2) (i64.add (get_local $f1f1_2)  (i64.add (get_local $f3f9_76) (i64.add (get_local $f4f8_38) (i64.add (get_local $f5f7_76) (get_local $f6f6_19)))))))
            (set_local $h3 (i64.add (get_local $f0f3_2) (i64.add (get_local $f1f2_2)  (i64.add (get_local $f4f9_38) (i64.add (get_local $f5f8_38) (get_local $f6f7_38))))))
            (set_local $h4 (i64.add (get_local $f0f4_2) (i64.add (get_local $f1f3_4)  (i64.add (get_local $f2f2)    (i64.add (get_local $f5f9_76) (i64.add (get_local $f6f8_38) (get_local $f7f7_38)))))))
            (set_local $h5 (i64.add (get_local $f0f5_2) (i64.add (get_local $f1f4_2)  (i64.add (get_local $f2f3_2)  (i64.add (get_local $f6f9_38) (get_local $f7f8_38))))))
            (set_local $h6 (i64.add (get_local $f0f6_2) (i64.add (get_local $f1f5_4)  (i64.add (get_local $f2f4_2)  (i64.add (get_local $f3f3_2)  (i64.add (get_local $f7f9_76) (get_local $f8f8_19)))))))
            (set_local $h7 (i64.add (get_local $f0f7_2) (i64.add (get_local $f1f6_2)  (i64.add (get_local $f2f5_2)  (i64.add (get_local $f3f4_2)  (get_local $f8f9_38))))))
            (set_local $h8 (i64.add (get_local $f0f8_2) (i64.add (get_local $f1f7_4)  (i64.add (get_local $f2f6_2)  (i64.add (get_local $f3f5_4)  (i64.add (get_local $f4f4)    (get_local $f9f9_38)))))))
            (set_local $h9 (i64.add (get_local $f0f9_2) (i64.add (get_local $f1f8_2)  (i64.add (get_local $f2f7_2)  (i64.add (get_local $f3f6_2)  (get_local $f4f5_2 ))))))

            (br_if $end (i32.eq (get_local $count) (get_local $repeat)))
            (set_local $count (i32.add (get_local $count) (i32.const 1)))
            (br $again)))

    (if (i32.eq (get_local $double) (i32.const 1))
      (then
        (set_local $h0 (i64.add (get_local $h0) (get_local $h0)))
        (set_local $h1 (i64.add (get_local $h1) (get_local $h1)))
        (set_local $h2 (i64.add (get_local $h2) (get_local $h2)))
        (set_local $h3 (i64.add (get_local $h3) (get_local $h3)))
        (set_local $h4 (i64.add (get_local $h4) (get_local $h4)))
        (set_local $h5 (i64.add (get_local $h5) (get_local $h5)))
        (set_local $h6 (i64.add (get_local $h6) (get_local $h6)))
        (set_local $h7 (i64.add (get_local $h7) (get_local $h7)))
        (set_local $h8 (i64.add (get_local $h8) (get_local $h8)))
        (set_local $h9 (i64.add (get_local $h9) (get_local $h9)))))

    (set_local $carry0 (i64.shr_s (i64.add (get_local $h0) (i64.shl (i64.const 1) (i64.const 25))) (i64.const 26)))
    (set_local $h1 (i64.add (get_local $h1) (get_local $carry0)))
    (set_local $h0 (i64.sub (get_local $h0) (i64.mul (get_local $carry0) (i64.shl (i64.const 1) (i64.const 26)))))
    (set_local $carry4 (i64.shr_s (i64.add (get_local $h4) (i64.shl (i64.const 1) (i64.const 25))) (i64.const 26)))
    (set_local $h5 (i64.add (get_local $h5) (get_local $carry4)))
    (set_local $h4 (i64.sub (get_local $h4) (i64.mul (get_local $carry4) (i64.shl (i64.const 1) (i64.const 26)))))

    (set_local $carry1 (i64.shr_s (i64.add (get_local $h1) (i64.shl (i64.const 1) (i64.const 24))) (i64.const 25)))
    (set_local $h2 (i64.add (get_local $h2) (get_local $carry1)))
    (set_local $h1 (i64.sub (get_local $h1) (i64.mul (get_local $carry1) (i64.shl (i64.const 1) (i64.const 25)))))
    (set_local $carry5 (i64.shr_s (i64.add (get_local $h5) (i64.shl (i64.const 1) (i64.const 24))) (i64.const 25)))
    (set_local $h6 (i64.add (get_local $h6) (get_local $carry5)))
    (set_local $h5 (i64.sub (get_local $h5) (i64.mul (get_local $carry5) (i64.shl (i64.const 1) (i64.const 25)))))
    
    (set_local $carry2 (i64.shr_s (i64.add (get_local $h2) (i64.shl (i64.const 1) (i64.const 25))) (i64.const 26)))
    (set_local $h3 (i64.add (get_local $h3) (get_local $carry2)))
    (set_local $h2 (i64.sub (get_local $h2) (i64.mul (get_local $carry2) (i64.shl (i64.const 1) (i64.const 26)))))
    (set_local $carry6 (i64.shr_s (i64.add (get_local $h6) (i64.shl (i64.const 1) (i64.const 25))) (i64.const 26)))
    (set_local $h7 (i64.add (get_local $h7) (get_local $carry6)))
    (set_local $h6 (i64.sub (get_local $h6) (i64.mul (get_local $carry6) (i64.shl (i64.const 1) (i64.const 26)))))

    (set_local $carry3 (i64.shr_s (i64.add (get_local $h3) (i64.shl (i64.const 1) (i64.const 24))) (i64.const 25)))
    (set_local $h4 (i64.add (get_local $h4) (get_local $carry3)))
    (set_local $h3 (i64.sub (get_local $h3) (i64.mul (get_local $carry3) (i64.shl (i64.const 1) (i64.const 25)))))
    (set_local $carry7 (i64.shr_s (i64.add (get_local $h7) (i64.shl (i64.const 1) (i64.const 24))) (i64.const 25)))
    (set_local $h8 (i64.add (get_local $h8) (get_local $carry7)))
    (set_local $h7 (i64.sub (get_local $h7) (i64.mul (get_local $carry7) (i64.shl (i64.const 1) (i64.const 25)))))

    (set_local $carry4 (i64.shr_s (i64.add (get_local $h4) (i64.shl (i64.const 1) (i64.const 25))) (i64.const 26)))
    (set_local $h5 (i64.add (get_local $h5) (get_local $carry4)))
    (set_local $h4 (i64.sub (get_local $h4) (i64.mul (get_local $carry4) (i64.shl (i64.const 1) (i64.const 26)))))
    (set_local $carry8 (i64.shr_s (i64.add (get_local $h8) (i64.shl (i64.const 1) (i64.const 25))) (i64.const 26)))
    (set_local $h9 (i64.add (get_local $h9) (get_local $carry8)))
    (set_local $h8 (i64.sub (get_local $h8) (i64.mul (get_local $carry8) (i64.shl (i64.const 1) (i64.const 26)))))

    (set_local $carry9 (i64.shr_s (i64.add (get_local $h9) (i64.shl (i64.const 1) (i64.const 24))) (i64.const 25)))
    (set_local $h0 (i64.add (get_local $h0) (i64.mul (get_local $carry9) (i64.const 19))))
    (set_local $h9 (i64.sub (get_local $h9) (i64.mul (get_local $carry9) (i64.shl (i64.const 1) (i64.const 25)))))

    (set_local $carry0 (i64.shr_s (i64.add (get_local $h0) (i64.shl (i64.const 1) (i64.const 25))) (i64.const 26)))
    (set_local $h1 (i64.add (get_local $h1) (get_local $carry0)))
    (set_local $h0 (i64.sub (get_local $h0) (i64.mul (get_local $carry0) (i64.shl (i64.const 1) (i64.const 26)))))

    (i64.store32 offset=0  (get_local $h) (get_local $h0))
    (i64.store32 offset=4  (get_local $h) (get_local $h1))
    (i64.store32 offset=8  (get_local $h) (get_local $h2))
    (i64.store32 offset=12 (get_local $h) (get_local $h3))
    (i64.store32 offset=16 (get_local $h) (get_local $h4))
    (i64.store32 offset=20 (get_local $h) (get_local $h5))
    (i64.store32 offset=24 (get_local $h) (get_local $h6))
    (i64.store32 offset=28 (get_local $h) (get_local $h7))
    (i64.store32 offset=32 (get_local $h) (get_local $h8))
    (i64.store32 offset=36 (get_local $h) (get_local $h9))))
