wardite 0.1.2 → 0.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: d27a05a105bd446883460d42c05cbec8502360dc686098368d59b1ae5e6e3e91
4
- data.tar.gz: d17f48eade8ac57845bf250583db7eb33dd9a418c315ba1083a7e0f598505298
3
+ metadata.gz: cefed459056cdf59c5c8823b1b4ef8ff53c84fd09a9f73883aaa291561ba4e00
4
+ data.tar.gz: b4ac97c31de3cc655aaf68d9c2097d1cb73ff67a184fd0c365d99b36371f1f93
5
5
  SHA512:
6
- metadata.gz: 21de2c67fd7aaaf04d55f028d304588a4f5c7f92b21ab4b7cb40dd7882103067db85401f41efc53b491996a82f109a9b11c05b0efa62e9622ad3971f6e254342
7
- data.tar.gz: 90542ce81cf6bf537eac6ddab087abab10842bfb24f153ba88865a7d2b5a0417c3e3fbab116e5ad2bedabc3d665810f34c0c8568a2baa2adbbdda89c681df076
6
+ metadata.gz: b3987aab13095263b109e7c907bee2640c3b9d2a5777b1b81812f692508de160d7fdd9f28e8c19c25d53445905e3b7b65379e0443f36dd56232e5c61b7d054bc
7
+ data.tar.gz: ca3e1e1b0390869ce69ddc880e574ff3fb6c75c7def7538ad628c121ea5c12e1c860dbadc960cbaba48841f6ab5be3f1eeb117e0822dd9488271eab0eb1745d9
data/Rakefile CHANGED
@@ -15,5 +15,183 @@ task :check do
15
15
  sh "bundle exec steep check"
16
16
  end
17
17
 
18
+ desc "Compile wat"
19
+ task :wasm, [:name] do |t, args|
20
+ Dir.chdir "examples" do
21
+ sh "wat2wasm #{args.name}.wat"
22
+ end
23
+ end
24
+
25
+ desc "Generate codes"
26
+ task :generate do
27
+ require_relative "scripts/gen_alu"
28
+ require_relative "scripts/gen_conv"
29
+ libdir = File.expand_path("../lib", __FILE__)
30
+
31
+ GenAlu.execute(libdir + "/wardite/alu_i32.generated.rb", prefix: "i32", defined_ops: [
32
+ :load,
33
+ :load8_s,
34
+ :load8_u,
35
+ :load16_s,
36
+ :load16_u,
37
+ :store,
38
+ :store8,
39
+ :store16,
40
+ :const,
41
+ :eqz,
42
+ :eq,
43
+ :ne,
44
+ :lts,
45
+ :ltu,
46
+ :gts,
47
+ :gtu,
48
+ :les,
49
+ :leu,
50
+ :ges,
51
+ :geu,
52
+ :clz,
53
+ :ctz,
54
+ :popcnt,
55
+ :add,
56
+ :sub,
57
+ :mul,
58
+ :div_s,
59
+ :div_u,
60
+ :rem_s,
61
+ :rem_u,
62
+ :and,
63
+ :or,
64
+ :xor,
65
+ :shl,
66
+ :shr_s,
67
+ :shr_u,
68
+ :rotl,
69
+ :rotr,
70
+ ])
71
+ GenAlu.execute(libdir + "/wardite/alu_i64.generated.rb", prefix: "i64", defined_ops: [
72
+ :load,
73
+ :load8_s,
74
+ :load8_u,
75
+ :load16_s,
76
+ :load16_u,
77
+ :load32_s,
78
+ :load32_u,
79
+ :store,
80
+ :store8,
81
+ :store16,
82
+ :store32,
83
+ :const,
84
+ :eqz,
85
+ :eq,
86
+ :ne,
87
+ :lts,
88
+ :ltu,
89
+ :gts,
90
+ :gtu,
91
+ :les,
92
+ :leu,
93
+ :ges,
94
+ :geu,
95
+ :clz,
96
+ :ctz,
97
+ :popcnt,
98
+ :add,
99
+ :sub,
100
+ :mul,
101
+ :div_s,
102
+ :div_u,
103
+ :rem_s,
104
+ :rem_u,
105
+ :and,
106
+ :or,
107
+ :xor,
108
+ :shl,
109
+ :shr_s,
110
+ :shr_u,
111
+ :rotl,
112
+ :rotr,
113
+ ])
114
+ GenAlu.execute(libdir + "/wardite/alu_f32.generated.rb", prefix: "f32", defined_ops: [
115
+ :load,
116
+ :store,
117
+ :const__f,
118
+ :eqz,
119
+ :eq,
120
+ :ne,
121
+ :lt,
122
+ :gt,
123
+ :le,
124
+ :ge,
125
+ :abs,
126
+ :neg,
127
+ :ceil,
128
+ :floor,
129
+ :trunc,
130
+ :nearest,
131
+ :sqrt,
132
+ :add,
133
+ :sub,
134
+ :mul,
135
+ :div,
136
+ :min,
137
+ :max,
138
+ :copysign,
139
+ ])
140
+ GenAlu.execute(libdir + "/wardite/alu_f64.generated.rb", prefix: "f64", defined_ops: [
141
+ :load,
142
+ :store,
143
+ :const__f,
144
+ :eqz,
145
+ :eq,
146
+ :ne,
147
+ :lt,
148
+ :gt,
149
+ :le,
150
+ :ge,
151
+ :abs,
152
+ :neg,
153
+ :ceil,
154
+ :floor,
155
+ :trunc,
156
+ :nearest,
157
+ :sqrt,
158
+ :add,
159
+ :sub,
160
+ :mul,
161
+ :div,
162
+ :min,
163
+ :max,
164
+ :copysign,
165
+ ])
166
+
167
+ GenConv.execute(libdir + "/wardite/convert.generated.rb", defined_ops: {
168
+ i32: {
169
+ wrap: [:i64],
170
+ trunc_s: [:f32, :f64],
171
+ trunc_u: [:f32, :f64],
172
+ reinterpret: [:f32],
173
+ },
174
+ i64: {
175
+ extend_s: [:i32, :i64],
176
+ extend_u: [:i32, :i64],
177
+ trunc_s: [:f32, :f64],
178
+ trunc_u: [:f32, :f64],
179
+ reinterpret: [:f64],
180
+ },
181
+ f32: {
182
+ convert_s: [:i32, :i64],
183
+ convert_u: [:i32, :i64],
184
+ demote: [:f64],
185
+ reinterpret: [:i32],
186
+ },
187
+ f64: {
188
+ convert_s: [:i32, :i64],
189
+ convert_u: [:i32, :i64],
190
+ promote: [:f32],
191
+ reinterpret: [:i64],
192
+ },
193
+ })
194
+ end
195
+
18
196
  task default: %i[test check]
