mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2025-08-07 12:28:24 +00:00
Fix FP_TO_INT**_IN_MEM lowering.
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@25368 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
@@ -642,64 +642,6 @@ SDOperand X86DAGToDAGISel::Select(SDOperand N) {
|
|||||||
return CodeGenMap[N] = CurDAG->getTargetNode(Opc, VT, Result);
|
return CodeGenMap[N] = CurDAG->getTargetNode(Opc, VT, Result);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case X86ISD::FP_TO_INT16_IN_MEM:
|
|
||||||
case X86ISD::FP_TO_INT32_IN_MEM:
|
|
||||||
case X86ISD::FP_TO_INT64_IN_MEM: {
|
|
||||||
assert(N.getOperand(1).getValueType() == MVT::f64);
|
|
||||||
|
|
||||||
// Change the floating point control register to use "round towards zero"
|
|
||||||
// mode when truncating to an integer value.
|
|
||||||
MachineFunction &MF = CurDAG->getMachineFunction();
|
|
||||||
int CWFI = MF.getFrameInfo()->CreateStackObject(2, 2);
|
|
||||||
SDOperand CWSlot = CurDAG->getFrameIndex(CWFI, MVT::i32);
|
|
||||||
SDOperand Base, Scale, Index, Disp;
|
|
||||||
(void)SelectAddr(CWSlot, Base, Scale, Index, Disp);
|
|
||||||
SDOperand Chain = N.getOperand(0);
|
|
||||||
|
|
||||||
// Save the control word.
|
|
||||||
Chain = CurDAG->getTargetNode(X86::FNSTCW16m, MVT::Other,
|
|
||||||
Base, Scale, Index, Disp, Chain);
|
|
||||||
|
|
||||||
// Load the old value of the high byte of the control word.
|
|
||||||
SDOperand OldCW =
|
|
||||||
CurDAG->getTargetNode(X86::MOV16rm, MVT::i16, MVT::Other,
|
|
||||||
Base, Scale, Index, Disp, Chain);
|
|
||||||
Chain = OldCW.getValue(1);
|
|
||||||
|
|
||||||
// Set the high part to be round to zero...
|
|
||||||
Chain = CurDAG->getTargetNode(X86::MOV16mi, MVT::Other,
|
|
||||||
Base, Scale, Index, Disp,
|
|
||||||
CurDAG->getConstant(0xC7F, MVT::i16),
|
|
||||||
Chain);
|
|
||||||
|
|
||||||
// Reload the modified control word now...
|
|
||||||
Chain = CurDAG->getTargetNode(X86::FLDCW16m, MVT::Other,
|
|
||||||
Base, Scale, Index, Disp, Chain);
|
|
||||||
|
|
||||||
// Restore the memory image of control word to original value
|
|
||||||
Chain = CurDAG->getTargetNode(X86::MOV16mr, MVT::Other,
|
|
||||||
Base, Scale, Index, Disp, OldCW, Chain);
|
|
||||||
|
|
||||||
switch (Opcode) {
|
|
||||||
default: assert(0 && "Unknown FP_TO_INT*_IN_MEM");
|
|
||||||
case X86ISD::FP_TO_INT16_IN_MEM: Opc = X86::FpIST16m; break;
|
|
||||||
case X86ISD::FP_TO_INT32_IN_MEM: Opc = X86::FpIST32m; break;
|
|
||||||
case X86ISD::FP_TO_INT64_IN_MEM: Opc = X86::FpIST64m; break;
|
|
||||||
}
|
|
||||||
|
|
||||||
SDOperand N1 = Select(N.getOperand(1));
|
|
||||||
SDOperand Base2, Scale2, Index2, Disp2;
|
|
||||||
(void)SelectAddr(N.getOperand(2), Base2, Scale2, Index2, Disp2);
|
|
||||||
Chain = CurDAG->getTargetNode(Opc, MVT::Other,
|
|
||||||
Base2, Scale2, Index2, Disp2, N1, Chain);
|
|
||||||
|
|
||||||
// Reload the modified control word now...
|
|
||||||
CodeGenMap[N] =
|
|
||||||
Chain = CurDAG->getTargetNode(X86::FLDCW16m, MVT::Other,
|
|
||||||
Base, Scale, Index, Disp, Chain);
|
|
||||||
return Chain;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return SelectCode(N);
|
return SelectCode(N);
|
||||||
|
@@ -13,6 +13,7 @@
|
|||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
#include "X86.h"
|
#include "X86.h"
|
||||||
|
#include "X86InstrBuilder.h"
|
||||||
#include "X86ISelLowering.h"
|
#include "X86ISelLowering.h"
|
||||||
#include "X86TargetMachine.h"
|
#include "X86TargetMachine.h"
|
||||||
#include "llvm/CallingConv.h"
|
#include "llvm/CallingConv.h"
|
||||||
@@ -1261,54 +1262,117 @@ static bool hasFPCMov(unsigned X86CC) {
|
|||||||
MachineBasicBlock *
|
MachineBasicBlock *
|
||||||
X86TargetLowering::InsertAtEndOfBasicBlock(MachineInstr *MI,
|
X86TargetLowering::InsertAtEndOfBasicBlock(MachineInstr *MI,
|
||||||
MachineBasicBlock *BB) {
|
MachineBasicBlock *BB) {
|
||||||
assert((MI->getOpcode() == X86::CMOV_FR32 ||
|
switch (MI->getOpcode()) {
|
||||||
MI->getOpcode() == X86::CMOV_FR64) &&
|
default: assert(false && "Unexpected instr type to insert");
|
||||||
"Unexpected instr type to insert");
|
case X86::CMOV_FR32:
|
||||||
|
case X86::CMOV_FR64: {
|
||||||
|
// To "insert" a SELECT_CC instruction, we actually have to insert the diamond
|
||||||
|
// control-flow pattern. The incoming instruction knows the destination vreg
|
||||||
|
// to set, the condition code register to branch on, the true/false values to
|
||||||
|
// select between, and a branch opcode to use.
|
||||||
|
const BasicBlock *LLVM_BB = BB->getBasicBlock();
|
||||||
|
ilist<MachineBasicBlock>::iterator It = BB;
|
||||||
|
++It;
|
||||||
|
|
||||||
|
// thisMBB:
|
||||||
|
// ...
|
||||||
|
// TrueVal = ...
|
||||||
|
// cmpTY ccX, r1, r2
|
||||||
|
// bCC copy1MBB
|
||||||
|
// fallthrough --> copy0MBB
|
||||||
|
MachineBasicBlock *thisMBB = BB;
|
||||||
|
MachineBasicBlock *copy0MBB = new MachineBasicBlock(LLVM_BB);
|
||||||
|
MachineBasicBlock *sinkMBB = new MachineBasicBlock(LLVM_BB);
|
||||||
|
unsigned Opc = getCondBrOpcodeForX86CC(MI->getOperand(3).getImmedValue());
|
||||||
|
BuildMI(BB, Opc, 1).addMBB(sinkMBB);
|
||||||
|
MachineFunction *F = BB->getParent();
|
||||||
|
F->getBasicBlockList().insert(It, copy0MBB);
|
||||||
|
F->getBasicBlockList().insert(It, sinkMBB);
|
||||||
|
// Update machine-CFG edges
|
||||||
|
BB->addSuccessor(copy0MBB);
|
||||||
|
BB->addSuccessor(sinkMBB);
|
||||||
|
|
||||||
|
// copy0MBB:
|
||||||
|
// %FalseValue = ...
|
||||||
|
// # fallthrough to sinkMBB
|
||||||
|
BB = copy0MBB;
|
||||||
|
|
||||||
|
// Update machine-CFG edges
|
||||||
|
BB->addSuccessor(sinkMBB);
|
||||||
|
|
||||||
|
// sinkMBB:
|
||||||
|
// %Result = phi [ %FalseValue, copy0MBB ], [ %TrueValue, thisMBB ]
|
||||||
|
// ...
|
||||||
|
BB = sinkMBB;
|
||||||
|
BuildMI(BB, X86::PHI, 4, MI->getOperand(0).getReg())
|
||||||
|
.addReg(MI->getOperand(1).getReg()).addMBB(copy0MBB)
|
||||||
|
.addReg(MI->getOperand(2).getReg()).addMBB(thisMBB);
|
||||||
|
|
||||||
// To "insert" a SELECT_CC instruction, we actually have to insert the diamond
|
delete MI; // The pseudo instruction is gone now.
|
||||||
// control-flow pattern. The incoming instruction knows the destination vreg
|
return BB;
|
||||||
// to set, the condition code register to branch on, the true/false values to
|
}
|
||||||
// select between, and a branch opcode to use.
|
|
||||||
const BasicBlock *LLVM_BB = BB->getBasicBlock();
|
|
||||||
ilist<MachineBasicBlock>::iterator It = BB;
|
|
||||||
++It;
|
|
||||||
|
|
||||||
// thisMBB:
|
|
||||||
// ...
|
|
||||||
// TrueVal = ...
|
|
||||||
// cmpTY ccX, r1, r2
|
|
||||||
// bCC copy1MBB
|
|
||||||
// fallthrough --> copy0MBB
|
|
||||||
MachineBasicBlock *thisMBB = BB;
|
|
||||||
MachineBasicBlock *copy0MBB = new MachineBasicBlock(LLVM_BB);
|
|
||||||
MachineBasicBlock *sinkMBB = new MachineBasicBlock(LLVM_BB);
|
|
||||||
unsigned Opc = getCondBrOpcodeForX86CC(MI->getOperand(3).getImmedValue());
|
|
||||||
BuildMI(BB, Opc, 1).addMBB(sinkMBB);
|
|
||||||
MachineFunction *F = BB->getParent();
|
|
||||||
F->getBasicBlockList().insert(It, copy0MBB);
|
|
||||||
F->getBasicBlockList().insert(It, sinkMBB);
|
|
||||||
// Update machine-CFG edges
|
|
||||||
BB->addSuccessor(copy0MBB);
|
|
||||||
BB->addSuccessor(sinkMBB);
|
|
||||||
|
|
||||||
// copy0MBB:
|
|
||||||
// %FalseValue = ...
|
|
||||||
// # fallthrough to sinkMBB
|
|
||||||
BB = copy0MBB;
|
|
||||||
|
|
||||||
// Update machine-CFG edges
|
|
||||||
BB->addSuccessor(sinkMBB);
|
|
||||||
|
|
||||||
// sinkMBB:
|
|
||||||
// %Result = phi [ %FalseValue, copy0MBB ], [ %TrueValue, thisMBB ]
|
|
||||||
// ...
|
|
||||||
BB = sinkMBB;
|
|
||||||
BuildMI(BB, X86::PHI, 4, MI->getOperand(0).getReg())
|
|
||||||
.addReg(MI->getOperand(1).getReg()).addMBB(copy0MBB)
|
|
||||||
.addReg(MI->getOperand(2).getReg()).addMBB(thisMBB);
|
|
||||||
|
|
||||||
delete MI; // The pseudo instruction is gone now.
|
case X86::FP_TO_INT16_IN_MEM:
|
||||||
return BB;
|
case X86::FP_TO_INT32_IN_MEM:
|
||||||
|
case X86::FP_TO_INT64_IN_MEM: {
|
||||||
|
// Change the floating point control register to use "round towards zero"
|
||||||
|
// mode when truncating to an integer value.
|
||||||
|
MachineFunction *F = BB->getParent();
|
||||||
|
int CWFrameIdx = F->getFrameInfo()->CreateStackObject(2, 2);
|
||||||
|
addFrameReference(BuildMI(BB, X86::FNSTCW16m, 4), CWFrameIdx);
|
||||||
|
|
||||||
|
// Load the old value of the high byte of the control word...
|
||||||
|
unsigned OldCW =
|
||||||
|
F->getSSARegMap()->createVirtualRegister(X86::R16RegisterClass);
|
||||||
|
addFrameReference(BuildMI(BB, X86::MOV16rm, 4, OldCW), CWFrameIdx);
|
||||||
|
|
||||||
|
// Set the high part to be round to zero...
|
||||||
|
addFrameReference(BuildMI(BB, X86::MOV16mi, 5), CWFrameIdx).addImm(0xC7F);
|
||||||
|
|
||||||
|
// Reload the modified control word now...
|
||||||
|
addFrameReference(BuildMI(BB, X86::FLDCW16m, 4), CWFrameIdx);
|
||||||
|
|
||||||
|
// Restore the memory image of control word to original value
|
||||||
|
addFrameReference(BuildMI(BB, X86::MOV16mr, 5), CWFrameIdx).addReg(OldCW);
|
||||||
|
|
||||||
|
// Get the X86 opcode to use.
|
||||||
|
unsigned Opc;
|
||||||
|
switch (MI->getOpcode()) {
|
||||||
|
case X86::FP_TO_INT16_IN_MEM: Opc = X86::FpIST16m; break;
|
||||||
|
case X86::FP_TO_INT32_IN_MEM: Opc = X86::FpIST32m; break;
|
||||||
|
case X86::FP_TO_INT64_IN_MEM: Opc = X86::FpIST64m; break;
|
||||||
|
}
|
||||||
|
|
||||||
|
X86AddressMode AM;
|
||||||
|
MachineOperand &Op = MI->getOperand(0);
|
||||||
|
if (Op.isRegister()) {
|
||||||
|
AM.BaseType = X86AddressMode::RegBase;
|
||||||
|
AM.Base.Reg = Op.getReg();
|
||||||
|
} else {
|
||||||
|
AM.BaseType = X86AddressMode::FrameIndexBase;
|
||||||
|
AM.Base.FrameIndex = Op.getFrameIndex();
|
||||||
|
}
|
||||||
|
Op = MI->getOperand(1);
|
||||||
|
if (Op.isImmediate())
|
||||||
|
AM.Scale = Op.getImmedValue();
|
||||||
|
Op = MI->getOperand(2);
|
||||||
|
if (Op.isImmediate())
|
||||||
|
AM.IndexReg = Op.getImmedValue();
|
||||||
|
Op = MI->getOperand(3);
|
||||||
|
if (Op.isGlobalAddress()) {
|
||||||
|
AM.GV = Op.getGlobal();
|
||||||
|
} else {
|
||||||
|
AM.Disp = Op.getImmedValue();
|
||||||
|
}
|
||||||
|
addFullAddress(BuildMI(BB, Opc, 5), AM).addReg(MI->getOperand(4).getReg());
|
||||||
|
|
||||||
|
// Reload the original control word now.
|
||||||
|
addFrameReference(BuildMI(BB, X86::FLDCW16m, 4), CWFrameIdx);
|
||||||
|
|
||||||
|
delete MI; // The pseudo instruction is gone now.
|
||||||
|
return BB;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@@ -52,6 +52,7 @@ def SDTX86Fst : SDTypeProfile<0, 3, [SDTCisFP<0>,
|
|||||||
SDTCisPtrTy<1>, SDTCisVT<2, OtherVT>]>;
|
SDTCisPtrTy<1>, SDTCisVT<2, OtherVT>]>;
|
||||||
def SDTX86Fild : SDTypeProfile<1, 2, [SDTCisVT<0, f64>, SDTCisPtrTy<1>,
|
def SDTX86Fild : SDTypeProfile<1, 2, [SDTCisVT<0, f64>, SDTCisPtrTy<1>,
|
||||||
SDTCisVT<2, OtherVT>]>;
|
SDTCisVT<2, OtherVT>]>;
|
||||||
|
def SDTX86FpToIMem: SDTypeProfile<0, 2, [SDTCisFP<0>, SDTCisPtrTy<1>]>;
|
||||||
|
|
||||||
def SDTX86RepStr : SDTypeProfile<0, 1, [SDTCisVT<0, OtherVT>]>;
|
def SDTX86RepStr : SDTypeProfile<0, 1, [SDTCisVT<0, OtherVT>]>;
|
||||||
|
|
||||||
@@ -102,6 +103,12 @@ def X86fst : SDNode<"X86ISD::FST", SDTX86Fst,
|
|||||||
[SDNPHasChain]>;
|
[SDNPHasChain]>;
|
||||||
def X86fild : SDNode<"X86ISD::FILD", SDTX86Fild,
|
def X86fild : SDNode<"X86ISD::FILD", SDTX86Fild,
|
||||||
[SDNPHasChain]>;
|
[SDNPHasChain]>;
|
||||||
|
def X86fp_to_i16mem : SDNode<"X86ISD::FP_TO_INT16_IN_MEM", SDTX86FpToIMem,
|
||||||
|
[SDNPHasChain]>;
|
||||||
|
def X86fp_to_i32mem : SDNode<"X86ISD::FP_TO_INT32_IN_MEM", SDTX86FpToIMem,
|
||||||
|
[SDNPHasChain]>;
|
||||||
|
def X86fp_to_i64mem : SDNode<"X86ISD::FP_TO_INT64_IN_MEM", SDTX86FpToIMem,
|
||||||
|
[SDNPHasChain]>;
|
||||||
|
|
||||||
def X86rep_stos: SDNode<"X86ISD::REP_STOS", SDTX86RepStr,
|
def X86rep_stos: SDNode<"X86ISD::REP_STOS", SDTX86RepStr,
|
||||||
[SDNPHasChain, SDNPInFlag]>;
|
[SDNPHasChain, SDNPInFlag]>;
|
||||||
@@ -401,16 +408,32 @@ def IMPLICIT_DEF_FR64 : I<0, Pseudo, (ops FR64:$dst),
|
|||||||
let usesCustomDAGSchedInserter = 1 in { // Expanded by the scheduler.
|
let usesCustomDAGSchedInserter = 1 in { // Expanded by the scheduler.
|
||||||
def CMOV_FR32 : I<0, Pseudo,
|
def CMOV_FR32 : I<0, Pseudo,
|
||||||
(ops FR32:$dst, FR32:$t, FR32:$f, i8imm:$cond),
|
(ops FR32:$dst, FR32:$t, FR32:$f, i8imm:$cond),
|
||||||
"#CMOV PSEUDO!",
|
"#CMOV_FR32 PSEUDO!",
|
||||||
[(set FR32:$dst, (X86cmov FR32:$t, FR32:$f, imm:$cond,
|
[(set FR32:$dst, (X86cmov FR32:$t, FR32:$f, imm:$cond,
|
||||||
STATUS))]>;
|
STATUS))]>;
|
||||||
def CMOV_FR64 : I<0, Pseudo,
|
def CMOV_FR64 : I<0, Pseudo,
|
||||||
(ops FR64:$dst, FR64:$t, FR64:$f, i8imm:$cond),
|
(ops FR64:$dst, FR64:$t, FR64:$f, i8imm:$cond),
|
||||||
"#CMOV PSEUDO!",
|
"#CMOV_FR64 PSEUDO!",
|
||||||
[(set FR64:$dst, (X86cmov FR64:$t, FR64:$f, imm:$cond,
|
[(set FR64:$dst, (X86cmov FR64:$t, FR64:$f, imm:$cond,
|
||||||
STATUS))]>;
|
STATUS))]>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let usesCustomDAGSchedInserter = 1 in { // Expanded by the scheduler.
|
||||||
|
def FP_TO_INT16_IN_MEM : I<0, Pseudo,
|
||||||
|
(ops i16mem:$dst, RFP:$src),
|
||||||
|
"#FP_TO_INT16_IN_MEM PSEUDO!",
|
||||||
|
[(X86fp_to_i16mem RFP:$src, addr:$dst)]>;
|
||||||
|
def FP_TO_INT32_IN_MEM : I<0, Pseudo,
|
||||||
|
(ops i32mem:$dst, RFP:$src),
|
||||||
|
"#FP_TO_INT32_IN_MEM PSEUDO!",
|
||||||
|
[(X86fp_to_i32mem RFP:$src, addr:$dst)]>;
|
||||||
|
def FP_TO_INT64_IN_MEM : I<0, Pseudo,
|
||||||
|
(ops i64mem:$dst, RFP:$src),
|
||||||
|
"#FP_TO_INT64_IN_MEM PSEUDO!",
|
||||||
|
[(X86fp_to_i64mem RFP:$src, addr:$dst)]>;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
let isTerminator = 1 in
|
let isTerminator = 1 in
|
||||||
let Defs = [FP0, FP1, FP2, FP3, FP4, FP5, FP6] in
|
let Defs = [FP0, FP1, FP2, FP3, FP4, FP5, FP6] in
|
||||||
def FP_REG_KILL : I<0, Pseudo, (ops), "#FP_REG_KILL", []>;
|
def FP_REG_KILL : I<0, Pseudo, (ops), "#FP_REG_KILL", []>;
|
||||||
|
Reference in New Issue
Block a user