Przeglądaj źródła

[PATCH 173/188] changed from using textual format of operand to
binary

From e855f0b9ce6fe4c156bb48c41d76d588c3caf987 Mon Sep 17 00:00:00 2001
From: Dmitry Boyarintsev <[email protected]>
Date: Thu, 2 Apr 2020 11:45:18 -0400

git-svn-id: branches/wasm@46169 -

nickysn 5 lat temu
rodzic
commit
b710b84191

+ 2 - 0
utils/wasmbin/wasmbincode.pas

@@ -210,6 +210,8 @@ type
     ipOfsAlign,  // memory arguments, ask for offset + align
     ipi32,       // signed Leb of maximum 4 bytes
     ipi64,       // signed Leb of maximum 8 bytes
+    ipu32,       // unsigned Leb of maximum 4 bytes
+    ipu64,       // unsigned Leb of maximum 8 bytes
     ipf32,       // float point single
     ipf64,       // float point double
     ipJumpVec,   // an array of jump labels used for br_table only

+ 10 - 256
utils/wasmbin/wasmbinwriter.pas

@@ -607,248 +607,6 @@ begin
   end;
 end;
 
-function WriteI32Operand(dst: TStream; const operand: string): Boolean;
-var
-  err : integer;
-  i32 : integer;
-  u32 : LongWord;
-begin
-  Val(operand, i32, err);
-  if err = 0 then begin
-    WriteS( dst, i32, sizeof(i32));
-    Result := true;
-    Exit;
-  end else
-    Val(operand, u32, err);
-
-  Result := (err = 0);
-  if Result then WriteU32(dst, u32);
-end;
-
-procedure WriteAlign(dst: TStream; const operand: string);
-var
-  m : Integer;
-begin
-  m := 0;
-  if (length(operand)=1) then
-    case operand[1] of
-      '1': m := 0;
-      '2': m := 1;
-      '4': m := 2;
-      '8': m := 3;
-    end;
-  WriteU32(dst, m);
-end;
-
-function WriteI64Operand(dst: TStream; const operand: string): Boolean;
-var
-  err : integer;
-  i64 : Int64;
-  u64 : UInt64;
-begin
-  Val(operand, i64, err);
-  if err = 0 then begin
-    WriteS64(dst, i64);
-    Result := true;
-    //Exit;
-    //u64 := UInt64(i64)
-  end else begin
-    Val(operand, u64, err);
-    if Result then WriteS64(dst, Int64(u64));
-  end;
-  Result := (err = 0);
-end;
-
-type
-  THexStr = record
-    num   : QWord;
-    frac  : QWord;
-    exp   : integer;
-    isNeg : Boolean;
-  end;
-
-function HexFloatStrToHexStr(const t: string; out hexStr: THexStr): Boolean;
-var
-  i : integer;
-  j : integer;
-  err : Integer;
-const
-  HexChars = ['0'..'9','a'..'f','A'..'F'];
-begin
-  hexStr.isNeg:=false;
-  hexStr.num:=0;
-  hexStr.frac:=0;
-  hexStr.exp:=0;
-  if (t='') then begin
-    Result:=true;
-    Exit;
-  end;
-
-  i:=1;
-  hexStr.isNeg:=t[i]='-';
-  if (hexStr.isNeg) then inc(i);
-  inc(i,2); // skipping '0x'
-
-  j:=i;
-  while (i<=length(t)) and (t[i] in HexChars) do inc(i);
-  Val('$'+Copy(t, j, i-j), hexStr.num, err);
-  Result:=err=0;
-  if not Result then Exit;
-
-  if (t[i]='.') then begin
-    inc(i);
-    j:=i;
-    while (i<=length(t)) and (t[i] in HexChars) do inc(i);
-    Val('$'+Copy(t, j, i-j), hexStr.frac, err);
-    Result:=err=0;
-    if not Result then Exit;
-  end;
-
-  Result := (i<=length(t)) and (t[i] = 'p') or (t[i]='P');
-  inc(i);
-  Val(Copy(t, i, length(t)), hexStr.exp, err);
-  Result:=err=0;
-end;
-
-function HexFracToSingle(const num, frac: QWord; exp: Integer; isNeg: Boolean): Single;
-var
-  x      : QWord;
-  nm     : QWord;
-  adjexp : integer;
-  sr     : TSingleRec;
-begin
-  nm := num;
-  x := frac;
-  adjexp := -1;
-  while (nm > 0) do begin
-    x:=(x shr 1) or ((nm and 1) shl 23);
-    nm := nm shr 1;
-    inc(adjexp);
-  end;
-  sr.Exp:=127 + exp + adjexp;
-  sr.Frac:=x;
-  sr.Sign:=isNeg;
-  Result := sr.Value;
-end;
-
-function HexFloatStrToSingle(const hexstr: string): Single;
-var
-  st : THexStr;
-begin
-  HexFloatStrToHexStr(hexstr, st);
-  Result:=HexFracToSingle(st.num, st.frac, st.exp, st.isNeg);
-end;
-
-function HexFracToDouble(const num, frac: QWord; exp: Integer; neg: Boolean): Double;
-var
-  x      : QWord;
-  nm     : QWord;
-  adjexp : integer;
-  sr     : TDoubleRec;
-begin
-  nm := num;
-  x := frac;
-  adjexp := 0;
-  while (nm > 1) do begin
-    x:=(x shr 1) or ((nm and 1) shl 52);
-    nm := nm shr 1;
-    inc(adjexp);
-  end;
-  sr.Exp:=1023 + exp + adjexp;
-  sr.Frac:=x;
-  sr.Sign:=neg;
-  Result := sr.Value;
-end;
-
-function HexFloatStrToDouble(const hexstr: string): double;
-var
-  st : THexStr;
-begin
-  HexFloatStrToHexStr(hexstr, st);
-  Result:=HexFracToDouble(st.num, st.frac, st.exp, st.isNeg);
-end;
-
-procedure WriteF32Operand(dst: TStream; const txt: string);
-var
-  f   : single;
-  err : integer;
-  l   : LongWord;
-  i   : Integer;
-  hx  : string;
-  hl  : LongWord;
-  p   : Integer;
-  ft  : string;
-const
-  BINARY_INF    = $7f800000;
-  BINARY_NEGINF = $ff800000;
-  BINARY_NEGMAN = $00400000;
-begin
-  // val() doesn't handle "nan" in wasm compatible
-  // any "nan" is always returned as "negative nan" (in Wasm terms)
-  // "inf" works just fine
-  if (Pos('nan', txt)>0) then begin
-    if txt[1]='-' then l := NtoLE(BINARY_NEGINF)
-    else l := NtoLE(BINARY_INF);
-
-    i:=Pos(':', txt);
-    if i>0 then begin
-      hx := '$'+Copy(txt, i+3, length(txt)); // skipping '0x'
-      Val(hx, hl, err);
-    end else
-      hl:=BINARY_NEGMAN; // nan
-    l:=l or hl;
-    dst.Write(l, sizeof(l));
-  end else begin
-    f:=0;
-    err:=0;
-    if (Pos('0x', txt)>0) then
-      f := HexFloatStrToSingle(txt)
-    else
-      Val(txt, f, err);
-
-    dst.Write(f, sizeof(f));
-  end;
-end;
-
-procedure WriteF64Operand(dst: TStream; const txt: string);
-var
-  f   : double;
-  err : integer;
-  l   : QWord;
-  i   : Integer;
-  hx  : string;
-  hl  : QWord;
-const
-  BINARY_INF    = QWord($7ff0000000000000);
-  BINARY_NEGINF = QWord($fff0000000000000);
-  BINARY_NEGMAN = QWord($0008000000000000);
-begin
-  if (Pos('nan', txt)>0) then begin
-    if txt[1]='-' then l := NtoLE(BINARY_NEGINF)
-    else l := NtoLE(BINARY_INF);
-
-    i:=Pos(':', txt);
-    if i>0 then begin
-      hx := '$'+Copy(txt, i+3, length(txt)); // skipping '0x'
-      Val(hx, hl, err);
-    end else
-      hl:=BINARY_NEGMAN; // nan
-    l:=l or hl;
-    dst.Write(l, sizeof(l));
-  end else begin
-    f:=0;
-    if (Pos('0x', txt)>0) then
-    begin
-      writeln('txt=',txt);
-      f := HexFloatStrToDouble(txt)
-    end
-    else
-      Val(txt, f, err);
-    dst.Write(f, sizeof(f));
-  end;
-end;
-
-
 procedure TBinWriter.WriteInstList(list: TWasmInstrList; ofsAddition: LongWord);
 var
   i   : integer;
