@@ -29,7 +29,7 @@ void emitter::emitIns(instruction ins)
2929// ------------------------------------------------------------------------
3030// emitIns_I: Emit an instruction with an immediate operand.
3131//
32- void emitter::emitIns_I (instruction ins, emitAttr attr, target_ssize_t imm)
32+ void emitter::emitIns_I (instruction ins, emitAttr attr, cnsval_ssize_t imm)
3333{
3434 instrDesc* id = emitNewInstrSC (attr, imm);
3535 insFormat fmt = emitInsFormat (ins);
@@ -59,7 +59,7 @@ void emitter::emitIns_R(instruction ins, emitAttr attr, regNumber reg)
5959 NYI_WASM (" emitIns_R" );
6060}
6161
62- void emitter::emitIns_R_I (instruction ins, emitAttr attr, regNumber reg, ssize_t imm)
62+ void emitter::emitIns_R_I (instruction ins, emitAttr attr, regNumber reg, cnsval_ssize_t imm)
6363{
6464 NYI_WASM (" emitIns_R_I" );
6565}
@@ -124,7 +124,13 @@ size_t emitter::emitSizeOfInsDsc(instrDesc* id) const
124124 return sizeof (instrDesc);
125125}
126126
127- static unsigned SizeOfULEB128 (uint64_t value)
127+ unsigned emitter::emitGetAlignHintLog2 (const instrDesc* id)
128+ {
129+ // FIXME
130+ return 0 ;
131+ }
132+
133+ unsigned emitter::SizeOfULEB128 (uint64_t value)
128134{
129135 // bits_to_encode = (data != 0) ? 64 - CLZ(x) : 1 = 64 - CLZ(data | 1)
130136 // bytes = ceil(bits_to_encode / 7.0); = (6 + bits_to_encode) / 7
@@ -134,6 +140,13 @@ static unsigned SizeOfULEB128(uint64_t value)
134140 return (x * 37 ) >> 8 ;
135141}
136142
143+ unsigned emitter::SizeOfSLEB128 (int64_t value)
144+ {
145+ // The same as SizeOfULEB128 calculation but we have to account for the sign bit.
146+ unsigned x = 1 + 6 + 64 - (unsigned )BitOperations::LeadingZeroCount ((uint64_t )(value ^ (value >> 63 )) | 1UL );
147+ return (x * 37 ) >> 8 ;
148+ }
149+
137150unsigned emitter::instrDesc::idCodeSize () const
138151{
139152#ifdef TARGET_WASM32
@@ -154,15 +167,28 @@ unsigned emitter::instrDesc::idCodeSize() const
154167 break ;
155168 case IF_LABEL:
156169 assert (!idIsCnsReloc ());
157- size = SizeOfULEB128 (static_cast < target_size_t >( emitGetInsSC (this ) ));
170+ size = SizeOfULEB128 (emitGetInsSC (this ));
158171 break ;
159172 case IF_ULEB128:
160- size += idIsCnsReloc () ? PADDED_RELOC_SIZE : SizeOfULEB128 (static_cast <target_size_t >(emitGetInsSC (this )));
173+ size += idIsCnsReloc () ? PADDED_RELOC_SIZE : SizeOfULEB128 (emitGetInsSC (this ));
174+ break ;
175+ case IF_SLEB128:
176+ size += idIsCnsReloc () ? PADDED_RELOC_SIZE : SizeOfSLEB128 (emitGetInsSC (this ));
177+ break ;
178+ case IF_F32:
179+ size += 4 ;
180+ break ;
181+ case IF_F64:
182+ size += 8 ;
161183 break ;
162184 case IF_MEMARG:
163- size += 1 ; // The alignment hint byte.
164- size += idIsCnsReloc () ? PADDED_RELOC_SIZE : SizeOfULEB128 (static_cast <target_size_t >(emitGetInsSC (this )));
185+ {
186+ uint64_t align = emitGetAlignHintLog2 (this );
187+ assert (align < 64 ); // spec says align > 2^6 produces a memidx for multiple memories.
188+ size += SizeOfULEB128 (align);
189+ size += idIsCnsReloc () ? PADDED_RELOC_SIZE : SizeOfULEB128 (emitGetInsSC (this ));
165190 break ;
191+ }
166192 default :
167193 unreached ();
168194 }
@@ -174,6 +200,56 @@ void emitter::emitSetShortJump(instrDescJmp* id)
174200 NYI_WASM (" emitSetShortJump" );
175201}
176202
203+ size_t emitter::emitOutputULEB128 (uint8_t * destination, uint64_t value)
204+ {
205+ uint8_t * buffer = destination + writeableOffset;
206+ if (value >= 0x80 )
207+ {
208+ int pos = 0 ;
209+ do
210+ {
211+ buffer[pos++] = (uint8_t )((value & 0x7F ) | ((value >= 0x80 ) ? 0x80u : 0 ));
212+ value >>= 7 ;
213+ } while (value > 0 );
214+
215+ return pos;
216+ }
217+ else
218+ {
219+ buffer[0 ] = (uint8_t )value;
220+ return 1 ;
221+ }
222+ }
223+
224+ size_t emitter::emitOutputSLEB128 (uint8_t * destination, int64_t value)
225+ {
226+ uint8_t * buffer = destination + writeableOffset;
227+ bool cont = true ;
228+ int pos = 0 ;
229+ while (cont)
230+ {
231+ uint8_t b = ((uint8_t )value & 0x7F );
232+ value >>= 7 ;
233+ bool isSignBitSet = (b & 0x40 ) != 0 ;
234+ if ((value == 0 && !isSignBitSet) || (value == -1 && isSignBitSet))
235+ {
236+ cont = false ;
237+ }
238+ else
239+ {
240+ b |= 0x80 ;
241+ }
242+ buffer[pos++] = b;
243+ }
244+ return pos;
245+ }
246+
247+ size_t emitter::emitRawBytes (uint8_t * destination, const void * source, size_t count)
248+ {
249+ memcpy (destination + writeableOffset, source, count);
250+ return count;
251+ }
252+
177253size_t emitter::emitOutputInstr (insGroup* ig, instrDesc* id, BYTE** dp)
178254{
179255 BYTE* dst = *dp;
@@ -189,16 +265,61 @@ size_t emitter::emitOutputInstr(insGroup* ig, instrDesc* id, BYTE** dp)
189265 break ;
190266 case IF_BLOCK:
191267 dst += emitOutputByte (dst, opcode);
192- dst += emitOutputByte (dst, 0x40 );
268+ dst += emitOutputByte (dst, 0x40 /* block type of void */ );
193269 break ;
194270 case IF_ULEB128:
271+ {
272+ dst += emitOutputByte (dst, opcode);
273+ cnsval_ssize_t constant = emitGetInsSC (id);
274+ dst += emitOutputULEB128 (dst, (uint64_t )constant);
275+ break ;
276+ }
277+ case IF_SLEB128:
278+ {
279+ dst += emitOutputByte (dst, opcode);
280+ cnsval_ssize_t constant = emitGetInsSC (id);
281+ dst += emitOutputSLEB128 (dst, (int64_t )constant);
282+ break ;
283+ }
284+ case IF_F32:
285+ {
286+ dst += emitOutputByte (dst, opcode);
287+ // Reinterpret the bits as a double constant and then truncate it to f32,
288+ // then finally copy the raw truncated f32 bits to the output.
289+ cnsval_ssize_t bits = emitGetInsSC (id);
290+ double value;
291+ float truncated;
292+ memcpy (&value, &bits, sizeof (double ));
293+ truncated = FloatingPointUtils::convertToSingle (value);
294+ dst += emitRawBytes (dst, &truncated, sizeof (float ));
295+ break ;
296+ }
297+ case IF_F64:
298+ {
195299 dst += emitOutputByte (dst, opcode);
196- // TODO-WASM: emit uleb128
300+ // The int64 bits are actually a double constant we can copy directly
301+ // to the output stream.
302+ cnsval_ssize_t bits = emitGetInsSC (id);
303+ dst += emitRawBytes (dst, &bits, sizeof (cnsval_ssize_t ));
197304 break ;
305+ }
198306 case IF_LABEL:
199- // TODO-WASM: emit uleb128
307+ NYI_WASM (" emitOutputInstr IF_LABEL" );
308+ break ;
309+ case IF_MEMARG:
310+ {
311+ dst += emitOutputByte (dst, opcode);
312+ uint64_t align = emitGetAlignHintLog2 (id);
313+ uint64_t offset = emitGetInsSC (id);
314+ assert (align <= UINT32_MAX); // spec says memarg alignment is u32
315+ assert (align < 64 ); // spec says align > 2^6 produces a memidx for multiple memories.
316+ dst += emitOutputULEB128 (dst, align);
317+ dst += emitOutputULEB128 (dst, offset);
318+ break ;
319+ }
200320 default :
201321 NYI_WASM (" emitOutputInstr" );
322+ break ;
202323 }
203324
204325#ifdef DEBUG
@@ -301,17 +422,34 @@ void emitter::emitDispIns(
301422 case IF_LABEL:
302423 case IF_ULEB128:
303424 {
304- target_size_t imm = emitGetInsSC (id);
305- printf (" %u" , imm);
425+ cnsval_ssize_t imm = emitGetInsSC (id);
426+ printf (" %llu" , (uint64_t )imm);
427+ }
428+ break ;
429+
430+ case IF_SLEB128:
431+ {
432+ cnsval_ssize_t imm = emitGetInsSC (id);
433+ printf (" %lli" , (int64_t )imm);
434+ }
435+ break ;
436+
437+ case IF_F32:
438+ case IF_F64:
439+ {
440+ cnsval_ssize_t bits = emitGetInsSC (id);
441+ double value;
442+ memcpy (&value, &bits, sizeof (double ));
443+ printf (" %f" , value);
306444 }
307445 break ;
308446
309447 case IF_MEMARG:
310448 {
311449 // TODO-WASM: decide what our strategy for alignment hints is and display these accordingly.
312- unsigned log2align = 1 ;
313- target_size_t offset = emitGetInsSC (id);
314- printf (" %u %u " , log2align, offset);
450+ unsigned log2align = emitGetAlignHintLog2 (id) + 1 ;
451+ cnsval_ssize_t offset = emitGetInsSC (id);
452+ printf (" %u %llu " , log2align, ( uint64_t ) offset);
315453 }
316454 break ;
317455
0 commit comments