19
197
 
data/Steepfile CHANGED
@@ -3,6 +3,7 @@ target :lib do
3
3
  signature "sig"
4
4
  check "lib"
5
5
 
6
+ library "pp"
6
7
  # configure_code_diagnostics(Steep::Diagnostic::Ruby.strict)
7
8
  end
8
9
 
@@ -0,0 +1,12 @@
1
+ (module
2
+ (func $test_const (result f32)
3
+ (i32.const 42)
4
+ (drop)
5
+ (i64.const 42)
6
+ (drop)
7
+ (f64.const 3.14)
8
+ (drop)
9
+ (f32.const 3.14)
10
+ )
11
+ (export "test_const" (func $test_const))
12
+ )
@@ -0,0 +1,250 @@
1
+ # rbs_inline: enabled
2
+ require_relative "value"
3
+
4
+ module Wardite
5
+ module Evaluator
6
+ # @rbs runtime: Runtime
7
+ # @rbs frame: Frame
8
+ # @rbs insn: Op
9
+ # @rbs return: void
10
+ def self.f32_eval_insn(runtime, frame, insn)
11
+ case insn.code
12
+
13
+ when :f32_load
14
+ _align = insn.operand[0] # TODO: alignment support?
15
+ offset = insn.operand[1]
16
+ raise EvalError, "[BUG] invalid type of operand" if !offset.is_a?(Integer)
17
+
18
+ addr = runtime.stack.pop
19
+ if !addr.is_a?(I32)
20
+ raise EvalError, "maybe stack too short"
21
+ end
22
+
23
+ at = addr.value + offset
24
+ data_end = at + F32.new.memsize / 8
25
+ memory = runtime.instance.store.memories[0] || raise("[BUG] no memory")
26
+ buf = memory.data[at...data_end]
27
+ if !buf
28
+ raise EvalError, "invalid memory range"
29
+ end
30
+ runtime.stack.push(F32.from_bytes(buf))
31
+
32
+
33
+ when :f32_store
34
+ _align = insn.operand[0] # TODO: alignment support?
35
+ offset = insn.operand[1]
36
+ raise EvalError, "[BUG] invalid type of operand" if !offset.is_a?(Integer)
37
+
38
+ value = runtime.stack.pop
39
+ addr = runtime.stack.pop
40
+ if !value.is_a?(F32) || !addr.is_a?(I32)
41
+ raise EvalError, "maybe stack too short"
42
+ end
43
+
44
+ at = addr.value + offset
45
+ data_end = at + value.packed.size
46
+ memory = runtime.instance.store.memories[0] || raise("[BUG] no memory")
47
+ memory.data[at...data_end] = value.packed
48
+
49
+
50
+ when :f32_const
51
+ const = insn.operand[0]
52
+ if !const.is_a?(Float)
53
+ raise EvalError, "invalid type of operand"
54
+ end
55
+ runtime.stack.push(F32(const))
56
+
57
+
58
+ when :f32_eqz
59
+ target = runtime.stack.pop
60
+ if !target.is_a?(F32)
61
+ raise EvalError, "maybe empty or invalid stack"
62
+ end
63
+ value = target.value.zero? ? 1 : 0
64
+ runtime.stack.push(I32(value))
65
+
66
+
67
+ when :f32_eq
68
+ right, left = runtime.stack.pop, runtime.stack.pop
69
+ if !right.is_a?(F32) || !left.is_a?(F32)
70
+ raise EvalError, "maybe empty or invalid stack"
71
+ end
72
+ value = (left.value == right.value) ? 1 : 0
73
+ runtime.stack.push(I32(value))
74
+
75
+
76
+ when :f32_ne
77
+ right, left = runtime.stack.pop, runtime.stack.pop
78
+ if !right.is_a?(F32) || !left.is_a?(F32)
79
+ raise EvalError, "maybe empty or invalid stack"
80
+ end
81
+ value = (left.value != right.value) ? 1 : 0
82
+ runtime.stack.push(I32(value))
83
+
84
+
85
+ when :f32_lt
86
+ right, left = runtime.stack.pop, runtime.stack.pop
87
+ if !right.is_a?(F32) || !left.is_a?(F32)
88
+ raise EvalError, "maybe empty or invalid stack"
89
+ end
90
+ value = (left.value < right.value) ? 1 : 0
91
+ runtime.stack.push(I32(value))
92
+
93
+
94
+ when :f32_gt
95
+ right, left = runtime.stack.pop, runtime.stack.pop
96
+ if !right.is_a?(F32) || !left.is_a?(F32)
97
+ raise EvalError, "maybe empty or invalid stack"
98
+ end
99
+ value = (left.value > right.value) ? 1 : 0
100
+ runtime.stack.push(I32(value))
101
+
102
+
103
+ when :f32_le
104
+ right, left = runtime.stack.pop, runtime.stack.pop
105
+ if !right.is_a?(F32) || !left.is_a?(F32)
106
+ raise EvalError, "maybe empty or invalid stack"
107
+ end
108
+ value = (left.value <= right.value) ? 1 : 0
109
+ runtime.stack.push(I32(value))
110
+
111
+
112
+ when :f32_ge
113
+ right, left = runtime.stack.pop, runtime.stack.pop
114
+ if !right.is_a?(F32) || !left.is_a?(F32)
115
+ raise EvalError, "maybe empty or invalid stack"
116
+ end
117
+ value = (left.value >= right.value) ? 1 : 0
118
+ runtime.stack.push(I32(value))
119
+
120
+
121
+ when :f32_abs
122
+ x = runtime.stack.pop
123
+ if !x.is_a?(F32)
124
+ raise EvalError, "maybe empty or invalid stack"
125
+ end
126
+ runtime.stack.push(F32(x.value.abs))
127
+
128
+
129
+ when :f32_neg
130
+ x = runtime.stack.pop
131
+ if !x.is_a?(F32)
132
+ raise EvalError, "maybe empty or invalid stack"
133
+ end
134
+ runtime.stack.push(F32(-(x.value)))
135
+
136
+
137
+ when :f32_ceil
138
+ x = runtime.stack.pop
139
+ if !x.is_a?(F32)
140
+ raise EvalError, "maybe empty or invalid stack"
141
+ end
142
+ runtime.stack.push(F32(x.value.ceil.to_f))
143
+
144
+
145
+ when :f32_floor
146
+ x = runtime.stack.pop
147
+ if !x.is_a?(F32)
148
+ raise EvalError, "maybe empty or invalid stack"
149
+ end
150
+ runtime.stack.push(F32(x.value.floor.to_f))
151
+
152
+
153
+ when :f32_trunc
154
+ x = runtime.stack.pop
155
+ if !x.is_a?(F32)
156
+ raise EvalError, "maybe empty or invalid stack"
157
+ end
158
+ runtime.stack.push(F32(x.value.to_i.to_f))
159
+
160
+
161
+ when :f32_nearest
162
+ x = runtime.stack.pop
163
+ if !x.is_a?(F32)
164
+ raise EvalError, "maybe empty or invalid stack"
165
+ end
166
+ runtime.stack.push(F32(x.value.round.to_f))
167
+
168
+
169
+ when :f32_sqrt
170
+ x = runtime.stack.pop
171
+ if !x.is_a?(F32)
172
+ raise EvalError, "maybe empty or invalid stack"
173
+ end
174
+ runtime.stack.push(F32(x.value ** 0.5))
175
+
176
+
177
+ when :f32_add
178
+ right, left = runtime.stack.pop, runtime.stack.pop
179
+ if !right.is_a?(F32) || !left.is_a?(F32)
180
+ raise EvalError, "maybe empty or invalid stack"
181
+ end
182
+ runtime.stack.push(F32(left.value + right.value))
183
+
184
+
185
+ when :f32_sub
186
+ right, left = runtime.stack.pop, runtime.stack.pop
187
+ if !right.is_a?(F32) || !left.is_a?(F32)
188
+ raise EvalError, "maybe empty or invalid stack"
189
+ end
190
+ runtime.stack.push(F32(left.value - right.value))
191
+
192
+
193
+ when :f32_mul
194
+ right, left = runtime.stack.pop, runtime.stack.pop
195
+ if !right.is_a?(F32) || !left.is_a?(F32)
196
+ raise EvalError, "maybe empty or invalid stack"
197
+ end
198
+ runtime.stack.push(F32(left.value * right.value))
199
+
200
+
201
+ when :f32_div
202
+ right, left = runtime.stack.pop, runtime.stack.pop
203
+ if !right.is_a?(F32) || !left.is_a?(F32)
204
+ raise EvalError, "maybe empty or invalid stack"
205
+ end
206
+ runtime.stack.push(F32(left.value / right.value))
207
+
208
+
209
+ when :f32_min
210
+ right, left = runtime.stack.pop, runtime.stack.pop
211
+ if !right.is_a?(F32) || !left.is_a?(F32)
212
+ raise EvalError, "maybe empty or invalid stack"
213
+ end
214
+ if right.value.nan? || left.value.nan?
215
+ runtime.stack.push(F32(Float::NAN))
216
+ return
217
+ end
218
+ runtime.stack.push(F32([left.value, right.value].min))
219
+
220
+
221
+ when :f32_max
222
+ right, left = runtime.stack.pop, runtime.stack.pop
223
+ if !right.is_a?(F32) || !left.is_a?(F32)
224
+ raise EvalError, "maybe empty or invalid stack"
225
+ end
226
+ if right.value.nan? || left.value.nan?
227
+ runtime.stack.push(F32(Float::NAN))
228
+ return
229
+ end
230
+ runtime.stack.push(F32([left.value, right.value].max))
231
+
232
+
233
+ when :f32_copysign
234
+ right, left = runtime.stack.pop, runtime.stack.pop
235
+ if !right.is_a?(F32) || !left.is_a?(F32)
236
+ raise EvalError, "maybe empty or invalid stack"
237
+ end
238
+ if left.sign == right.sign
239
+ runtime.stack.push(F32(left.value))
240
+ else
241
+ runtime.stack.push(F32(-left.value))
242
+ end
243
+
244
+
245
+ else
246
+ raise "Unknown opcode for namespace #{insn.namespace}: #{insn.code}"
247
+ end
248
+ end
249
+ end
250
+ end
@@ -0,0 +1,250 @@
1
+ # rbs_inline: enabled
2
+ require_relative "value"
3
+
4
+ module Wardite
5
+ module Evaluator
6
+ # @rbs runtime: Runtime
7
+ # @rbs frame: Frame
8
+ # @rbs insn: Op
9
+ # @rbs return: void
10
+ def self.f64_eval_insn(runtime, frame, insn)
11
+ case insn.code
12
+
13
+ when :f64_load
14
+ _align = insn.operand[0] # TODO: alignment support?
15
+ offset = insn.operand[1]
16
+ raise EvalError, "[BUG] invalid type of operand" if !offset.is_a?(Integer)
17
+
18
+ addr = runtime.stack.pop
19
+ if !addr.is_a?(I32)
20
+ raise EvalError, "maybe stack too short"
21
+ end
22
+
23
+ at = addr.value + offset
24
+ data_end = at + F64.new.memsize / 8
25
+ memory = runtime.instance.store.memories[0] || raise("[BUG] no memory")
26
+ buf = memory.data[at...data_end]
27
+ if !buf
28
+ raise EvalError, "invalid memory range"
29
+ end
30
+ runtime.stack.push(F64.from_bytes(buf))
31
+
32
+
33
+ when :f64_store
34
+ _align = insn.operand[0] # TODO: alignment support?
35
+ offset = insn.operand[1]
36
+ raise EvalError, "[BUG] invalid type of operand" if !offset.is_a?(Integer)
37
+
38
+ value = runtime.stack.pop
39
+ addr = runtime.stack.pop
40
+ if !value.is_a?(F64) || !addr.is_a?(I32)
41
+ raise EvalError, "maybe stack too short"
42
+ end
43
+
44
+ at = addr.value + offset
45
+ data_end = at + value.packed.size
46
+ memory = runtime.instance.store.memories[0] || raise("[BUG] no memory")
47
+ memory.data[at...data_end] = value.packed
48
+
49
+
50
+ when :f64_const
51
+ const = insn.operand[0]
52
+ if !const.is_a?(Float)
53
+ raise EvalError, "invalid type of operand"
54
+ end
55
+ runtime.stack.push(F64(const))
56
+
57
+
58
+ when :f64_eqz
59
+ target = runtime.stack.pop
60
+ if !target.is_a?(F64)
61
+ raise EvalError, "maybe empty or invalid stack"
62
+ end
63
+ value = target.value.zero? ? 1 : 0
64
+ runtime.stack.push(I32(value))
65
+
66
+
67
+ when :f64_eq
68
+ right, left = runtime.stack.pop, runtime.stack.pop
69
+ if !right.is_a?(F64) || !left.is_a?(F64)
70
+ raise EvalError, "maybe empty or invalid stack"
71
+ end
72
+ value = (left.value == right.value) ? 1 : 0
73
+ runtime.stack.push(I32(value))
74
+
75
+
76
+ when :f64_ne
77
+ right, left = runtime.stack.pop, runtime.stack.pop
78
+ if !right.is_a?(F64) || !left.is_a?(F64)
79
+ raise EvalError, "maybe empty or invalid stack"
80
+ end
81
+ value = (left.value != right.value) ? 1 : 0
82
+ runtime.stack.push(I32(value))
83
+
84
+
85
+ when :f64_lt
86
+ right, left = runtime.stack.pop, runtime.stack.pop
87
+ if !right.is_a?(F64) || !left.is_a?(F64)
88
+ raise EvalError, "maybe empty or invalid stack"
89
+ end
90
+ value = (left.value < right.value) ? 1 : 0
91
+ runtime.stack.push(I32(value))
92
+
93
+
94
+ when :f64_gt
95
+ right, left = runtime.stack.pop, runtime.stack.pop
96
+ if !right.is_a?(F64) || !left.is_a?(F64)
97
+ raise EvalError, "maybe empty or invalid stack"
98
+ end
99
+ value = (left.value > right.value) ? 1 : 0
100
+ runtime.stack.push(I32(value))
101
+
102
+
103
+ when :f64_le
104
+ right, left = runtime.stack.pop, runtime.stack.pop
105
+ if !right.is_a?(F64) || !left.is_a?(F64)
106
+ raise EvalError, "maybe empty or invalid stack"
107
+ end
108
+ value = (left.value <= right.value) ? 1 : 0
109
+ runtime.stack.push(I32(value))
110
+
111
+
112
+ when :f64_ge
113
+ right, left = runtime.stack.pop, runtime.stack.pop
114
+ if !right.is_a?(F64) || !left.is_a?(F64)
115
+ raise EvalError, "maybe empty or invalid stack"
116
+ end
117
+ value = (left.value >= right.value) ? 1 : 0
118
+ runtime.stack.push(I32(value))
119
+
120
+
121
+ when :f64_abs
122
+ x = runtime.stack.pop
123
+ if !x.is_a?(F64)
124
+ raise EvalError, "maybe empty or invalid stack"
125
+ end
126
+ runtime.stack.push(F64(x.value.abs))
127
+
128
+
129
+ when :f64_neg
130
+ x = runtime.stack.pop
131
+ if !x.is_a?(F64)
132
+ raise EvalError, "maybe empty or invalid stack"
133
+ end
134
+ runtime.stack.push(F64(-(x.value)))
135
+
136
+
137
+ when :f64_ceil
138
+ x = runtime.stack.pop
139
+ if !x.is_a?(F64)
140
+ raise EvalError, "maybe empty or invalid stack"
141
+ end
142
+ runtime.stack.push(F64(x.value.ceil.to_f))
143
+
144
+
145
+ when :f64_floor
146
+ x = runtime.stack.pop
147
+ if !x.is_a?(F64)
148
+ raise EvalError, "maybe empty or invalid stack"
149
+ end
150
+ runtime.stack.push(F64(x.value.floor.to_f))
151
+
152
+
153
+ when :f64_trunc
154
+ x = runtime.stack.pop
155
+ if !x.is_a?(F64)
156
+ raise EvalError, "maybe empty or invalid stack"
157
+ end
158
+ runtime.stack.push(F64(x.value.to_i.to_f))
159
+
160
+
161
+ when :f64_nearest
162
+ x = runtime.stack.pop
163
+ if !x.is_a?(F64)
164
+ raise EvalError, "maybe empty or invalid stack"
165
+ end
166
+ runtime.stack.push(F64(x.value.round.to_f))
167
+
168
+
169
+ when :f64_sqrt
170
+ x = runtime.stack.pop
171
+ if !x.is_a?(F64)
172
+ raise EvalError, "maybe empty or invalid stack"
173
+ end
174
+ runtime.stack.push(F64(x.value ** 0.5))
175
+
176
+
177
+ when :f64_add
178
+ right, left = runtime.stack.pop, runtime.stack.pop
179
+ if !right.is_a?(F64) || !left.is_a?(F64)
180
+ raise EvalError, "maybe empty or invalid stack"
181
+ end
182
+ runtime.stack.push(F64(left.value + right.value))
183
+
184
+
185
+ when :f64_sub
186
+ right, left = runtime.stack.pop, runtime.stack.pop
187
+ if !right.is_a?(F64) || !left.is_a?(F64)
188
+ raise EvalError, "maybe empty or invalid stack"
189
+ end
190
+ runtime.stack.push(F64(left.value - right.value))
191
+
192
+
193
+ when :f64_mul
194
+ right, left = runtime.stack.pop, runtime.stack.pop
195
+ if !right.is_a?(F64) || !left.is_a?(F64)
196
+ raise EvalError, "maybe empty or invalid stack"
197
+ end
198
+ runtime.stack.push(F64(left.value * right.value))
199
+
200
+
201
+ when :f64_div
202
+ right, left = runtime.stack.pop, runtime.stack.pop
203
+ if !right.is_a?(F64) || !left.is_a?(F64)
204
+ raise EvalError, "maybe empty or invalid stack"
205
+ end
206
+ runtime.stack.push(F64(left.value / right.value))
207
+
208
+
209
+ when :f64_min
210
+ right, left = runtime.stack.pop, runtime.stack.pop
211
+ if !right.is_a?(F64) || !left.is_a?(F64)
212
+ raise EvalError, "maybe empty or invalid stack"
213
+ end
214
+ if right.value.nan? || left.value.nan?
215
+ runtime.stack.push(F64(Float::NAN))
216
+ return
217
+ end
218
+ runtime.stack.push(F64([left.value, right.value].min))
219
+
220
+
221
+ when :f64_max
222
+ right, left = runtime.stack.pop, runtime.stack.pop
223
+ if !right.is_a?(F64) || !left.is_a?(F64)
224
+ raise EvalError, "maybe empty or invalid stack"
225
+ end
226
+ if right.value.nan? || left.value.nan?
227
+ runtime.stack.push(F64(Float::NAN))
228
+ return
229
+ end
230
+ runtime.stack.push(F64([left.value, right.value].max))
231
+
232
+
233
+ when :f64_copysign
234
+ right, left = runtime.stack.pop, runtime.stack.pop
235
+ if !right.is_a?(F64) || !left.is_a?(F64)
236
+ raise EvalError, "maybe empty or invalid stack"
237
+ end
238
+ if left.sign == right.sign
239
+ runtime.stack.push(F64(left.value))
240
+ else
241
+ runtime.stack.push(F64(-left.value))
242
+ end
243
+
244
+
245
+ else
246
+ raise "Unknown opcode for namespace #{insn.namespace}: #{insn.code}"
247
+ end
248
+ end
249
+ end
250
+ end