@@ -868,23 +626,19 @@ begin
     end;
 
     case INST_FLAGS[ci.code].Param of
-      ipi32: begin
-        WriteI32Operand(dst, ci.operandText);
-      end;
-
-      ipi64: begin     // signed Leb of maximum 8 bytes
-        WriteI64Operand(dst, ci.operandText);
-      end;
-
-      ipf32: WriteF32Operand(dst, ci.operandText);
-      ipf64: WriteF64Operand(dst, ci.operandText);
+      ipi32: WriteS(dst, ci.operand1.s32, sizeof(ci.operand1.s32));
+      ipi64: WriteS64(dst, ci.operand1.s64);
+      ipu32: WriteU32(dst, ci.operand1.u32);
+      ipu64: WriteS64(dst, Int64(ci.operand1.u64));
+      ipf32: dst.Write(ci.operand1.f32, sizeof(ci.operand1.f32));
+      ipf64: dst.Write(ci.operand1.f64, sizeof(ci.operand1.f64));
 
       ipi32OrFunc: begin
         if ci.hasRelocIdx then
           // should have been populated with Normalize
-          WriteRelocU32(LongWord(ci.operandNum))
+          WriteRelocU32(LongWord(ci.operand1.u32)) // todo!
         else
-          WriteI32Operand(dst, ci.operandText);
+          WriteS(dst, ci.operand1.s32, sizeof(ci.operand1.s32));
       end;
       //ipf32,     // float point single
       //ipf64,     // float point double
