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 }