github.com/decomp/exp@v0.0.0-20210624183419-6d058f5e1da6/lift/x86/inst_fpu.go (about)

     1  // x87 FPU Instructions.
     2  //
     3  // ref: $ 5.2 X87 FPU INSTRUCTIONS, Intel 64 and IA-32 architectures software
     4  // developer's manual volume 1: Basic architecture.
     5  
     6  package x86
     7  
     8  import (
     9  	"fmt"
    10  	"math"
    11  
    12  	"github.com/decomp/exp/disasm/x86"
    13  	"github.com/kr/pretty"
    14  	"github.com/llir/llvm/ir"
    15  	"github.com/llir/llvm/ir/constant"
    16  	"github.com/llir/llvm/ir/enum"
    17  	"github.com/llir/llvm/ir/types"
    18  	"github.com/llir/llvm/ir/value"
    19  	"github.com/pkg/errors"
    20  	"golang.org/x/arch/x86/x86asm"
    21  )
    22  
    23  // === [ x87 FPU Data Transfer Instructions ] ==================================
    24  
    25  // --- [ FLD ] -----------------------------------------------------------------
    26  
    27  // liftInstFLD lifts the given x87 FLD instruction to LLVM IR, emitting code to
    28  // f.
    29  func (f *Func) liftInstFLD(inst *x86.Inst) error {
    30  	// FLD - Load floating-point value.
    31  	//
    32  	//    FLD m32fp           Push m32fp onto the FPU register stack.
    33  	//    FLD m64fp           Push m64fp onto the FPU register stack.
    34  	//    FLD m80fp           Push m80fp onto the FPU register stack.
    35  	//    FLD ST(i)           Push ST(i) onto the FPU register stack.
    36  	//
    37  	// Pushes the source operand onto the FPU register stack. If the source
    38  	// operand is in single-precision or double-precision floating-point format,
    39  	// it is automatically converted to the double extended-precision floating-
    40  	// point format before being pushed on the stack.
    41  	src := f.useArg(inst.Arg(0))
    42  	// TODO: Verify that FLD ST(i) is handled correctly.
    43  	if !types.Equal(src.Type(), types.X86_FP80) {
    44  		src = f.cur.NewFPExt(src, types.X86_FP80)
    45  	}
    46  	f.fpush(src)
    47  	return nil
    48  }
    49  
    50  // --- [ FST ] -----------------------------------------------------------------
    51  
    52  // liftInstFST lifts the given x87 FST instruction to LLVM IR, emitting code to
    53  // f.
    54  func (f *Func) liftInstFST(inst *x86.Inst) error {
    55  	// FST - Store floating-point value.
    56  	//
    57  	//    FST m32fp      Copy ST(0) to m32fp.
    58  	//    FST m64fp      Copy ST(0) to m64fp.
    59  	//    FST ST(i)      Copy ST(0) to ST(i).
    60  	//
    61  	// Copies the value in the ST(0) register to the destination operand.
    62  	src := f.fload()
    63  	switch arg := inst.Args[0].(type) {
    64  	case x86asm.Reg:
    65  		// no type conversion needed.
    66  	case x86asm.Mem:
    67  		var typ types.Type
    68  		switch inst.MemBytes {
    69  		case 4:
    70  			typ = types.Float
    71  		case 8:
    72  			typ = types.Double
    73  		default:
    74  			panic(fmt.Errorf("support for memory argument with byte size %d not yet implemented", inst.MemBytes))
    75  		}
    76  		src = f.cur.NewFPTrunc(src, typ)
    77  	default:
    78  		panic(fmt.Errorf("support for operand type %T not yet implemented", arg))
    79  	}
    80  	f.defArg(inst.Arg(0), src)
    81  	return nil
    82  }
    83  
    84  // --- [ FSTP ] ----------------------------------------------------------------
    85  
    86  // liftInstFSTP lifts the given x87 FSTP instruction to LLVM IR, emitting code
    87  // to f.
    88  func (f *Func) liftInstFSTP(inst *x86.Inst) error {
    89  	// FSTP - Store floating-point value and pop.
    90  	//
    91  	//    FSTP m32fp          Copy ST(0) to m32fp and pop register stack.
    92  	//    FSTP m64fp          Copy ST(0) to m64fp and pop register stack.
    93  	//    FSTP m80fp          Copy ST(0) to m80fp and pop register stack.
    94  	//    FSTP ST(i)          Copy ST(0) to ST(i) and pop register stack.
    95  	//
    96  	// Copies the value in the ST(0) register to the destination operand.
    97  	src := f.fload()
    98  	switch arg := inst.Args[0].(type) {
    99  	case x86asm.Reg:
   100  		// no type conversion needed.
   101  	case x86asm.Mem:
   102  		switch inst.MemBytes {
   103  		case 4:
   104  			src = f.cur.NewFPTrunc(src, types.Float)
   105  		case 8:
   106  			src = f.cur.NewFPTrunc(src, types.Double)
   107  		case 10:
   108  			// no type conversion needed.
   109  		default:
   110  			panic(fmt.Errorf("support for memory argument with byte size %d not yet implemented", inst.MemBytes))
   111  		}
   112  	default:
   113  		panic(fmt.Errorf("support for operand type %T not yet implemented", arg))
   114  	}
   115  	f.defArg(inst.Arg(0), src)
   116  	f.pop()
   117  	return nil
   118  }
   119  
   120  // --- [ FILD ] ----------------------------------------------------------------
   121  
   122  // liftInstFILD lifts the given x87 FILD instruction to LLVM IR, emitting code
   123  // to f.
   124  func (f *Func) liftInstFILD(inst *x86.Inst) error {
   125  	// FILD - Load integer.
   126  	//
   127  	//    FILD m16int         Push m16int onto the FPU register stack.
   128  	//    FILD m32int         Push m32int onto the FPU register stack.
   129  	//    FILD m64int         Push m64int onto the FPU register stack.
   130  	//
   131  	// Converts the signed-integer source operand into double extended-precision
   132  	// floating-point format and pushes the value onto the FPU register stack.
   133  	arg := f.useArg(inst.Arg(0))
   134  	src := f.cur.NewSIToFP(arg, types.X86_FP80)
   135  	f.fpush(src)
   136  	return nil
   137  }
   138  
   139  // --- [ FIST ] ----------------------------------------------------------------
   140  
   141  // liftInstFIST lifts the given x87 FIST instruction to LLVM IR, emitting code
   142  // to f.
   143  func (f *Func) liftInstFIST(inst *x86.Inst) error {
   144  	// FIST - Store integer.
   145  	pretty.Println("inst:", inst)
   146  	panic("liftInstFIST: not yet implemented")
   147  }
   148  
   149  // --- [ FISTP ] ---------------------------------------------------------------
   150  
   151  // liftInstFISTP lifts the given x87 FISTP instruction to LLVM IR, emitting code
   152  // to f.
   153  func (f *Func) liftInstFISTP(inst *x86.Inst) error {
   154  	// FISTP - Store integer and pop.
   155  	pretty.Println("inst:", inst)
   156  	panic("liftInstFISTP: not yet implemented")
   157  }
   158  
   159  // --- [ FBLD ] ----------------------------------------------------------------
   160  
   161  // liftInstFBLD lifts the given x87 FBLD instruction to LLVM IR, emitting code
   162  // to f.
   163  func (f *Func) liftInstFBLD(inst *x86.Inst) error {
   164  	// FBLD - Load BCD.
   165  	pretty.Println("inst:", inst)
   166  	panic("liftInstFBLD: not yet implemented")
   167  }
   168  
   169  // --- [ FBSTP ] ---------------------------------------------------------------
   170  
   171  // liftInstFBSTP lifts the given x87 FBSTP instruction to LLVM IR, emitting code
   172  // to f.
   173  func (f *Func) liftInstFBSTP(inst *x86.Inst) error {
   174  	// FBSTP - Store BCD and pop.
   175  	pretty.Println("inst:", inst)
   176  	panic("liftInstFBSTP: not yet implemented")
   177  }
   178  
   179  // --- [ FXCH ] ----------------------------------------------------------------
   180  
   181  // liftInstFXCH lifts the given x87 FXCH instruction to LLVM IR, emitting code
   182  // to f.
   183  func (f *Func) liftInstFXCH(inst *x86.Inst) error {
   184  	// FXCH - Exchange registers.
   185  	pretty.Println("inst:", inst)
   186  	panic("liftInstFXCH: not yet implemented")
   187  }
   188  
   189  // ___ [ FCMOVcc - Floating-Point Conditional Move Instructions ] ______________
   190  //
   191  //    Instruction Mnemonic   Status Flag States   Condition Description
   192  //
   193  //    FCMOVB                 CF=1                 Below
   194  //    FCMOVNB                CF=0                 Not below
   195  //    FCMOVE                 ZF=1                 Equal
   196  //    FCMOVNE                ZF=0                 Not equal
   197  //    FCMOVBE                CF=1 or ZF=1         Below or equal
   198  //    FCMOVNBE               CF=0 or ZF=0         Not below nor equal
   199  //    FCMOVU                 PF=1                 Unordered
   200  //    FCMOVNU                PF=0                 Not unordered
   201  //
   202  // ref: $ 8.3.3 Data Transfer Instructions, Table 8-5, Floating-Point
   203  // Conditional Move Instructions, Intel 64 and IA-32 Architectures Software
   204  // Developer's Manual: Basic architecture.
   205  
   206  // --- [ FCMOVE ] --------------------------------------------------------------
   207  
   208  // liftInstFCMOVE lifts the given x87 FCMOVE instruction to LLVM IR, emitting
   209  // code to f.
   210  func (f *Func) liftInstFCMOVE(inst *x86.Inst) error {
   211  	// FCMOVE - Floating-point conditional move if equal.
   212  	pretty.Println("inst:", inst)
   213  	panic("liftInstFCMOVE: not yet implemented")
   214  }
   215  
   216  // --- [ FCMOVNE ] -------------------------------------------------------------
   217  
   218  // liftInstFCMOVNE lifts the given x87 FCMOVNE instruction to LLVM IR, emitting
   219  // code to f.
   220  func (f *Func) liftInstFCMOVNE(inst *x86.Inst) error {
   221  	// FCMOVNE - Floating-point conditional move if not equal.
   222  	pretty.Println("inst:", inst)
   223  	panic("liftInstFCMOVNE: not yet implemented")
   224  }
   225  
   226  // --- [ FCMOVB ] --------------------------------------------------------------
   227  
   228  // liftInstFCMOVB lifts the given x87 FCMOVB instruction to LLVM IR, emitting
   229  // code to f.
   230  func (f *Func) liftInstFCMOVB(inst *x86.Inst) error {
   231  	// FCMOVB - Floating-point conditional move if below.
   232  	pretty.Println("inst:", inst)
   233  	panic("liftInstFCMOVB: not yet implemented")
   234  }
   235  
   236  // --- [ FCMOVBE ] -------------------------------------------------------------
   237  
   238  // liftInstFCMOVBE lifts the given x87 FCMOVBE instruction to LLVM IR, emitting
   239  // code to f.
   240  func (f *Func) liftInstFCMOVBE(inst *x86.Inst) error {
   241  	// FCMOVBE - Floating-point conditional move if below or equal.
   242  	pretty.Println("inst:", inst)
   243  	panic("liftInstFCMOVBE: not yet implemented")
   244  }
   245  
   246  // --- [ FCMOVNB ] -------------------------------------------------------------
   247  
   248  // liftInstFCMOVNB lifts the given x87 FCMOVNB instruction to LLVM IR, emitting
   249  // code to f.
   250  func (f *Func) liftInstFCMOVNB(inst *x86.Inst) error {
   251  	// FCMOVNB - Floating-point conditional move if not below.
   252  	pretty.Println("inst:", inst)
   253  	panic("liftInstFCMOVNB: not yet implemented")
   254  }
   255  
   256  // --- [ FCMOVNBE ] ------------------------------------------------------------
   257  
   258  // liftInstFCMOVNBE lifts the given x87 FCMOVNBE instruction to LLVM IR,
   259  // emitting code to f.
   260  func (f *Func) liftInstFCMOVNBE(inst *x86.Inst) error {
   261  	// FCMOVNBE - Floating-point conditional move if not below or equal.
   262  	pretty.Println("inst:", inst)
   263  	panic("liftInstFCMOVNBE: not yet implemented")
   264  }
   265  
   266  // --- [ FCMOVU ] --------------------------------------------------------------
   267  
   268  // liftInstFCMOVU lifts the given x87 FCMOVU instruction to LLVM IR, emitting
   269  // code to f.
   270  func (f *Func) liftInstFCMOVU(inst *x86.Inst) error {
   271  	// FCMOVU - Floating-point conditional move if unordered.
   272  	pretty.Println("inst:", inst)
   273  	panic("liftInstFCMOVU: not yet implemented")
   274  }
   275  
   276  // --- [ FCMOVNU ] -------------------------------------------------------------
   277  
   278  // liftInstFCMOVNU lifts the given x87 FCMOVNU instruction to LLVM IR, emitting
   279  // code to f.
   280  func (f *Func) liftInstFCMOVNU(inst *x86.Inst) error {
   281  	// FCMOVNU - Floating-point conditional move if not unordered.
   282  	pretty.Println("inst:", inst)
   283  	panic("liftInstFCMOVNU: not yet implemented")
   284  }
   285  
   286  // === [ x87 FPU Basic Arithmetic Instructions ] ===============================
   287  
   288  // --- [ FADD ] ----------------------------------------------------------------
   289  
   290  // liftInstFADD lifts the given x87 FADD instruction to LLVM IR, emitting code
   291  // to f.
   292  func (f *Func) liftInstFADD(inst *x86.Inst) error {
   293  	// FADD - Add floating-point.
   294  	//
   295  	//    FADD m32fp          Add m32fp to ST(0) and store result in ST(0).
   296  	//    FADD m64fp          Add m64fp to ST(0) and store result in ST(0).
   297  	//    FADD ST(0), ST(i)   Add ST(0) to ST(i) and store result in ST(0).
   298  	//    FADD ST(i), ST(0)   Add ST(i) to ST(0) and store result in ST(i).
   299  	//
   300  	// Adds the destination and source operands and stores the sum in the
   301  	// destination location.
   302  	if inst.Args[1] != nil {
   303  		// Two-operand form.
   304  		dst := f.useArg(inst.Arg(0))
   305  		src := f.useArg(inst.Arg(1))
   306  		result := f.cur.NewFAdd(dst, src)
   307  		f.defArg(inst.Arg(0), result)
   308  		return nil
   309  	}
   310  	// One-operand form.
   311  	src := f.useArg(inst.Arg(0))
   312  	v := f.cur.NewFPExt(src, types.X86_FP80)
   313  	st0 := f.fload()
   314  	result := f.cur.NewFAdd(st0, v)
   315  	f.fstore(result)
   316  	return nil
   317  }
   318  
   319  // --- [ FADDP ] ---------------------------------------------------------------
   320  
   321  // liftInstFADDP lifts the given x87 FADDP instruction to LLVM IR, emitting code
   322  // to f.
   323  func (f *Func) liftInstFADDP(inst *x86.Inst) error {
   324  	// FADDP - Add floating-point and pop.
   325  	//
   326  	//    FADDP ST(i), ST(0)            Add ST(0) to ST(i), store result in ST(i), and pop the register stack.
   327  	//    FADDP                         Add ST(0) to ST(1), store result in ST(1), and pop the register stack.
   328  	//
   329  	// Adds the destination and source operands and stores the sum in the
   330  	// destination location.
   331  	if inst.Args[1] != nil {
   332  		// Two-operand form.
   333  		dst := f.useArg(inst.Arg(0))
   334  		src := f.useArg(inst.Arg(1))
   335  		result := f.cur.NewFAdd(dst, src)
   336  		f.defArg(inst.Arg(0), result)
   337  		return nil
   338  	}
   339  	// Zero-operand form.
   340  
   341  	// TODO: Figure out how to handle F1, directly or through abstraction since
   342  	// the underlying register of F1 changes as ST is updated.
   343  	st0 := f.useReg(x86.NewReg(x86asm.F0, inst))
   344  	st1 := f.useReg(x86.NewReg(x86asm.F1, inst))
   345  	result := f.cur.NewFAdd(st0, st1)
   346  	f.defReg(x86.NewReg(x86asm.F1, inst), result)
   347  
   348  	f.pop()
   349  	return nil
   350  }
   351  
   352  // --- [ FIADD ] ---------------------------------------------------------------
   353  
   354  // liftInstFIADD lifts the given x87 FIADD instruction to LLVM IR, emitting code
   355  // to f.
   356  func (f *Func) liftInstFIADD(inst *x86.Inst) error {
   357  	// FIADD - Add integer.
   358  	//
   359  	//    FIADD m32int        Add m32int to ST(0) and store result in ST(0).
   360  	//    FIADD m16int        Add m16int to ST(0) and store result in ST(0).
   361  	//
   362  	// Adds the destination and source operands and stores the sum in the
   363  	// destination location.
   364  	pretty.Println("inst:", inst)
   365  	panic("liftInstFIADD: not yet implemented")
   366  }
   367  
   368  // --- [ FSUB ] ----------------------------------------------------------------
   369  
   370  // liftInstFSUB lifts the given x87 FSUB instruction to LLVM IR, emitting code
   371  // to f.
   372  func (f *Func) liftInstFSUB(inst *x86.Inst) error {
   373  	// FSUB - Subtract floating-point.
   374  	//
   375  	//    FSUB m32fp             Subtract m32fp from ST(0) and store result in ST(0).
   376  	//    FSUB m64fp             Subtract m64fp from ST(0) and store result in ST(0).
   377  	//    FSUB ST(0), ST(i)      Subtract ST(i) from ST(0) and store result in ST(0).
   378  	//    FSUB ST(i), ST(0)      Subtract ST(0) from ST(i) and store result in ST(i).
   379  	//
   380  	// Subtracts the source operand from the destination operand and stores the
   381  	// difference in the destination location.
   382  	pretty.Println("inst:", inst)
   383  	panic("liftInstFSUB: not yet implemented")
   384  }
   385  
   386  // --- [ FSUBP ] ---------------------------------------------------------------
   387  
   388  // liftInstFSUBP lifts the given x87 FSUBP instruction to LLVM IR, emitting code
   389  // to f.
   390  func (f *Func) liftInstFSUBP(inst *x86.Inst) error {
   391  	// FSUBP - Subtract floating-point and pop.
   392  	//
   393  	//    FSUBP ST(i), ST(0)     Subtract ST(0) from ST(i), store result in ST(i), and pop register stack.
   394  	//    FSUBP                  Subtract ST(0) from ST(1), store result in ST(1), and pop register stack.
   395  	//
   396  	// Subtracts the source operand from the destination operand and stores the
   397  	// difference in the destination location.
   398  	pretty.Println("inst:", inst)
   399  	panic("liftInstFSUBP: not yet implemented")
   400  }
   401  
   402  // --- [ FISUB ] ---------------------------------------------------------------
   403  
   404  // liftInstFISUB lifts the given x87 FISUB instruction to LLVM IR, emitting code
   405  // to f.
   406  func (f *Func) liftInstFISUB(inst *x86.Inst) error {
   407  	// FISUB - Subtract integer.
   408  	//
   409  	//    FISUB m16int           Subtract m16int from ST(0) and store result in ST(0).
   410  	//    FISUB m32int           Subtract m32int from ST(0) and store result in ST(0).
   411  	//
   412  	// Subtracts the source operand from the destination operand and stores the
   413  	// difference in the destination location.
   414  	arg := f.useArg(inst.Arg(0))
   415  	src := f.cur.NewSIToFP(arg, types.X86_FP80)
   416  	st0 := f.fload()
   417  	result := f.cur.NewFSub(st0, src)
   418  	f.fstore(result)
   419  	return nil
   420  }
   421  
   422  // --- [ FSUBR ] ---------------------------------------------------------------
   423  
   424  // liftInstFSUBR lifts the given x87 FSUBR instruction to LLVM IR, emitting code
   425  // to f.
   426  func (f *Func) liftInstFSUBR(inst *x86.Inst) error {
   427  	// FSUBR - Subtract floating-point reverse.
   428  	pretty.Println("inst:", inst)
   429  	panic("liftInstFSUBR: not yet implemented")
   430  }
   431  
   432  // --- [ FSUBRP ] --------------------------------------------------------------
   433  
   434  // liftInstFSUBRP lifts the given x87 FSUBRP instruction to LLVM IR, emitting
   435  // code to f.
   436  func (f *Func) liftInstFSUBRP(inst *x86.Inst) error {
   437  	// FSUBRP - Subtract floating-point reverse and pop.
   438  	pretty.Println("inst:", inst)
   439  	panic("liftInstFSUBRP: not yet implemented")
   440  }
   441  
   442  // --- [ FISUBR ] --------------------------------------------------------------
   443  
   444  // liftInstFISUBR lifts the given x87 FISUBR instruction to LLVM IR, emitting
   445  // code to f.
   446  func (f *Func) liftInstFISUBR(inst *x86.Inst) error {
   447  	// FISUBR - Subtract integer reverse.
   448  	pretty.Println("inst:", inst)
   449  	panic("liftInstFISUBR: not yet implemented")
   450  }
   451  
   452  // --- [ FMUL ] ----------------------------------------------------------------
   453  
   454  // liftInstFMUL lifts the given x87 FMUL instruction to LLVM IR, emitting code
   455  // to f.
   456  func (f *Func) liftInstFMUL(inst *x86.Inst) error {
   457  	// FMUL - Multiply floating-point.
   458  	//
   459  	//    FMUL m32fp          Multiply ST(0) by m32fp and store result in ST(0).
   460  	//    FMUL m64fp          Multiply ST(0) by m64fp and store result in ST(0).
   461  	//    FMUL ST(0), ST(i)   Multiply ST(0) by ST(i) and store result in ST(0).
   462  	//    FMUL ST(i), ST(0)   Multiply ST(i) by ST(0) and store result in ST(i).
   463  	//
   464  	// Multiplies the destination and source operands and stores the product in
   465  	// the destination location.
   466  	if inst.Args[1] != nil {
   467  		// Two-operand form.
   468  		dst := f.useArg(inst.Arg(0))
   469  		src := f.useArg(inst.Arg(1))
   470  		result := f.cur.NewFMul(dst, src)
   471  		f.defArg(inst.Arg(0), result)
   472  		return nil
   473  	}
   474  	// One-operand form.
   475  	arg := f.useArg(inst.Arg(0))
   476  	src := f.cur.NewFPExt(arg, types.X86_FP80)
   477  	st0 := f.fload()
   478  	result := f.cur.NewFMul(st0, src)
   479  	f.fstore(result)
   480  	return nil
   481  }
   482  
   483  // --- [ FMULP ] ---------------------------------------------------------------
   484  
   485  // liftInstFMULP lifts the given x87 FMULP instruction to LLVM IR, emitting code
   486  // to f.
   487  func (f *Func) liftInstFMULP(inst *x86.Inst) error {
   488  	// FMULP - Multiply floating-point and pop.
   489  	//
   490  	//    FMULP ST(i), ST(0)     Multiply ST(i) by ST(0), store result in ST(i), and pop the register stack.
   491  	//    FMULP                  Multiply ST(1) by ST(0), store result in ST(1), and pop the register stack.
   492  	//
   493  	// Multiplies the destination and source operands and stores the product in
   494  	// the destination location.
   495  	pretty.Println("inst:", inst)
   496  	panic("liftInstFMULP: not yet implemented")
   497  }
   498  
   499  // --- [ FIMUL ] ---------------------------------------------------------------
   500  
   501  // liftInstFIMUL lifts the given x87 FIMUL instruction to LLVM IR, emitting code
   502  // to f.
   503  func (f *Func) liftInstFIMUL(inst *x86.Inst) error {
   504  	// FIMUL - Multiply integer.
   505  	//
   506  	//    FIMUL m16int           Multiply ST(0) by m16int and store result in ST(0).
   507  	//    FIMUL m32int           Multiply ST(0) by m32int and store result in ST(0).
   508  	//
   509  	// Multiplies the destination and source operands and stores the product in
   510  	// the destination location.
   511  	arg := f.useArg(inst.Arg(0))
   512  	src := f.cur.NewSIToFP(arg, types.X86_FP80)
   513  	st0 := f.fload()
   514  	result := f.cur.NewFMul(st0, src)
   515  	f.fstore(result)
   516  	return nil
   517  }
   518  
   519  // --- [ FDIV ] ----------------------------------------------------------------
   520  
   521  // liftInstFDIV lifts the given x87 FDIV instruction to LLVM IR, emitting code
   522  // to f.
   523  func (f *Func) liftInstFDIV(inst *x86.Inst) error {
   524  	// FDIV - Divide floating-point.
   525  	//
   526  	//    FDIV m32fp          Divide ST(0) by m32fp and store result in ST(0).
   527  	//    FDIV m64fp          Divide ST(0) by m64fp and store result in ST(0).
   528  	//    FDIV ST(0), ST(i)   Divide ST(0) by ST(i) and store result in ST(0).
   529  	//    FDIV ST(i), ST(0)   Divide ST(i) by ST(0) and store result in ST(i).
   530  	//
   531  	// Divides the destination operand by the source operand and stores the
   532  	// result in the destination location.
   533  	if inst.Args[1] != nil {
   534  		// Two-operand form.
   535  		dst := f.useArg(inst.Arg(0))
   536  		src := f.useArg(inst.Arg(1))
   537  		result := f.cur.NewFDiv(dst, src)
   538  		f.defArg(inst.Arg(0), result)
   539  		return nil
   540  	}
   541  	// One-operand form.
   542  	arg := f.useArg(inst.Arg(0))
   543  	src := f.cur.NewFPExt(arg, types.X86_FP80)
   544  	st0 := f.fload()
   545  	result := f.cur.NewFDiv(st0, src)
   546  	f.fstore(result)
   547  	return nil
   548  }
   549  
   550  // --- [ FDIVP ] ---------------------------------------------------------------
   551  
   552  // liftInstFDIVP lifts the given x87 FDIVP instruction to LLVM IR, emitting code
   553  // to f.
   554  func (f *Func) liftInstFDIVP(inst *x86.Inst) error {
   555  	// FDIVP - Divide floating-point and pop.
   556  	//
   557  	//    FDIVP ST(i), ST(0)            Divide ST(i) by ST(0), store result in ST(i), and pop the register stack.
   558  	//    FDIVP                         Divide ST(1) by ST(0), store result in ST(1), and pop the register stack.
   559  	//
   560  	// Divides the destination operand by the source operand and stores the
   561  	// result in the destination location.
   562  	if inst.Args[1] != nil {
   563  		// Two-operand form.
   564  		dst := f.useArg(inst.Arg(0))
   565  		src := f.useArg(inst.Arg(1))
   566  		result := f.cur.NewFDiv(dst, src)
   567  		f.defArg(inst.Arg(0), result)
   568  		f.fpop()
   569  		return nil
   570  	}
   571  	// Zero-operand form.
   572  	dst := f.useReg(x86.NewReg(x86asm.F1, inst))
   573  	src := f.useReg(x86.NewReg(x86asm.F0, inst))
   574  	result := f.cur.NewFDiv(dst, src)
   575  	f.defReg(x86.NewReg(x86asm.F1, inst), result)
   576  	f.pop()
   577  	return nil
   578  }
   579  
   580  // --- [ FIDIV ] ---------------------------------------------------------------
   581  
   582  // liftInstFIDIV lifts the given x87 FIDIV instruction to LLVM IR, emitting code
   583  // to f.
   584  func (f *Func) liftInstFIDIV(inst *x86.Inst) error {
   585  	// FIDIV - Divide integer.
   586  	//
   587  	//    FIDIV m16int        Divide ST(0) by m16int and store result in ST(0).
   588  	//    FIDIV m32int        Divide ST(0) by m32int and store result in ST(0).
   589  	//
   590  	// Convert an integer source operand to double extended-precision floating-
   591  	// point format before performing the division.
   592  	arg := f.useArg(inst.Arg(0))
   593  	src := f.cur.NewSIToFP(arg, types.X86_FP80)
   594  	st0 := f.fload()
   595  	result := f.cur.NewFDiv(st0, src)
   596  	f.fstore(result)
   597  	return nil
   598  }
   599  
   600  // --- [ FDIVR ] ---------------------------------------------------------------
   601  
   602  // liftInstFDIVR lifts the given x87 FDIVR instruction to LLVM IR, emitting code
   603  // to f.
   604  func (f *Func) liftInstFDIVR(inst *x86.Inst) error {
   605  	// FDIVR - Divide floating-point reverse.
   606  	//
   607  	//    FDIVR m32fp                   Divide m32fp by ST(0) and store result in ST(0).
   608  	//    FDIVR m64fp                   Divide m64fp by ST(0) and store result in ST(0).
   609  	//    FDIVR ST(0), ST(i)            Divide ST(i) by ST(0) and store result in ST(0).
   610  	//    FDIVR ST(i), ST(0)            Divide ST(0) by ST(i) and store result in ST(i).
   611  	//
   612  	// Divides the source operand by the destination operand and stores the
   613  	// result in the destination location.
   614  
   615  	pretty.Println("inst:", inst)
   616  	panic("liftInstFDIVR: not yet implemented")
   617  }
   618  
   619  // --- [ FDIVRP ] --------------------------------------------------------------
   620  
   621  // liftInstFDIVRP lifts the given x87 FDIVRP instruction to LLVM IR, emitting
   622  // code to f.
   623  func (f *Func) liftInstFDIVRP(inst *x86.Inst) error {
   624  	// FDIVRP - Divide floating-point reverse and pop.
   625  	//
   626  	//    FDIVRP ST(i), ST(0)           Divide ST(0) by ST(i), store result in ST(i), and pop the register stack.
   627  	//    FDIVRP                        Divide ST(0) by ST(1), store result in ST(1), and pop the register stack.
   628  	//
   629  	// Divides the source operand by the destination operand and stores the
   630  	// result in the destination location.
   631  	if inst.Args[1] != nil {
   632  		// Two-operand form.
   633  		dst := f.useArg(inst.Arg(0))
   634  		src := f.useArg(inst.Arg(1))
   635  		result := f.cur.NewFDiv(src, dst)
   636  		f.defArg(inst.Arg(0), result)
   637  		f.pop()
   638  		return nil
   639  	}
   640  	// Zero-operand form.
   641  	dst := f.useReg(x86.NewReg(x86asm.F1, inst))
   642  	src := f.useReg(x86.NewReg(x86asm.F0, inst))
   643  	result := f.cur.NewFDiv(src, dst)
   644  	f.defReg(x86.NewReg(x86asm.F1, inst), result)
   645  	f.pop()
   646  	return nil
   647  }
   648  
   649  // --- [ FIDIVR ] --------------------------------------------------------------
   650  
   651  // liftInstFIDIVR lifts the given x87 FIDIVR instruction to LLVM IR, emitting
   652  // code to f.
   653  func (f *Func) liftInstFIDIVR(inst *x86.Inst) error {
   654  	// FIDIVR - Divide integer reverse.
   655  	//
   656  	//    FIDIVR m32int       Divide m32int by ST(0) and store result in ST(0).
   657  	//    FIDIVR m16int       Divide m16int by ST(0) and store result in ST(0).
   658  	//
   659  	// Divides the source operand by the destination operand and stores the
   660  	// result in the destination location.
   661  
   662  	pretty.Println("inst:", inst)
   663  	panic("liftInstFIDIVR: not yet implemented")
   664  }
   665  
   666  // --- [ FPREM ] ---------------------------------------------------------------
   667  
   668  // liftInstFPREM lifts the given x87 FPREM instruction to LLVM IR, emitting code
   669  // to f.
   670  func (f *Func) liftInstFPREM(inst *x86.Inst) error {
   671  	// FPREM - Partial remainder.
   672  	pretty.Println("inst:", inst)
   673  	panic("liftInstFPREM: not yet implemented")
   674  }
   675  
   676  // --- [ FPREM1 ] --------------------------------------------------------------
   677  
   678  // liftInstFPREM1 lifts the given x87 FPREM1 instruction to LLVM IR, emitting
   679  // code to f.
   680  func (f *Func) liftInstFPREM1(inst *x86.Inst) error {
   681  	// FPREM1 - IEEE Partial remainder.
   682  	pretty.Println("inst:", inst)
   683  	panic("liftInstFPREM1: not yet implemented")
   684  }
   685  
   686  // --- [ FABS ] ----------------------------------------------------------------
   687  
   688  // liftInstFABS lifts the given x87 FABS instruction to LLVM IR, emitting code
   689  // to f.
   690  func (f *Func) liftInstFABS(inst *x86.Inst) error {
   691  	// FABS - Absolute value.
   692  	pretty.Println("inst:", inst)
   693  	panic("liftInstFABS: not yet implemented")
   694  }
   695  
   696  // --- [ FCHS ] ----------------------------------------------------------------
   697  
   698  // liftInstFCHS lifts the given x87 FCHS instruction to LLVM IR, emitting code
   699  // to f.
   700  func (f *Func) liftInstFCHS(inst *x86.Inst) error {
   701  	// FCHS - Change sign.
   702  	pretty.Println("inst:", inst)
   703  	panic("liftInstFCHS: not yet implemented")
   704  }
   705  
   706  // --- [ FRNDINT ] -------------------------------------------------------------
   707  
   708  // liftInstFRNDINT lifts the given x87 FRNDINT instruction to LLVM IR, emitting
   709  // code to f.
   710  func (f *Func) liftInstFRNDINT(inst *x86.Inst) error {
   711  	// FRNDINT - Round to integer.
   712  	pretty.Println("inst:", inst)
   713  	panic("liftInstFRNDINT: not yet implemented")
   714  }
   715  
   716  // --- [ FSCALE ] --------------------------------------------------------------
   717  
   718  // liftInstFSCALE lifts the given x87 FSCALE instruction to LLVM IR, emitting
   719  // code to f.
   720  func (f *Func) liftInstFSCALE(inst *x86.Inst) error {
   721  	// FSCALE - Scale by power of two.
   722  	pretty.Println("inst:", inst)
   723  	panic("liftInstFSCALE: not yet implemented")
   724  }
   725  
   726  // --- [ FSQRT ] ---------------------------------------------------------------
   727  
   728  // liftInstFSQRT lifts the given x87 FSQRT instruction to LLVM IR, emitting code
   729  // to f.
   730  func (f *Func) liftInstFSQRT(inst *x86.Inst) error {
   731  	// FSQRT - Square root.
   732  	pretty.Println("inst:", inst)
   733  	panic("liftInstFSQRT: not yet implemented")
   734  }
   735  
   736  // --- [ FXTRACT ] -------------------------------------------------------------
   737  
   738  // liftInstFXTRACT lifts the given x87 FXTRACT instruction to LLVM IR, emitting
   739  // code to f.
   740  func (f *Func) liftInstFXTRACT(inst *x86.Inst) error {
   741  	// FXTRACT - Extract exponent and significand.
   742  	pretty.Println("inst:", inst)
   743  	panic("liftInstFXTRACT: not yet implemented")
   744  }
   745  
   746  // === [ x87 FPU Comparison Instructions ] =====================================
   747  
   748  // --- [ FCOM ] ----------------------------------------------------------------
   749  
   750  // liftInstFCOM lifts the given x87 FCOM instruction to LLVM IR, emitting code
   751  // to f.
   752  func (f *Func) liftInstFCOM(inst *x86.Inst) error {
   753  	// FCOM - Compare floating-point.
   754  	//
   755  	//    FCOM m32fp          Compare ST(0) with m32fp.
   756  	//    FCOM m64fp          Compare ST(0) with m64fp.
   757  	//    FCOM ST(i)          Compare ST(0) with ST(i).
   758  	//    FCOM                Compare ST(0) with ST(1).
   759  	//
   760  	// Compares the contents of register ST(0) and source value and sets
   761  	// condition code flags C0, C2, and C3 in the FPU status word according to
   762  	// the results (see the table below).
   763  	//
   764  	//    Condition       C3 C2 C0
   765  	//
   766  	//    ST(0) > SRC      0  0  0
   767  	//    ST(0) < SRC      0  0  1
   768  	//    ST(0) = SRC      1  0  0
   769  	//    Unordered        1  1  1
   770  	if inst.Args[0] == nil {
   771  		panic(fmt.Errorf("support for zero-operand FCOM not yet implemented; instruction %v at address %v", inst, inst.Addr))
   772  	}
   773  	src := f.useArg(inst.Arg(0))
   774  	if !types.Equal(src.Type(), types.X86_FP80) {
   775  		src = f.cur.NewFPExt(src, types.X86_FP80)
   776  	}
   777  	st0 := f.fload()
   778  	a := f.cur.NewFCmp(enum.FPredOGT, st0, src)
   779  	b := f.cur.NewFCmp(enum.FPredOLT, st0, src)
   780  	c := f.cur.NewFCmp(enum.FPredOEQ, st0, src)
   781  	d := f.cur.NewFCmp(enum.FPredUNO, st0, src)
   782  	end := &ir.Block{}
   783  	targetA := &ir.Block{}
   784  	targetA.NewBr(end)
   785  	targetB := &ir.Block{}
   786  	targetB.NewBr(end)
   787  	targetC := &ir.Block{}
   788  	targetC.NewBr(end)
   789  	targetD := &ir.Block{}
   790  	targetD.NewBr(end)
   791  	next := &ir.Block{}
   792  	f.cur.NewCondBr(a, targetA, next)
   793  	f.cur = next
   794  	f.Blocks = append(f.Blocks, next)
   795  	next = &ir.Block{}
   796  	f.cur.NewCondBr(b, targetB, next)
   797  	f.cur = next
   798  	f.Blocks = append(f.Blocks, next)
   799  	next = &ir.Block{}
   800  	f.cur.NewCondBr(c, targetC, next)
   801  	f.cur = next
   802  	f.Blocks = append(f.Blocks, next)
   803  	next = &ir.Block{}
   804  	f.cur.NewCondBr(d, targetD, end)
   805  	f.cur = targetA
   806  	f.Blocks = append(f.Blocks, targetA)
   807  	f.defFStatus(C0, constant.False)
   808  	f.defFStatus(C2, constant.False)
   809  	f.defFStatus(C3, constant.False)
   810  	f.cur = targetB
   811  	f.Blocks = append(f.Blocks, targetB)
   812  	f.defFStatus(C0, constant.True)
   813  	f.defFStatus(C2, constant.False)
   814  	f.defFStatus(C3, constant.False)
   815  	f.cur = targetC
   816  	f.Blocks = append(f.Blocks, targetC)
   817  	f.defFStatus(C0, constant.False)
   818  	f.defFStatus(C2, constant.False)
   819  	f.defFStatus(C3, constant.True)
   820  	f.cur = targetD
   821  	f.Blocks = append(f.Blocks, targetD)
   822  	f.defFStatus(C0, constant.True)
   823  	f.defFStatus(C2, constant.True)
   824  	f.defFStatus(C3, constant.True)
   825  	f.cur = end
   826  	f.Blocks = append(f.Blocks, end)
   827  	return nil
   828  }
   829  
   830  // --- [ FCOMP ] ---------------------------------------------------------------
   831  
   832  // liftInstFCOMP lifts the given x87 FCOMP instruction to LLVM IR, emitting code
   833  // to f.
   834  func (f *Func) liftInstFCOMP(inst *x86.Inst) error {
   835  	// FCOMP - Compare floating-point and pop.
   836  	//
   837  	//    FCOMP m32fp         Compare ST(0) with m32fp and pop register stack.
   838  	//    FCOMP m64fp         Compare ST(0) with m64fp and pop register stack.
   839  	//    FCOMP ST(i)         Compare ST(0) with ST(i) and pop register stack.
   840  	//    FCOMP               Compare ST(0) with ST(1) and pop register stack.
   841  	//
   842  	// Compares the contents of register ST(0) and source value and sets
   843  	// condition code flags C0, C2, and C3 in the FPU status word according to
   844  	// the results (see the table below).
   845  	//
   846  	//    Condition       C3 C2 C0
   847  	//
   848  	//    ST(0) > SRC      0  0  0
   849  	//    ST(0) < SRC      0  0  1
   850  	//    ST(0) = SRC      1  0  0
   851  	//    Unordered        1  1  1
   852  	if err := f.liftInstFCOM(inst); err != nil {
   853  		return errors.WithStack(err)
   854  	}
   855  	f.pop()
   856  	return nil
   857  }
   858  
   859  // --- [ FCOMPP ] --------------------------------------------------------------
   860  
   861  // liftInstFCOMPP lifts the given x87 FCOMPP instruction to LLVM IR, emitting
   862  // code to f.
   863  func (f *Func) liftInstFCOMPP(inst *x86.Inst) error {
   864  	// FCOMPP - Compare floating-point and pop twice.
   865  	//
   866  	//    FCOMPP              Compare ST(0) with ST(1) and pop register stack twice.
   867  	//
   868  	// Compares the contents of register ST(0) and source value and sets
   869  	// condition code flags C0, C2, and C3 in the FPU status word according to
   870  	// the results (see the table below).
   871  	//
   872  	//    Condition       C3 C2 C0
   873  	//
   874  	//    ST(0) > SRC      0  0  0
   875  	//    ST(0) < SRC      0  0  1
   876  	//    ST(0) = SRC      1  0  0
   877  	//    Unordered        1  1  1
   878  	if err := f.liftInstFCOM(inst); err != nil {
   879  		return errors.WithStack(err)
   880  	}
   881  	f.pop()
   882  	f.pop()
   883  	return nil
   884  }
   885  
   886  // --- [ FUCOM ] ---------------------------------------------------------------
   887  
   888  // liftInstFUCOM lifts the given x87 FUCOM instruction to LLVM IR, emitting code
   889  // to f.
   890  func (f *Func) liftInstFUCOM(inst *x86.Inst) error {
   891  	// FUCOM - Unordered compare floating-point.
   892  	pretty.Println("inst:", inst)
   893  	panic("liftInstFUCOM: not yet implemented")
   894  }
   895  
   896  // --- [ FUCOMP ] --------------------------------------------------------------
   897  
   898  // liftInstFUCOMP lifts the given x87 FUCOMP instruction to LLVM IR, emitting
   899  // code to f.
   900  func (f *Func) liftInstFUCOMP(inst *x86.Inst) error {
   901  	// FUCOMP - Unordered compare floating-point and pop.
   902  	pretty.Println("inst:", inst)
   903  	panic("liftInstFUCOMP: not yet implemented")
   904  }
   905  
   906  // --- [ FUCOMPP ] -------------------------------------------------------------
   907  
   908  // liftInstFUCOMPP lifts the given x87 FUCOMPP instruction to LLVM IR, emitting
   909  // code to f.
   910  func (f *Func) liftInstFUCOMPP(inst *x86.Inst) error {
   911  	// FUCOMPP - Unordered compare floating-point and pop twice.
   912  	pretty.Println("inst:", inst)
   913  	panic("liftInstFUCOMPP: not yet implemented")
   914  }
   915  
   916  // --- [ FICOM ] ---------------------------------------------------------------
   917  
   918  // liftInstFICOM lifts the given x87 FICOM instruction to LLVM IR, emitting code
   919  // to f.
   920  func (f *Func) liftInstFICOM(inst *x86.Inst) error {
   921  	// FICOM - Compare integer.
   922  	pretty.Println("inst:", inst)
   923  	panic("liftInstFICOM: not yet implemented")
   924  }
   925  
   926  // --- [ FICOMP ] --------------------------------------------------------------
   927  
   928  // liftInstFICOMP lifts the given x87 FICOMP instruction to LLVM IR, emitting
   929  // code to f.
   930  func (f *Func) liftInstFICOMP(inst *x86.Inst) error {
   931  	// FICOMP - Compare integer and pop.
   932  	pretty.Println("inst:", inst)
   933  	panic("liftInstFICOMP: not yet implemented")
   934  }
   935  
   936  // --- [ FCOMI ] ---------------------------------------------------------------
   937  
   938  // liftInstFCOMI lifts the given x87 FCOMI instruction to LLVM IR, emitting code
   939  // to f.
   940  func (f *Func) liftInstFCOMI(inst *x86.Inst) error {
   941  	// FCOMI - Compare floating-point and set EFLAGS.
   942  	pretty.Println("inst:", inst)
   943  	panic("liftInstFCOMI: not yet implemented")
   944  }
   945  
   946  // --- [ FUCOMI ] --------------------------------------------------------------
   947  
   948  // liftInstFUCOMI lifts the given x87 FUCOMI instruction to LLVM IR, emitting
   949  // code to f.
   950  func (f *Func) liftInstFUCOMI(inst *x86.Inst) error {
   951  	// FUCOMI - Unordered compare floating-point and set EFLAGS.
   952  	pretty.Println("inst:", inst)
   953  	panic("liftInstFUCOMI: not yet implemented")
   954  }
   955  
   956  // --- [ FCOMIP ] --------------------------------------------------------------
   957  
   958  // liftInstFCOMIP lifts the given x87 FCOMIP instruction to LLVM IR, emitting
   959  // code to f.
   960  func (f *Func) liftInstFCOMIP(inst *x86.Inst) error {
   961  	// FCOMIP - Compare floating-point, set EFLAGS, and pop.
   962  	pretty.Println("inst:", inst)
   963  	panic("liftInstFCOMIP: not yet implemented")
   964  }
   965  
   966  // --- [ FUCOMIP ] -------------------------------------------------------------
   967  
   968  // liftInstFUCOMIP lifts the given x87 FUCOMIP instruction to LLVM IR, emitting
   969  // code to f.
   970  func (f *Func) liftInstFUCOMIP(inst *x86.Inst) error {
   971  	// FUCOMIP - Unordered compare floating-point, set EFLAGS, and pop.
   972  	pretty.Println("inst:", inst)
   973  	panic("liftInstFUCOMIP: not yet implemented")
   974  }
   975  
   976  // --- [ FTST ] ----------------------------------------------------------------
   977  
   978  // liftInstFTST lifts the given x87 FTST instruction to LLVM IR, emitting code
   979  // to f.
   980  func (f *Func) liftInstFTST(inst *x86.Inst) error {
   981  	// FTST - Test floating-point (compare with 0.0).
   982  	pretty.Println("inst:", inst)
   983  	panic("liftInstFTST: not yet implemented")
   984  }
   985  
   986  // --- [ FXAM ] ----------------------------------------------------------------
   987  
   988  // liftInstFXAM lifts the given x87 FXAM instruction to LLVM IR, emitting code
   989  // to f.
   990  func (f *Func) liftInstFXAM(inst *x86.Inst) error {
   991  	// FXAM - Examine floating-point.
   992  	pretty.Println("inst:", inst)
   993  	panic("liftInstFXAM: not yet implemented")
   994  }
   995  
   996  // === [ x87 FPU Transcendental Instructions ] =================================
   997  
   998  // --- [ FSIN ] ----------------------------------------------------------------
   999  
  1000  // liftInstFSIN lifts the given x87 FSIN instruction to LLVM IR, emitting code
  1001  // to f.
  1002  func (f *Func) liftInstFSIN(inst *x86.Inst) error {
  1003  	// FSIN - Sine.
  1004  	pretty.Println("inst:", inst)
  1005  	panic("liftInstFSIN: not yet implemented")
  1006  }
  1007  
  1008  // --- [ FCOS ] ----------------------------------------------------------------
  1009  
  1010  // liftInstFCOS lifts the given x87 FCOS instruction to LLVM IR, emitting code
  1011  // to f.
  1012  func (f *Func) liftInstFCOS(inst *x86.Inst) error {
  1013  	// FCOS - Cosine.
  1014  	pretty.Println("inst:", inst)
  1015  	panic("liftInstFCOS: not yet implemented")
  1016  }
  1017  
  1018  // --- [ FSINCOS ] -------------------------------------------------------------
  1019  
  1020  // liftInstFSINCOS lifts the given x87 FSINCOS instruction to LLVM IR, emitting
  1021  // code to f.
  1022  func (f *Func) liftInstFSINCOS(inst *x86.Inst) error {
  1023  	// FSINCOS - Sine and cosine.
  1024  	pretty.Println("inst:", inst)
  1025  	panic("liftInstFSINCOS: not yet implemented")
  1026  }
  1027  
  1028  // --- [ FPTAN ] ---------------------------------------------------------------
  1029  
  1030  // liftInstFPTAN lifts the given x87 FPTAN instruction to LLVM IR, emitting code
  1031  // to f.
  1032  func (f *Func) liftInstFPTAN(inst *x86.Inst) error {
  1033  	// FPTAN - Partial tangent.
  1034  	pretty.Println("inst:", inst)
  1035  	panic("liftInstFPTAN: not yet implemented")
  1036  }
  1037  
  1038  // --- [ FPATAN ] --------------------------------------------------------------
  1039  
  1040  // liftInstFPATAN lifts the given x87 FPATAN instruction to LLVM IR, emitting
  1041  // code to f.
  1042  func (f *Func) liftInstFPATAN(inst *x86.Inst) error {
  1043  	// FPATAN - Partial arctangent.
  1044  	pretty.Println("inst:", inst)
  1045  	panic("liftInstFPATAN: not yet implemented")
  1046  }
  1047  
  1048  // --- [ F2XM1 ] ---------------------------------------------------------------
  1049  
  1050  // liftInstF2XM1 lifts the given x87 F2XM1 instruction to LLVM IR, emitting code
  1051  // to f.
  1052  func (f *Func) liftInstF2XM1(inst *x86.Inst) error {
  1053  	// F2XM1 - 2^x - 1.
  1054  	pretty.Println("inst:", inst)
  1055  	panic("liftInstF2XM1: not yet implemented")
  1056  }
  1057  
  1058  // --- [ FYL2X ] ---------------------------------------------------------------
  1059  
  1060  // liftInstFYL2X lifts the given x87 FYL2X instruction to LLVM IR, emitting code
  1061  // to f.
  1062  func (f *Func) liftInstFYL2X(inst *x86.Inst) error {
  1063  	// FYL2X - y*log_2(x).
  1064  	pretty.Println("inst:", inst)
  1065  	panic("liftInstFYL2X: not yet implemented")
  1066  }
  1067  
  1068  // --- [ FYL2XP1 ] -------------------------------------------------------------
  1069  
  1070  // liftInstFYL2XP1 lifts the given x87 FYL2XP1 instruction to LLVM IR, emitting
  1071  // code to f.
  1072  func (f *Func) liftInstFYL2XP1(inst *x86.Inst) error {
  1073  	// FYL2XP1 - y*log_2(x+1).
  1074  	pretty.Println("inst:", inst)
  1075  	panic("liftInstFYL2XP1: not yet implemented")
  1076  }
  1077  
  1078  // === [ x87 FPU Load Constants Instructions ] =================================
  1079  
  1080  // --- [ FLD1 ] ----------------------------------------------------------------
  1081  
  1082  // liftInstFLD1 lifts the given x87 FLD1 instruction to LLVM IR, emitting code
  1083  // to f.
  1084  func (f *Func) liftInstFLD1(inst *x86.Inst) error {
  1085  	// FLD1 - Load +1.0.
  1086  	//
  1087  	//    FLD1                Push +1.0 onto the FPU register stack.
  1088  	//
  1089  	// Push one of seven commonly used constants (in double extended-precision
  1090  	// floating-point format) onto the FPU register stack.
  1091  	src := constant.NewFloat(types.X86_FP80, 1)
  1092  	f.fpush(src)
  1093  	return nil
  1094  }
  1095  
  1096  // --- [ FLDZ ] ----------------------------------------------------------------
  1097  
  1098  // liftInstFLDZ lifts the given x87 FLDZ instruction to LLVM IR, emitting code
  1099  // to f.
  1100  func (f *Func) liftInstFLDZ(inst *x86.Inst) error {
  1101  	// FLDZ - Load +0.0.
  1102  	//
  1103  	//    FLDZ                Push +0.0 onto the FPU register stack.
  1104  	//
  1105  	// Push one of seven commonly used constants (in double extended-precision
  1106  	// floating-point format) onto the FPU register stack.
  1107  	src := constant.NewFloat(types.X86_FP80, 0)
  1108  	f.fpush(src)
  1109  	return nil
  1110  }
  1111  
  1112  // --- [ FLDPI ] ---------------------------------------------------------------
  1113  
  1114  // liftInstFLDPI lifts the given x87 FLDPI instruction to LLVM IR, emitting code
  1115  // to f.
  1116  func (f *Func) liftInstFLDPI(inst *x86.Inst) error {
  1117  	// FLDPI - Load π.
  1118  	//
  1119  	//    FLDPI               Push π onto the FPU register stack.
  1120  	//
  1121  	// Push one of seven commonly used constants (in double extended-precision
  1122  	// floating-point format) onto the FPU register stack.
  1123  	src := constant.NewFloat(types.X86_FP80, math.Pi)
  1124  	f.fpush(src)
  1125  	return nil
  1126  }
  1127  
  1128  // --- [ FLDL2E ] --------------------------------------------------------------
  1129  
  1130  // liftInstFLDL2E lifts the given x87 FLDL2E instruction to LLVM IR, emitting
  1131  // code to f.
  1132  func (f *Func) liftInstFLDL2E(inst *x86.Inst) error {
  1133  	// FLDL2E - Load log_2(e).
  1134  	//
  1135  	//    FLDL2E              Push log_2(e) onto the FPU register stack.
  1136  	//
  1137  	// Push one of seven commonly used constants (in double extended-precision
  1138  	// floating-point format) onto the FPU register stack.
  1139  	src := constant.NewFloat(types.X86_FP80, math.Log2E)
  1140  	f.fpush(src)
  1141  	return nil
  1142  }
  1143  
  1144  // --- [ FLDLN2 ] --------------------------------------------------------------
  1145  
  1146  // liftInstFLDLN2 lifts the given x87 FLDLN2 instruction to LLVM IR, emitting
  1147  // code to f.
  1148  func (f *Func) liftInstFLDLN2(inst *x86.Inst) error {
  1149  	// FLDLN2 - Load log_e(2).
  1150  	//
  1151  	//    FLDLN2              Push log_e(2) onto the FPU register stack.
  1152  	//
  1153  	// Push one of seven commonly used constants (in double extended-precision
  1154  	// floating-point format) onto the FPU register stack.
  1155  	src := constant.NewFloat(types.X86_FP80, math.Ln2)
  1156  	f.fpush(src)
  1157  	return nil
  1158  }
  1159  
  1160  // --- [ FLDL2T ] --------------------------------------------------------------
  1161  
  1162  // liftInstFLDL2T lifts the given x87 FLDL2T instruction to LLVM IR, emitting
  1163  // code to f.
  1164  func (f *Func) liftInstFLDL2T(inst *x86.Inst) error {
  1165  	// FLDL2T - Load log_2(10).
  1166  	//
  1167  	//    FLDL2T              Push log_2(10) onto the FPU register stack.
  1168  	//
  1169  	// Push one of seven commonly used constants (in double extended-precision
  1170  	// floating-point format) onto the FPU register stack.
  1171  	src := constant.NewFloat(types.X86_FP80, math.Log2(10))
  1172  	f.fpush(src)
  1173  	return nil
  1174  }
  1175  
  1176  // --- [ FLDLG2 ] --------------------------------------------------------------
  1177  
  1178  // liftInstFLDLG2 lifts the given x87 FLDLG2 instruction to LLVM IR, emitting
  1179  // code to f.
  1180  func (f *Func) liftInstFLDLG2(inst *x86.Inst) error {
  1181  	// FLDLG2 - Load log_10(2).
  1182  	//
  1183  	//    FLDLG2              Push log_10(2) onto the FPU register stack.
  1184  	//
  1185  	// Push one of seven commonly used constants (in double extended-precision
  1186  	// floating-point format) onto the FPU register stack.
  1187  	src := constant.NewFloat(types.X86_FP80, math.Log10(2))
  1188  	f.fpush(src)
  1189  	return nil
  1190  }
  1191  
  1192  // === [ x87 FPU Control Instructions ] ========================================
  1193  
  1194  // --- [ FINCSTP ] -------------------------------------------------------------
  1195  
  1196  // liftInstFINCSTP lifts the given x87 FINCSTP instruction to LLVM IR, emitting
  1197  // code to f.
  1198  func (f *Func) liftInstFINCSTP(inst *x86.Inst) error {
  1199  	// FINCSTP - Increment FPU register stack pointer.
  1200  	pretty.Println("inst:", inst)
  1201  	panic("liftInstFINCSTP: not yet implemented")
  1202  }
  1203  
  1204  // --- [ FDECSTP ] -------------------------------------------------------------
  1205  
  1206  // liftInstFDECSTP lifts the given x87 FDECSTP instruction to LLVM IR, emitting
  1207  // code to f.
  1208  func (f *Func) liftInstFDECSTP(inst *x86.Inst) error {
  1209  	// FDECSTP - Decrement FPU register stack pointer.
  1210  	pretty.Println("inst:", inst)
  1211  	panic("liftInstFDECSTP: not yet implemented")
  1212  }
  1213  
  1214  // --- [ FFREE ] ---------------------------------------------------------------
  1215  
  1216  // liftInstFFREE lifts the given x87 FFREE instruction to LLVM IR, emitting code
  1217  // to f.
  1218  func (f *Func) liftInstFFREE(inst *x86.Inst) error {
  1219  	// FFREE - Free floating-point register.
  1220  	pretty.Println("inst:", inst)
  1221  	panic("liftInstFFREE: not yet implemented")
  1222  }
  1223  
  1224  // --- [ FINIT ] ---------------------------------------------------------------
  1225  
  1226  // liftInstFINIT lifts the given x87 FINIT instruction to LLVM IR, emitting code
  1227  // to f.
  1228  func (f *Func) liftInstFINIT(inst *x86.Inst) error {
  1229  	// FINIT - Initialize FPU after checking error conditions.
  1230  	pretty.Println("inst:", inst)
  1231  	panic("liftInstFINIT: not yet implemented")
  1232  }
  1233  
  1234  // --- [ FNINIT ] --------------------------------------------------------------
  1235  
  1236  // liftInstFNINIT lifts the given x87 FNINIT instruction to LLVM IR, emitting
  1237  // code to f.
  1238  func (f *Func) liftInstFNINIT(inst *x86.Inst) error {
  1239  	// FNINIT - Initialize FPU without checking error conditions.
  1240  	pretty.Println("inst:", inst)
  1241  	panic("liftInstFNINIT: not yet implemented")
  1242  }
  1243  
  1244  // --- [ FCLEX ] ---------------------------------------------------------------
  1245  
  1246  // liftInstFCLEX lifts the given x87 FCLEX instruction to LLVM IR, emitting code
  1247  // to f.
  1248  func (f *Func) liftInstFCLEX(inst *x86.Inst) error {
  1249  	// FCLEX - Clear floating-point exception flags after checking for error
  1250  	// conditions.
  1251  	pretty.Println("inst:", inst)
  1252  	panic("liftInstFCLEX: not yet implemented")
  1253  }
  1254  
  1255  // --- [ FNCLEX ] --------------------------------------------------------------
  1256  
  1257  // liftInstFNCLEX lifts the given x87 FNCLEX instruction to LLVM IR, emitting
  1258  // code to f.
  1259  func (f *Func) liftInstFNCLEX(inst *x86.Inst) error {
  1260  	// FNCLEX - Clear floating-point exception flags without checking for error
  1261  	// conditions.
  1262  	pretty.Println("inst:", inst)
  1263  	panic("liftInstFNCLEX: not yet implemented")
  1264  }
  1265  
  1266  // --- [ FSTCW ] ---------------------------------------------------------------
  1267  
  1268  // liftInstFSTCW lifts the given x87 FSTCW instruction to LLVM IR, emitting code
  1269  // to f.
  1270  func (f *Func) liftInstFSTCW(inst *x86.Inst) error {
  1271  	// FSTCW - Store FPU control word after checking error conditions.
  1272  	pretty.Println("inst:", inst)
  1273  	panic("liftInstFSTCW: not yet implemented")
  1274  }
  1275  
  1276  // --- [ FNSTCW ] --------------------------------------------------------------
  1277  
  1278  // liftInstFNSTCW lifts the given x87 FNSTCW instruction to LLVM IR, emitting
  1279  // code to f.
  1280  func (f *Func) liftInstFNSTCW(inst *x86.Inst) error {
  1281  	// FNSTCW - Store FPU control word without checking error conditions.
  1282  	pretty.Println("inst:", inst)
  1283  	panic("liftInstFNSTCW: not yet implemented")
  1284  }
  1285  
  1286  // --- [ FLDCW ] ---------------------------------------------------------------
  1287  
  1288  // liftInstFLDCW lifts the given x87 FLDCW instruction to LLVM IR, emitting code
  1289  // to f.
  1290  func (f *Func) liftInstFLDCW(inst *x86.Inst) error {
  1291  	// FLDCW - Load FPU control word.
  1292  	pretty.Println("inst:", inst)
  1293  	panic("liftInstFLDCW: not yet implemented")
  1294  }
  1295  
  1296  // --- [ FSTENV ] --------------------------------------------------------------
  1297  
  1298  // liftInstFSTENV lifts the given x87 FSTENV instruction to LLVM IR, emitting
  1299  // code to f.
  1300  func (f *Func) liftInstFSTENV(inst *x86.Inst) error {
  1301  	// FSTENV - Store FPU environment after checking error conditions.
  1302  	pretty.Println("inst:", inst)
  1303  	panic("liftInstFSTENV: not yet implemented")
  1304  }
  1305  
  1306  // --- [ FNSTENV ] -------------------------------------------------------------
  1307  
  1308  // liftInstFNSTENV lifts the given x87 FNSTENV instruction to LLVM IR, emitting
  1309  // code to f.
  1310  func (f *Func) liftInstFNSTENV(inst *x86.Inst) error {
  1311  	// FNSTENV - Store FPU environment without checking error conditions.
  1312  	pretty.Println("inst:", inst)
  1313  	panic("liftInstFNSTENV: not yet implemented")
  1314  }
  1315  
  1316  // --- [ FLDENV ] --------------------------------------------------------------
  1317  
  1318  // liftInstFLDENV lifts the given x87 FLDENV instruction to LLVM IR, emitting
  1319  // code to f.
  1320  func (f *Func) liftInstFLDENV(inst *x86.Inst) error {
  1321  	// FLDENV - Load FPU environment.
  1322  	pretty.Println("inst:", inst)
  1323  	panic("liftInstFLDENV: not yet implemented")
  1324  }
  1325  
  1326  // --- [ FSAVE ] ---------------------------------------------------------------
  1327  
  1328  // liftInstFSAVE lifts the given x87 FSAVE instruction to LLVM IR, emitting code
  1329  // to f.
  1330  func (f *Func) liftInstFSAVE(inst *x86.Inst) error {
  1331  	// FSAVE - Save FPU state after checking error conditions.
  1332  	pretty.Println("inst:", inst)
  1333  	panic("liftInstFSAVE: not yet implemented")
  1334  }
  1335  
  1336  // --- [ FNSAVE ] --------------------------------------------------------------
  1337  
  1338  // liftInstFNSAVE lifts the given x87 FNSAVE instruction to LLVM IR, emitting
  1339  // code to f.
  1340  func (f *Func) liftInstFNSAVE(inst *x86.Inst) error {
  1341  	// FNSAVE - Save FPU state without checking error conditions.
  1342  	pretty.Println("inst:", inst)
  1343  	panic("liftInstFNSAVE: not yet implemented")
  1344  }
  1345  
  1346  // --- [ FRSTOR ] --------------------------------------------------------------
  1347  
  1348  // liftInstFRSTOR lifts the given x87 FRSTOR instruction to LLVM IR, emitting
  1349  // code to f.
  1350  func (f *Func) liftInstFRSTOR(inst *x86.Inst) error {
  1351  	// FRSTOR - Restore FPU state.
  1352  	pretty.Println("inst:", inst)
  1353  	panic("liftInstFRSTOR: not yet implemented")
  1354  }
  1355  
  1356  // --- [ FSTSW ] ---------------------------------------------------------------
  1357  
  1358  // liftInstFSTSW lifts the given x87 FSTSW instruction to LLVM IR, emitting code
  1359  // to f.
  1360  func (f *Func) liftInstFSTSW(inst *x86.Inst) error {
  1361  	// FSTSW - Store FPU status word after checking error conditions.
  1362  	//
  1363  	//    FSTSW m16           Store FPU status word at m16 after checking for pending unmasked floating-point exceptions.
  1364  	//    FSTSW AX            Store FPU status word in AX register after checking for pending unmasked floating-point exceptions.
  1365  	//
  1366  	// Stores the current value of the x87 FPU status word in the destination
  1367  	// location.
  1368  	if err := f.liftInstFNSTSW(inst); err != nil {
  1369  		return errors.WithStack(err)
  1370  	}
  1371  	// TODO: Check FPU error condition.
  1372  	return nil
  1373  }
  1374  
  1375  // --- [ FNSTSW ] --------------------------------------------------------------
  1376  
  1377  // liftInstFNSTSW lifts the given x87 FNSTSW instruction to LLVM IR, emitting
  1378  // code to f.
  1379  func (f *Func) liftInstFNSTSW(inst *x86.Inst) error {
  1380  	// FNSTSW - Store FPU status word without checking error conditions.
  1381  	//
  1382  	//    FNSTSW m16          Store FPU status word at m16 without checking for pending unmasked floating-point exceptions.
  1383  	//    FNSTSW AX           Store FPU status word in AX register without checking for pending unmasked floating-point exceptions.
  1384  	//
  1385  	// Stores the current value of the x87 FPU status word in the destination
  1386  	// location.
  1387  
  1388  	// Load FPU status flags.
  1389  	b := f.useFStatus(Busy)
  1390  	c3 := f.useFStatus(C3)
  1391  	st := f.fload()
  1392  	c2 := f.useFStatus(C2)
  1393  	c1 := f.useFStatus(C1)
  1394  	c0 := f.useFStatus(C0)
  1395  	es := f.useFStatus(ES)
  1396  	sf := f.useFStatus(StackFault)
  1397  	pe := f.useFStatus(PE)
  1398  	ue := f.useFStatus(UE)
  1399  	oe := f.useFStatus(OE)
  1400  	ze := f.useFStatus(ZE)
  1401  	de := f.useFStatus(DE)
  1402  	ie := f.useFStatus(IE)
  1403  
  1404  	// Extend to 16-bit.
  1405  	b = f.cur.NewZExt(b, types.I16)
  1406  	c3 = f.cur.NewZExt(b, types.I16)
  1407  	st = f.cur.NewZExt(b, types.I16)
  1408  	c2 = f.cur.NewZExt(b, types.I16)
  1409  	c1 = f.cur.NewZExt(b, types.I16)
  1410  	c0 = f.cur.NewZExt(b, types.I16)
  1411  	es = f.cur.NewZExt(b, types.I16)
  1412  	sf = f.cur.NewZExt(b, types.I16)
  1413  	pe = f.cur.NewZExt(b, types.I16)
  1414  	ue = f.cur.NewZExt(b, types.I16)
  1415  	oe = f.cur.NewZExt(b, types.I16)
  1416  	ze = f.cur.NewZExt(b, types.I16)
  1417  	de = f.cur.NewZExt(b, types.I16)
  1418  	ie = f.cur.NewZExt(b, types.I16)
  1419  
  1420  	// x87 FPU Status Word
  1421  	//
  1422  	//    15    - B, FPU Busy
  1423  	//    14    - C3, Conditional Code 3
  1424  	//    11-13 - TOP, Top of Stack Pointer
  1425  	//    10    - C2, Conditional Code 2
  1426  	//     9    - C1, Conditional Code 1
  1427  	//     8    - C0, Conditional Code 0
  1428  	//     7    - ES, Exception Summary Status
  1429  	//     6    - SF, Stack Fault
  1430  	//     5    - PE, Precision
  1431  	//     4    - UE, Underflow
  1432  	//     3    - OE, Overflow
  1433  	//     2    - ZE, Zero Divide
  1434  	//     1    - DE, Denormalized Operand
  1435  	//     0    - IE, Invalid Operation
  1436  	//
  1437  	// ref: 8.1.3 x87 FPU Status Register, Intel 64 and IA-32 architectures
  1438  	// software developer's manual volume 1: Basic architecture.
  1439  	b = f.cur.NewShl(b, constant.NewInt(types.I64, 15))
  1440  	c3 = f.cur.NewShl(c3, constant.NewInt(types.I64, 14))
  1441  	st = f.cur.NewShl(st, constant.NewInt(types.I64, 11))
  1442  	c2 = f.cur.NewShl(c2, constant.NewInt(types.I64, 10))
  1443  	c1 = f.cur.NewShl(c1, constant.NewInt(types.I64, 9))
  1444  	c0 = f.cur.NewShl(c0, constant.NewInt(types.I64, 8))
  1445  	es = f.cur.NewShl(es, constant.NewInt(types.I64, 7))
  1446  	sf = f.cur.NewShl(sf, constant.NewInt(types.I64, 6))
  1447  	pe = f.cur.NewShl(pe, constant.NewInt(types.I64, 5))
  1448  	ue = f.cur.NewShl(ue, constant.NewInt(types.I64, 4))
  1449  	oe = f.cur.NewShl(oe, constant.NewInt(types.I64, 3))
  1450  	ze = f.cur.NewShl(ze, constant.NewInt(types.I64, 2))
  1451  	de = f.cur.NewShl(de, constant.NewInt(types.I64, 1))
  1452  	//ie = f.cur.NewShl(ie, constant.NewInt(0, types.I64))
  1453  
  1454  	tmp := f.cur.NewOr(b, c3)
  1455  	tmp = f.cur.NewOr(tmp, st)
  1456  	tmp = f.cur.NewOr(tmp, c2)
  1457  	tmp = f.cur.NewOr(tmp, c1)
  1458  	tmp = f.cur.NewOr(tmp, c0)
  1459  	tmp = f.cur.NewOr(tmp, es)
  1460  	tmp = f.cur.NewOr(tmp, sf)
  1461  	tmp = f.cur.NewOr(tmp, pe)
  1462  	tmp = f.cur.NewOr(tmp, ue)
  1463  	tmp = f.cur.NewOr(tmp, oe)
  1464  	tmp = f.cur.NewOr(tmp, ze)
  1465  	tmp = f.cur.NewOr(tmp, de)
  1466  	result := f.cur.NewOr(tmp, ie)
  1467  
  1468  	// Store FPU status flags.
  1469  	f.defArg(inst.Arg(0), result)
  1470  
  1471  	return nil
  1472  }
  1473  
  1474  // --- [ FWAIT ] ---------------------------------------------------------------
  1475  
  1476  // liftInstWAIT_FWAIT lifts the given x87 WAIT_FWAIT instruction to LLVM IR,
  1477  // emitting code to f.
  1478  func (f *Func) liftInstFWAIT(inst *x86.Inst) error {
  1479  	// FWAIT - Wait for FPU.
  1480  	pretty.Println("inst:", inst)
  1481  	panic("liftInstFWAIT: not yet implemented")
  1482  }
  1483  
  1484  // --- [ FNOP ] ----------------------------------------------------------------
  1485  
  1486  // liftInstFNOP lifts the given x87 FNOP instruction to LLVM IR, emitting code
  1487  // to f.
  1488  func (f *Func) liftInstFNOP(inst *x86.Inst) error {
  1489  	// FNOP - FPU no operation.
  1490  	pretty.Println("inst:", inst)
  1491  	panic("liftInstFNOP: not yet implemented")
  1492  }
  1493  
  1494  // ### [ Helper functions ] ####################################################
  1495  
  1496  // fpush pushes the given value to the top of the FPU register stack, emitting
  1497  // code to f.
  1498  func (f *Func) fpush(src value.Value) {
  1499  	// Decrement st.
  1500  	tmp1 := f.cur.NewLoad(f.st)
  1501  	targetTrue := &ir.Block{}
  1502  	targetFalse := &ir.Block{}
  1503  	follow := &ir.Block{}
  1504  	targetTrue.NewBr(follow)
  1505  	targetFalse.NewBr(follow)
  1506  	zero := constant.NewInt(types.I8, 0)
  1507  	cond := f.cur.NewICmp(enum.IPredEQ, tmp1, zero)
  1508  	f.cur.NewCondBr(cond, targetTrue, targetFalse)
  1509  	f.cur = targetTrue
  1510  	f.Blocks = append(f.Blocks, targetTrue)
  1511  	seven := constant.NewInt(types.I8, 7)
  1512  	f.cur.NewStore(seven, f.st)
  1513  	f.cur = targetFalse
  1514  	f.Blocks = append(f.Blocks, targetFalse)
  1515  	one := constant.NewInt(types.I8, 1)
  1516  	tmp2 := f.cur.NewSub(tmp1, one)
  1517  	f.cur.NewStore(tmp2, f.st)
  1518  	f.cur = follow
  1519  	f.Blocks = append(f.Blocks, follow)
  1520  
  1521  	// Store arg at st(0).
  1522  	f.fstore(src)
  1523  }
  1524  
  1525  // fpop pops and returns the top of the FPU register stack, emitting code to f.
  1526  func (f *Func) fpop() value.Value {
  1527  	// Load arg from st(0).
  1528  	v := f.fload()
  1529  
  1530  	// TODO: Mark st(0) as empty before incrementing st.
  1531  
  1532  	// Increment st.
  1533  	tmp1 := f.cur.NewLoad(f.st)
  1534  	targetTrue := &ir.Block{}
  1535  	targetFalse := &ir.Block{}
  1536  	follow := &ir.Block{}
  1537  	targetTrue.NewBr(follow)
  1538  	targetFalse.NewBr(follow)
  1539  	zero := constant.NewInt(types.I8, 7)
  1540  	cond := f.cur.NewICmp(enum.IPredEQ, tmp1, zero)
  1541  	f.cur.NewCondBr(cond, targetTrue, targetFalse)
  1542  	f.cur = targetTrue
  1543  	f.Blocks = append(f.Blocks, targetTrue)
  1544  	seven := constant.NewInt(types.I8, 0)
  1545  	f.cur.NewStore(seven, f.st)
  1546  	f.cur = targetFalse
  1547  	f.Blocks = append(f.Blocks, targetFalse)
  1548  	one := constant.NewInt(types.I8, 1)
  1549  	tmp2 := f.cur.NewAdd(tmp1, one)
  1550  	f.cur.NewStore(tmp2, f.st)
  1551  	f.cur = follow
  1552  	f.Blocks = append(f.Blocks, follow)
  1553  
  1554  	// Return arg.
  1555  	return v
  1556  }
  1557  
  1558  // fstore stores the source value to the top FPU register, emitting code to f.
  1559  func (f *Func) fstore(src value.Value) {
  1560  	// Store arg at st(0).
  1561  	end := &ir.Block{}
  1562  	cur := f.cur
  1563  	var cases []*ir.Case
  1564  	regs := []x86asm.Reg{x86asm.F0, x86asm.F1, x86asm.F2, x86asm.F3, x86asm.F4, x86asm.F5, x86asm.F6, x86asm.F7}
  1565  	for i, reg := range regs {
  1566  		block := &ir.Block{}
  1567  		block.NewBr(end)
  1568  		f.cur = block
  1569  		f.Blocks = append(f.Blocks, block)
  1570  		dst := f.reg(reg)
  1571  		f.cur.NewStore(src, dst)
  1572  		c := ir.NewCase(constant.NewInt(types.I8, int64(i)), block)
  1573  		cases = append(cases, c)
  1574  	}
  1575  	f.cur = cur
  1576  	st := f.cur.NewLoad(f.st)
  1577  	defaultTarget := &ir.Block{}
  1578  	defaultTarget.NewUnreachable()
  1579  	f.Blocks = append(f.Blocks, defaultTarget)
  1580  	f.cur.NewSwitch(st, defaultTarget, cases...)
  1581  	f.cur = end
  1582  	f.Blocks = append(f.Blocks, end)
  1583  }
  1584  
  1585  // fload returns the value of the top FPU register, emitting code to f.
  1586  func (f *Func) fload() value.Value {
  1587  	// Load value from st(0).
  1588  	end := &ir.Block{}
  1589  	cur := f.cur
  1590  	var cases []*ir.Case
  1591  	regs := []x86asm.Reg{x86asm.F0, x86asm.F1, x86asm.F2, x86asm.F3, x86asm.F4, x86asm.F5, x86asm.F6, x86asm.F7}
  1592  	var incs []*ir.Incoming
  1593  	for i, reg := range regs {
  1594  		block := &ir.Block{}
  1595  		block.NewBr(end)
  1596  		f.cur = block
  1597  		f.Blocks = append(f.Blocks, block)
  1598  		src := f.reg(reg)
  1599  		v := f.cur.NewLoad(src)
  1600  		inc := &ir.Incoming{
  1601  			X:    v,
  1602  			Pred: block,
  1603  		}
  1604  		incs = append(incs, inc)
  1605  		c := ir.NewCase(constant.NewInt(types.I8, int64(i)), block)
  1606  		cases = append(cases, c)
  1607  	}
  1608  	f.cur = cur
  1609  	st := f.cur.NewLoad(f.st)
  1610  	defaultTarget := &ir.Block{}
  1611  	defaultTarget.NewUnreachable()
  1612  	f.Blocks = append(f.Blocks, defaultTarget)
  1613  	f.cur.NewSwitch(st, defaultTarget, cases...)
  1614  	f.cur = end
  1615  	f.Blocks = append(f.Blocks, end)
  1616  	return f.cur.NewPhi(incs...)
  1617  }