@@ -925,9 +679,9 @@ begin
 
       ipOfsAlign: begin
         // align
-        WriteAlign(dst, ci.alignText);
+        WriteU32(dst, ci.operand2.u32);
         // offset
-        WriteI32Operand(dst, ci.offsetText);
+        WriteU32(dst, ci.operand1.u32);
       end;
     end;
   end;

+ 53 - 10
utils/wasmbin/wasmmodule.pas

@@ -69,16 +69,39 @@ type
     procedure CopyTo(t: TWasmFuncType);
   end;
 
+
+  TWasmInstrOperandType = (
+     otNotused,
+     otText,
+     otSInt32,
+     otUInt32,
+     otSInt64,
+     otUInt64,
+     otFloat32,
+     otFloat64
+  );
+
+  TWasmInstrOperand = record
+     textVal : string;
+     case tp : TWasmInstrOperandType of
+       otSInt32: (s32: Int32);
+       otUInt32: (u32: UInt32);
+       otSInt64: (s64: Int64);
+       otUInt64: (u64: UInt64);
+       otFloat32: (f32: single);
+       otFloat64: (f64: double);
+  end;
+
   { TWasmInstr }
 
   TWasmInstr = class(TObject)
     code        : byte;
     operandIdx  : string;
-    operandNum  : integer;    // for "call_indirect" this is table index
-                              // for "if", "loop", "block" - it's type
-    operandText : string;     // it's "offset" for load operations
-    operandText2: string;     // it's "align" for load operations
-    insttype    : TWasmFuncType; // used by call_indirect only
+    operandNum  : integer;            // for "call_indirect" this is table index
+                                      // for "if", "loop", "block" - it's type
+    operand1    : TWasmInstrOperand;  // it's "offset" for load operations
+    operand2    : TWasmInstrOperand;  // it's "align" for load operations
+    insttype    : TWasmFuncType;      // used by call_indirect only
 
     jumplabel   : string;   // the label is used only for "loop", "block" and "if"
 
@@ -94,8 +117,8 @@ type
     destructor Destroy; override;
     procedure SetReloc(ARelocType: byte; ARelocIndex: Integer);
 
-    property offsetText : string read operandText write operandText;
-    property alignText  : string read operandText2 write operandText2;
+    property offsetText : TWasmInstrOperand read operand1 write operand1;
+    property alignText  : TWasmInstrOperand read operand2 write operand2;
   end;
 
   { TWasmInstrList }
@@ -292,8 +315,29 @@ function RegisterFuncType(m: TWasmModule; funcType: TWasmFuncType): integer;
 // returns false, if instruction "l" is invalid, or no i32 instruction
 function InstrGetConsti32Value(l: TWasmInstrList; var vl: Integer): Boolean;
 
+procedure OperandSetType(var op: TWasmInstrOperand; tp: TWasmInstrOperandType); inline;
+procedure OperandSetInt32(var op: TWasmInstrOperand; i32: Int32); inline;
+procedure OperandSetText(var op: TWasmInstrOperand; const txt: string); inline;
+
 implementation
 
+procedure OperandSetType(var op: TWasmInstrOperand; tp: TWasmInstrOperandType); inline;
+begin
+  if op.tp<>tp then op.tp:=tp;
+end;
+
+procedure OperandSetInt32(var op: TWasmInstrOperand; i32: Int32);
+begin
+  OperandSetType(op, otSInt32);
+  op.s32:=i32;
+end;
+
+procedure OperandSetText(var op: TWasmInstrOperand; const txt: string); inline;
+begin
+  OperandSetType(op, otText);
+  op.textVal := txt;
+end;
+
 // returing a basic wasm basic type to a character
 // i32 = i
 // i64 = I
@@ -975,7 +1019,7 @@ const
 begin
   if m.ElementCount=0 then begin
     el := m.AddElement;
-    el.offset.AddInstr(INST_i32_const).operandText:=NON_ZEROFFSET_STR;
+    OperandSetInt32( el.offset.AddInstr(INST_i32_const).operand1, NON_ZEROFFSET);
     el.offset.AddInstr(INST_END);
   end else
     el := m.GetElement(0);
@@ -1012,8 +1056,7 @@ begin
   Result:=Assigned(l) and (l.Count>0) and (l.Item[0].code = INST_i32_const);
   if not Result then Exit;
 
-  Val(l.Item[0].operandText, vl, err);
-  Result := err = 0;
+  vl := l.Item[0].operand1.s32; // todo: check the type
 end;
 
 end.

+ 3 - 14
utils/wasmbin/wasmnormalize.pas

@@ -16,9 +16,9 @@ var
 begin
   case INST_FLAGS[ci.code].Param of
     ipi32OrFunc:
-      if (ci.operandText<>'') and (ci.operandText[1]='$') then begin
+      if (ci.operand1.textVal<>'') and (ci.operand1.textVal[1]='$') then begin
         //if not ci.hasRelocIdx then
-        idx := RegisterfuncInElem(module, ci.operandText);
+        idx := RegisterfuncInElem(module, ci.operand1.textVal);
         //AddReloc(rt, dst.Position+ofsAddition, idx);
         ci.operandNum := idx;
         ci.SetReloc(INST_RELOC_FLAGS[ci.code].relocType, idx);
@@ -48,15 +48,6 @@ begin
   Result := LblStack.Count-i-1;
 end;
 
-procedure NormalizeOfsAlign(ci: TWasmInstr);
-const
-  ALIGN_STR : array [0..3] of string = ('1','2','4','8');
-begin
-  if (ci.offsetText = '') then ci.offsetText := '0';
-  if (ci.alignText = '') then
-    ci.alignText := ALIGN_STR[INST_FLAGS[ci.code].align];
-end;
-
 // Normalizing instruction list, popuplating index reference ($index)
 // with the actual numbers. (params, locals, globals, memory, functions index)
 //
@@ -87,8 +78,6 @@ begin
 
           lbl.Add(ci.jumplabel);
         end;
-        ipOfsAlign:
-          NormalizeOfsAlign( ci );
       end;
 
       case ci.code of
@@ -261,7 +250,7 @@ begin
   for i:=0 to m.ElementCount-1 do begin
     e := m.GetElement(i);
     l := e.AddOffset;
-    if (l.Count=0) then l.AddInstr(INST_i32_const).operandText:='0';
+    if (l.Count=0) then l.AddInstr(INST_i32_const).operand1.s32:=0;
     NormalizeInst( m, nil, l);
   end;
 end;

+ 282 - 7
utils/wasmbin/watparser.pas

@@ -39,6 +39,9 @@ const
 function ParseModule(sc: TWatScanner; dst: TWasmModule; var errMsg: string): Boolean; overload;
 function ParseModule(sc: TWatScanner; dst: TWasmModule; out err: TParseResult): Boolean; overload;
 
+// castType can be otNotused, if no explicit type cast is expected
+function ParseOperand(sc: TWatScanner; var op: TWasmInstrOperand; castType: TWasmInstrOperandType): Boolean;
+
 implementation
 
 type
@@ -246,10 +249,37 @@ begin
   end;
 end;
 
+function IntToAlign(aint: Integer): integer;
+begin
+  Result:=0;
+  aint := aint shr 1;
+  while aint>0 do begin
+    aint := aint shr 1;
+    inc(Result);
+  end;
+end;
+
 procedure ParseInstrList(sc: TWatScanner; dst: TWasmInstrList);
 var
   ci  : TWasmInstr;
   ft  : TWasmFuncType;
+const
+  ParamTypeToOpType : array [TInstParamType] of TWasmInstrOperandType = (
+      otNotused, // ipNone
+      otUInt32,  // ipLeb,        // label index or function index
+      otUInt32,  // ipOfsAlign,   // memory arguments, ask for offset + align
+      otSInt32,  // ipi32,        // signed Leb of maximum 4 bytes
+      otNotused,  // ipi64,        // signed Leb of maximum 8 bytes
+      otUInt32,  // ipu32,        // signed Leb of maximum 4 bytes
+      otNotused,  // ipu64,        // signed Leb of maximum 8 bytes
+      otFloat32,  // ipf32,       // float point single
+      otFloat64,  // ipf64,       // float point double
+      otNotused,  // ipJumpVec,   // an array of jump labels used for br_table only
+      otNotused,  // ipResType,   // result type used for blocks, such as If, block or loop
+      otNotused,  // ipCallType,  // used for call_indirect
+      otNotused,  // ipi32OrFunc, // use for i32.const. Either a numeric OR function id is accepted.
+      otUInt32    // ipZero       // followed by a single byte zero
+  );
 begin
   while sc.token=weInstr do begin
     ci := dst.AddInstr(sc.instrCode);
@@ -266,25 +296,30 @@ begin
           sc.Next;
           ConsumeToken(sc, weEqual);
           if sc.token<>weNumber then ErrorExpectButFound(sc, 'number');
-          ci.operandText := sc.resText;
+          //todo: fail on invalid value
+          OperandSetInt32(ci.operand1, sc.resInt32(0));
           sc.Next;
         end;
+
         if sc.token = weAlign then begin
           sc.Next;
           ConsumeToken(sc, weEqual);
           if sc.token<>weNumber then ErrorExpectButFound(sc, 'number');
-          ci.operandText2 := sc.resText;
+          OperandSetInt32(ci.operand2, IntToAlign(sc.resInt32(0)));
           sc.Next;
-        end;
+        end else
+          OperandSetInt32(ci.operand2, INST_FLAGS[ci.code].align);
       end;
 
-      ipi32,ipi64,ipf32,ipf64,ipi32OrFunc:
+      ipi32,ipi64,ipu32,ipu64,ipf32,ipf64,ipi32OrFunc:
       begin
         if (INST_FLAGS[ci.code].Param = ipi32OrFunc) and (sc.token = weIdent) then
-          ci.operandText := sc.resText
-        else if sc.token<>weNumber then
+          OperandSetText(ci.operand1, sc.resText)
+        else if sc.token<>weNumber then begin
           ErrorExpectButFound(sc, 'number');
-        ci.operandText := sc.resText;
+          Exit;
+        end else
+          ParseOperand(sc, ci.operand1, ParamTypeToOpType[INST_FLAGS[ci.code].Param]);
         sc.Next;
       end;
 
@@ -805,4 +840,244 @@ begin
   offset:=aofs;
 end;
 
+const
+  INT64MASK = $FFFFFFFF00000000;
+  maxInt64  = 9223372036854775807;
+
+function Int64ToOperand(v: Int64; var op: TWasmInstrOperand; castType: TWasmInstrOperandType): Boolean;
+begin
+  Result := true;
+  case castType of
+    otNotused:
+      if (v and INT64MASK = 0) then begin
+        if (v<0) or (v < maxLongint) then begin
+          op.tp := otSInt32;
+          op.s32 := v;
+        end else begin
+          op.tp := otUInt32;
+          op.u32 := v;
+        end
+      end else begin
+        op.tp := otSInt64;
+        op.s64 := v;
+      end;
+
+    otSInt32:
+    begin
+      Result := (v and INT64MASK = 0);
+      if not Result then Exit;
+      op.tp := otSInt32;
+      op.s32 := v;
+    end;
+
+    otUInt32:
+    begin
+      Result := (v and INT64MASK = 0) and (v>=0);
+      if not Result then Exit;
+      op.tp := otUInt32;
+      op.u32 := v;
+    end;
+
+    otSInt64: begin
+      op.tp := otSInt32;
+      op.s64 := v;
+    end;
+
+    otUInt64: begin
+      Result := (v>=0);
+      op.tp := otUInt64;
+      op.u64 := v;
+    end;
+
+    otFloat32: begin
+      op.tp := otFloat32;
+      op.f32 := v;
+    end;
+
+    otFloat64: begin
+      op.tp := otFloat64;
+      op.f64 := v;
+    end;
+  end
+end;
+
+function UInt64ToOperand(v: UInt64; var op: TWasmInstrOperand; castType: TWasmInstrOperandType): Boolean;
+begin
+  Result := true;
+  case castType of
+    otNotused:
+      if (v and INT64MASK = 0) then begin
+        if (v < maxLongint) then begin
+          op.tp := otSInt32;
+          op.s32 := v;
+        end else begin
+          op.tp := otUInt32;
+          op.u32 := v;
+        end
+      end else begin
+        if v < maxInt64 then begin
+          op.tp := otSInt64;
+          op.s64 := v;
+        end else begin
+          op.tp := otUInt64;
+          op.u64 := v;
+        end;
+      end;
+
+    otSInt32:
+    begin
+      Result := (v and INT64MASK = 0) and (v < maxLongint);
+      if not Result then Exit;
+      op.tp := otSInt32;
+      op.s32 := v;
+    end;
+
+    otUInt32:
+    begin
+      Result := (v and INT64MASK = 0);
+      if not Result then Exit;
+      op.tp := otUInt32;
+      op.u32 := v;
+    end;
+
+    otSInt64: begin
+      Result := (v <= maxInt64);
+      if not Result then Exit;
+      op.tp := otSInt32;
+      op.s64 := v;
+    end;
+
+    otUInt64: begin
+      op.tp := otUInt64;
+      op.u64 := v;
+    end;
+
+    otFloat32: begin
+      op.tp := otFloat32;
+      op.f32 := v;
+    end;
+
+    otFloat64: begin
+      op.tp := otFloat64;
+      op.f64 := v;
+    end;
+  end
+end;
+
+function TextToFloat32(const txt: string; var vl: Single): Boolean;
+var
+  err : integer;
+  l   : LongWord;
+  i   : Integer;
+  hx  : string;
+  hl  : LongWord;
+const
+  BINARY_INF    = $7f800000;
+  BINARY_NEGINF = $ff800000;
+  BINARY_NEGMAN = $00400000;
+begin
+  // val() doesn't handle "nan" in wasm compatible
+  // any "nan" is always returned as "negative nan" (in Wasm terms)
+  // "inf" works just fine
+  Result := true;
+  if (Pos('nan', txt)>0) then begin
+    if txt[1]='-' then l := NtoLE(BINARY_NEGINF)
+    else l := NtoLE(BINARY_INF);
+
+    i:=Pos(':', txt);
+    if i>0 then begin
+      hx := '$'+Copy(txt, i+3, length(txt)); // skipping '0x'
+      Val(hx, hl, err);
+    end else
+      hl:=BINARY_NEGMAN; // nan
+    l:=l or hl;
+    vl := PSingle(@l)^;
+  end else begin
+    vl:=0;
+    err:=0;
+    if (Pos('0x', txt)>0) then
+      vl := HexFloatStrToSingle(txt)
+    else begin
+      Val(txt, vl, err);
+      Result := err = 0;
+    end;
+  end;
+end;
+
+function TextToFloat64(const txt: string; var vl: Double): Boolean;
+var
+  err : integer;
+  l   : QWord;
+  i   : Integer;
+  hx  : string;
+  hl  : QWord;
+const
+  BINARY_INF    = QWord($7ff0000000000000);
+  BINARY_NEGINF = QWord($fff0000000000000);
+  BINARY_NEGMAN = QWord($0008000000000000);
+begin
+  Result := true;
+  if (Pos('nan', txt)>0) then begin
+    if txt[1]='-' then l := NtoLE(BINARY_NEGINF)
+    else l := NtoLE(BINARY_INF);
+
+    i:=Pos(':', txt);
+    if i>0 then begin
+      hx := '$'+Copy(txt, i+3, length(txt)); // skipping '0x'
+      Val(hx, hl, err);
+    end else
+      hl:=BINARY_NEGMAN; // nan
+    l:=l or hl;
+    vl := PDouble(@l)^;
+  end else begin
+    vl:=0;
+    if (Pos('0x', txt)>0) then
+      vl := HexFloatStrToDouble(txt)
+    else begin
+      Val(txt, vl, err);
+      Result := err = 0;
+    end;
+  end;
+end;
+
+function ParseOperand(sc: TWatScanner; var op: TWasmInstrOperand; castType: TWasmInstrOperandType): Boolean;
+var
+  i64 : Int64;
+  u64 : UInt64;
+  err : Integer;
+begin
+  Result := Assigned(sc);
+  if not Result then Exit;
+
+  if (castType = otText) or (sc.token <> weNumber) then begin
+    OperandSetText(op, sc.resText);
+    Exit;
+  end;
+
+  case sc.numformat of
+    wnfInteger, wnfHex: begin
+      val(sc.resText, i64, err);
+      if err = 0 then
+        Result := Int64ToOperand(i64, op, castType)
+      else begin
+        Val(sc.resText, u64, err);
+        Result := err = 0;
+        if Result then
+          Result := UInt64ToOperand(u64, op, castType);
+      end;
+    end;
+    wnfFloat, wnfFloatHex: begin   // 0.000
+      Result := castType in [otNotused, otFloat32, otFloat64];
+      if not Result then Exit;
+      if castType = otFloat32 then begin
+        op.tp := otFloat32;
+        TextToFloat32(sc.resText, op.f32);
+      end else begin
+        op.tp := otFloat64;
+        TextToFloat64(sc.resText, op.f64);
+      end;
+    end;
+  end;
+end;
+
 end.

+ 114 - 0
utils/wasmbin/watscanner.pas

@@ -33,6 +33,13 @@ type
      wnfFloatHex // 0x000.bced
   );
 
+  THexStr = record
+    num   : QWord;
+    frac  : QWord;
+    exp   : integer;
+    isNeg : Boolean;
+  end;
+
   { TWatScanner }
 
   TWatScanner = class(TObject)
@@ -97,6 +104,12 @@ const
 
 function ScanString(const buf: string; var idx: integer): string;
 
+function HexFloatStrToHexStr(const t: string; out hexStr: THexStr): Boolean;
+function HexFracToSingle(const num, frac: QWord; exp: Integer; isNeg: Boolean): Single;
+function HexFloatStrToSingle(const hexstr: string): Single;
+function HexFracToDouble(const num, frac: QWord; exp: Integer; neg: Boolean): Double;
+function HexFloatStrToDouble(const hexstr: string): double;
+
 implementation
 
 procedure GetGrammar(const txt: string; out entity: TWatToken; out instByte: byte);
@@ -217,6 +230,7 @@ var
   si  : integer;
 begin
   numformat := wnfNo;
+
   Result := idx<=length(buf);
   if not Result then Exit;
 
@@ -347,5 +361,105 @@ begin
 end;
 
 
+function HexFloatStrToHexStr(const t: string; out hexStr: THexStr): Boolean;
+var
+  i : integer;
+  j : integer;
+  err : Integer;
+const
+  HexChars = ['0'..'9','a'..'f','A'..'F'];
+begin
+  hexStr.isNeg:=false;
+  hexStr.num:=0;
+  hexStr.frac:=0;
+  hexStr.exp:=0;
+  if (t='') then begin
+    Result:=true;
+    Exit;
+  end;
+
+  i:=1;
+  hexStr.isNeg:=t[i]='-';
+  if (hexStr.isNeg) then inc(i);
+  inc(i,2); // skipping '0x'
+
+  j:=i;
+  while (i<=length(t)) and (t[i] in HexChars) do inc(i);
+  Val('$'+Copy(t, j, i-j), hexStr.num, err);
+  Result:=err=0;
+  if not Result then Exit;
+
+  if (t[i]='.') then begin
+    inc(i);
+    j:=i;
+    while (i<=length(t)) and (t[i] in HexChars) do inc(i);
+    Val('$'+Copy(t, j, i-j), hexStr.frac, err);
+    Result:=err=0;
+    if not Result then Exit;
+  end;
+
+  Result := (i<=length(t)) and (t[i] = 'p') or (t[i]='P');
+  inc(i);
+  Val(Copy(t, i, length(t)), hexStr.exp, err);
+  Result:=err=0;
+end;
+
+function HexFracToSingle(const num, frac: QWord; exp: Integer; isNeg: Boolean): Single;
+var
+  x      : QWord;
+  nm     : QWord;
+  adjexp : integer;
+  sr     : TSingleRec;
+begin
+  nm := num;
+  x := frac;
+  adjexp := -1;
+  while (nm > 0) do begin
+    x:=(x shr 1) or ((nm and 1) shl 23);
+    nm := nm shr 1;
+    inc(adjexp);
+  end;
+  sr.Exp:=127 + exp + adjexp;
+  sr.Frac:=x;
+  sr.Sign:=isNeg;
+  Result := sr.Value;
+end;
+
+function HexFloatStrToSingle(const hexstr: string): Single;
+var
+  st : THexStr;
+begin
+  HexFloatStrToHexStr(hexstr, st);
+  Result:=HexFracToSingle(st.num, st.frac, st.exp, st.isNeg);
+end;
+
+function HexFracToDouble(const num, frac: QWord; exp: Integer; neg: Boolean): Double;
+var
+  x      : QWord;
+  nm     : QWord;
+  adjexp : integer;
+  sr     : TDoubleRec;
+begin
+  nm := num;
+  x := frac;
+  adjexp := 0;
+  while (nm > 1) do begin
+    x:=(x shr 1) or ((nm and 1) shl 52);
+    nm := nm shr 1;
+    inc(adjexp);
+  end;
+  sr.Exp:=1023 + exp + adjexp;
+  sr.Frac:=x;
+  sr.Sign:=neg;
+  Result := sr.Value;
+end;
+
+function HexFloatStrToDouble(const hexstr: string): double;
+var
+  st : THexStr;
+begin
+  HexFloatStrToHexStr(hexstr, st);
+  Result:=HexFracToDouble(st.num, st.frac, st.exp, st.isNeg);
+end;
 
 end.