mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2024-12-13 20:32:21 +00:00
- Remove Tilmann's custom truncate lowering: it completely hosed over
DAGcombine's ability to find reasons to remove truncates when they were not needed. Consequently, the CellSPU backend would produce correct, but _really slow and horrible_, code. Replaced with instruction sequences that do the equivalent truncation in SPUInstrInfo.td. - Re-examine how unaligned loads and stores work. Generated unaligned load code has been tested on the CellSPU hardware; see the i32operations.c and i64operations.c in CodeGen/CellSPU/useful-harnesses. (While they may be toy test code, it does prove that some real world code does compile correctly.) - Fix truncating stores in bug 3193 (note: unpack_df.ll will still make llc fault because i64 ult is not yet implemented.) - Added i64 eq and neq for setcc and select/setcc; started new instruction information file for them in SPU64InstrInfo.td. Additional i64 operations should be added to this file and not to SPUInstrInfo.td. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@61447 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
parent
1323e8bf6a
commit
f0569be4a9
@ -117,7 +117,7 @@ namespace {
|
||||
}
|
||||
|
||||
void
|
||||
printMemRegImmS7(const MachineInstr *MI, unsigned OpNo)
|
||||
printShufAddr(const MachineInstr *MI, unsigned OpNo)
|
||||
{
|
||||
char value = MI->getOperand(OpNo).getImm();
|
||||
O << (int) value;
|
||||
@ -183,16 +183,16 @@ namespace {
|
||||
}
|
||||
|
||||
void
|
||||
printMemRegImmS10(const MachineInstr *MI, unsigned OpNo)
|
||||
printDFormAddr(const MachineInstr *MI, unsigned OpNo)
|
||||
{
|
||||
const MachineOperand &MO = MI->getOperand(OpNo);
|
||||
assert(MO.isImm() &&
|
||||
"printMemRegImmS10 first operand is not immedate");
|
||||
"printDFormAddr first operand is not immedate");
|
||||
int64_t value = int64_t(MI->getOperand(OpNo).getImm());
|
||||
int16_t value16 = int16_t(value);
|
||||
assert((value16 >= -(1 << (9+4)) && value16 <= (1 << (9+4)) - 1)
|
||||
&& "Invalid dform s10 offset argument");
|
||||
O << value16 << "(";
|
||||
O << (value16 & ~0xf) << "(";
|
||||
printOperand(MI, OpNo+1);
|
||||
O << ")";
|
||||
}
|
||||
|
77
lib/Target/CellSPU/SPU64InstrInfo.td
Normal file
77
lib/Target/CellSPU/SPU64InstrInfo.td
Normal file
@ -0,0 +1,77 @@
|
||||
//-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~
|
||||
// 64-bit comparisons:
|
||||
//
|
||||
// 1. The instruction sequences for vector vice scalar differ by a
|
||||
// constant.
|
||||
//
|
||||
// 2. There are no "immediate" forms, since loading 64-bit constants
|
||||
// could be a constant pool load.
|
||||
//
|
||||
// 3. i64 setcc results are i32, which are subsequently converted to a FSM
|
||||
// mask when used in a select pattern.
|
||||
//
|
||||
// 4. v2i64 setcc results are v4i32, which can be converted to a FSM mask
|
||||
// (TODO)
|
||||
//
|
||||
// M00$E Kan be Pretty N@sTi!!!!! (appologies to Monty!)
|
||||
//-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~
|
||||
|
||||
// selb instruction definition for i64. Note that the selection mask is
|
||||
// a vector, produced by various forms of FSM:
|
||||
def SELBr64_cond:
|
||||
SELBInst<(outs R64C:$rT), (ins R64C:$rA, R64C:$rB, VECREG:$rC),
|
||||
[/* no pattern */]>;
|
||||
|
||||
class CodeFrag<dag frag> {
|
||||
dag Fragment = frag;
|
||||
}
|
||||
|
||||
class I64SELECTNegCond<PatFrag cond, CodeFrag cmpare>:
|
||||
Pat<(select (i32 (cond R64C:$rA, R64C:$rB)), R64C:$rTrue, R64C:$rFalse),
|
||||
(SELBr64_cond R64C:$rTrue, R64C:$rFalse, (FSMr32 cmpare.Fragment))>;
|
||||
|
||||
class I64SETCCNegCond<PatFrag cond, CodeFrag cmpare>:
|
||||
Pat<(cond R64C:$rA, R64C:$rB),
|
||||
(XORIr32 cmpare.Fragment, -1)>;
|
||||
|
||||
// The i64 seteq fragment that does the scalar->vector conversion and
|
||||
// comparison:
|
||||
def CEQr64compare:
|
||||
CodeFrag<(CGTIv4i32 (GBv4i32 (CEQv4i32 (ORv2i64_i64 R64C:$rA),
|
||||
(ORv2i64_i64 R64C:$rB))),
|
||||
0x0000000c)>;
|
||||
|
||||
|
||||
// The i64 seteq fragment that does the vector comparison
|
||||
def CEQv2i64compare:
|
||||
CodeFrag<(CGTIv4i32 (GBv4i32 (CEQv4i32 VECREG:$rA, VECREG:$rB)),
|
||||
0x0000000f)>;
|
||||
|
||||
// i64 seteq (equality): the setcc result is i32, which is converted to a
|
||||
// vector FSM mask when used in a select pattern.
|
||||
//
|
||||
// v2i64 seteq (equality): the setcc result is v4i32
|
||||
multiclass CompareEqual64 {
|
||||
// Plain old comparison, converts back to i32 scalar
|
||||
def r64: CodeFrag<(ORi32_v4i32 CEQr64compare.Fragment)>;
|
||||
def v2i64: CodeFrag<(ORi32_v4i32 CEQv2i64compare.Fragment)>;
|
||||
|
||||
// SELB mask from FSM:
|
||||
def r64mask: CodeFrag<(ORi32_v4i32 (FSMv4i32 CEQr64compare.Fragment))>;
|
||||
def v2i64mask: CodeFrag<(ORi32_v4i32 (FSMv4i32 CEQv2i64compare.Fragment))>;
|
||||
}
|
||||
|
||||
defm I64EQ: CompareEqual64;
|
||||
|
||||
def : Pat<(seteq R64C:$rA, R64C:$rB), I64EQr64.Fragment>;
|
||||
|
||||
def : Pat<(seteq (v2i64 VECREG:$rA), (v2i64 VECREG:$rB)),
|
||||
I64EQv2i64.Fragment>;
|
||||
|
||||
def I64Select:
|
||||
Pat<(select R32C:$rC, R64C:$rB, R64C:$rA),
|
||||
(SELBr64_cond R64C:$rA, R64C:$rB, (FSMr32 R32C:$rC))>;
|
||||
|
||||
def : I64SETCCNegCond<setne, I64EQr64>;
|
||||
|
||||
def : I64SELECTNegCond<setne, I64EQr64>;
|
@ -165,24 +165,23 @@ namespace {
|
||||
MVT VT;
|
||||
unsigned ldresult_ins; /// LDRESULT instruction (0 = undefined)
|
||||
bool ldresult_imm; /// LDRESULT instruction requires immediate?
|
||||
int prefslot_byte; /// Byte offset of the "preferred" slot
|
||||
unsigned lrinst; /// LR instruction
|
||||
};
|
||||
|
||||
const valtype_map_s valtype_map[] = {
|
||||
{ MVT::i1, 0, false, 3 },
|
||||
{ MVT::i8, SPU::ORBIr8, true, 3 },
|
||||
{ MVT::i16, SPU::ORHIr16, true, 2 },
|
||||
{ MVT::i32, SPU::ORIr32, true, 0 },
|
||||
{ MVT::i64, SPU::ORr64, false, 0 },
|
||||
{ MVT::f32, SPU::ORf32, false, 0 },
|
||||
{ MVT::f64, SPU::ORf64, false, 0 },
|
||||
{ MVT::i8, SPU::ORBIr8, true, SPU::LRr8 },
|
||||
{ MVT::i16, SPU::ORHIr16, true, SPU::LRr16 },
|
||||
{ MVT::i32, SPU::ORIr32, true, SPU::LRr32 },
|
||||
{ MVT::i64, SPU::ORr64, false, SPU::LRr64 },
|
||||
{ MVT::f32, SPU::ORf32, false, SPU::LRf32 },
|
||||
{ MVT::f64, SPU::ORf64, false, SPU::LRf64 },
|
||||
// vector types... (sigh!)
|
||||
{ MVT::v16i8, 0, false, 0 },
|
||||
{ MVT::v8i16, 0, false, 0 },
|
||||
{ MVT::v4i32, 0, false, 0 },
|
||||
{ MVT::v2i64, 0, false, 0 },
|
||||
{ MVT::v4f32, 0, false, 0 },
|
||||
{ MVT::v2f64, 0, false, 0 }
|
||||
{ MVT::v16i8, 0, false, SPU::LRv16i8 },
|
||||
{ MVT::v8i16, 0, false, SPU::LRv8i16 },
|
||||
{ MVT::v4i32, 0, false, SPU::LRv4i32 },
|
||||
{ MVT::v2i64, 0, false, SPU::LRv2i64 },
|
||||
{ MVT::v4f32, 0, false, SPU::LRv4f32 },
|
||||
{ MVT::v2f64, 0, false, SPU::LRv2f64 }
|
||||
};
|
||||
|
||||
const size_t n_valtype_map = sizeof(valtype_map) / sizeof(valtype_map[0]);
|
||||
@ -686,31 +685,32 @@ SPUDAGToDAGISel::Select(SDValue Op) {
|
||||
Result = CurDAG->getTargetNode(Opc, VT, MVT::Other, Arg, Arg, Chain);
|
||||
}
|
||||
|
||||
Chain = SDValue(Result, 1);
|
||||
|
||||
return Result;
|
||||
} else if (Opc == SPUISD::IndirectAddr) {
|
||||
SDValue Op0 = Op.getOperand(0);
|
||||
if (Op0.getOpcode() == SPUISD::LDRESULT) {
|
||||
/* || Op0.getOpcode() == SPUISD::AFormAddr) */
|
||||
// (IndirectAddr (LDRESULT, imm))
|
||||
SDValue Op1 = Op.getOperand(1);
|
||||
MVT VT = Op.getValueType();
|
||||
|
||||
DEBUG(cerr << "CellSPU: IndirectAddr(LDRESULT, imm):\nOp0 = ");
|
||||
DEBUG(Op.getOperand(0).getNode()->dump(CurDAG));
|
||||
DEBUG(cerr << "\nOp1 = ");
|
||||
DEBUG(Op.getOperand(1).getNode()->dump(CurDAG));
|
||||
DEBUG(cerr << "\n");
|
||||
// Look at the operands: SelectCode() will catch the cases that aren't
|
||||
// specifically handled here.
|
||||
//
|
||||
// SPUInstrInfo catches the following patterns:
|
||||
// (SPUindirect (SPUhi ...), (SPUlo ...))
|
||||
// (SPUindirect $sp, imm)
|
||||
MVT VT = Op.getValueType();
|
||||
SDValue Op0 = N->getOperand(0);
|
||||
SDValue Op1 = N->getOperand(1);
|
||||
RegisterSDNode *RN;
|
||||
|
||||
if ((Op0.getOpcode() != SPUISD::Hi && Op1.getOpcode() != SPUISD::Lo)
|
||||
|| (Op0.getOpcode() == ISD::Register
|
||||
&& ((RN = dyn_cast<RegisterSDNode>(Op0.getNode())) != 0
|
||||
&& RN->getReg() != SPU::R1))) {
|
||||
NewOpc = SPU::Ar32;
|
||||
if (Op1.getOpcode() == ISD::Constant) {
|
||||
ConstantSDNode *CN = cast<ConstantSDNode>(Op1);
|
||||
Op1 = CurDAG->getTargetConstant(CN->getZExtValue(), VT);
|
||||
Op1 = CurDAG->getTargetConstant(CN->getSExtValue(), VT);
|
||||
NewOpc = (isI32IntS10Immediate(CN) ? SPU::AIr32 : SPU::Ar32);
|
||||
Ops[0] = Op0;
|
||||
Ops[1] = Op1;
|
||||
n_ops = 2;
|
||||
}
|
||||
Ops[0] = Op0;
|
||||
Ops[1] = Op1;
|
||||
n_ops = 2;
|
||||
}
|
||||
}
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -39,7 +39,7 @@ namespace llvm {
|
||||
SHUFB, ///< Vector shuffle (permute)
|
||||
SHUFFLE_MASK, ///< Shuffle mask
|
||||
CNTB, ///< Count leading ones in bytes
|
||||
PROMOTE_SCALAR, ///< Promote scalar->vector
|
||||
PREFSLOT2VEC, ///< Promote scalar->vector
|
||||
VEC2PREFSLOT, ///< Extract element 0
|
||||
MPY, ///< 16-bit Multiply (low parts of a 32-bit)
|
||||
MPYU, ///< Multiply Unsigned
|
||||
@ -58,6 +58,7 @@ namespace llvm {
|
||||
ROTBYTES_LEFT_BITS, ///< Rotate bytes left by bit shift count
|
||||
SELECT_MASK, ///< Select Mask (FSM, FSMB, FSMH, FSMBI)
|
||||
SELB, ///< Select bits -> (b & mask) | (a & ~mask)
|
||||
GATHER_BITS, ///< Gather bits from bytes/words/halfwords
|
||||
ADD_EXTENDED, ///< Add extended, with carry
|
||||
CARRY_GENERATE, ///< Carry generate for ADD_EXTENDED
|
||||
SUB_EXTENDED, ///< Subtract extended, with borrow
|
||||
@ -120,6 +121,9 @@ namespace llvm {
|
||||
const SelectionDAG &DAG,
|
||||
unsigned Depth = 0) const;
|
||||
|
||||
virtual unsigned ComputeNumSignBitsForTargetNode(SDValue Op,
|
||||
unsigned Depth = 0) const;
|
||||
|
||||
ConstraintType getConstraintType(const std::string &ConstraintLetter) const;
|
||||
|
||||
std::pair<unsigned, const TargetRegisterClass*>
|
||||
|
@ -120,9 +120,8 @@ class CVTIntFPForm<bits<10> opcode, dag OOL, dag IOL, string asmstr,
|
||||
}
|
||||
|
||||
let RA = 0 in {
|
||||
class BICondForm<bits<11> opcode, string asmstr, list<dag> pattern>
|
||||
: RRForm<opcode, (outs), (ins R32C:$rA, R32C:$func), asmstr,
|
||||
BranchResolv, pattern>
|
||||
class BICondForm<bits<11> opcode, dag OOL, dag IOL, string asmstr, list<dag> pattern>
|
||||
: RRForm<opcode, OOL, IOL, asmstr, BranchResolv, pattern>
|
||||
{ }
|
||||
|
||||
let RT = 0 in {
|
||||
|
@ -34,10 +34,14 @@ namespace {
|
||||
inline bool isCondBranch(const MachineInstr *I) {
|
||||
unsigned opc = I->getOpcode();
|
||||
|
||||
return (opc == SPU::BRNZ
|
||||
|| opc == SPU::BRZ
|
||||
|| opc == SPU::BRHNZ
|
||||
|| opc == SPU::BRHZ);
|
||||
return (opc == SPU::BRNZr32
|
||||
|| opc == SPU::BRNZv4i32
|
||||
|| opc == SPU::BRZr32
|
||||
|| opc == SPU::BRZv4i32
|
||||
|| opc == SPU::BRHNZr16
|
||||
|| opc == SPU::BRHNZv8i16
|
||||
|| opc == SPU::BRHZr16
|
||||
|| opc == SPU::BRHZv8i16);
|
||||
}
|
||||
}
|
||||
|
||||
@ -103,6 +107,19 @@ SPUInstrInfo::isMoveInstr(const MachineInstr& MI,
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
case SPU::LRr8:
|
||||
case SPU::LRr16:
|
||||
case SPU::LRr32:
|
||||
case SPU::LRf32:
|
||||
case SPU::LRr64:
|
||||
case SPU::LRf64:
|
||||
case SPU::LRr128:
|
||||
case SPU::LRv16i8:
|
||||
case SPU::LRv8i16:
|
||||
case SPU::LRv4i32:
|
||||
case SPU::LRv4f32:
|
||||
case SPU::LRv2i64:
|
||||
case SPU::LRv2f64:
|
||||
case SPU::ORv16i8_i8:
|
||||
case SPU::ORv8i16_i16:
|
||||
case SPU::ORv4i32_i32:
|
||||
@ -114,7 +131,18 @@ SPUInstrInfo::isMoveInstr(const MachineInstr& MI,
|
||||
case SPU::ORi32_v4i32:
|
||||
case SPU::ORi64_v2i64:
|
||||
case SPU::ORf32_v4f32:
|
||||
case SPU::ORf64_v2f64:
|
||||
case SPU::ORf64_v2f64: {
|
||||
assert(MI.getNumOperands() == 2 &&
|
||||
MI.getOperand(0).isReg() &&
|
||||
MI.getOperand(1).isReg() &&
|
||||
"invalid SPU OR<type>_<vec> instruction!");
|
||||
if (MI.getOperand(0).getReg() == MI.getOperand(1).getReg()) {
|
||||
sourceReg = MI.getOperand(0).getReg();
|
||||
destReg = MI.getOperand(0).getReg();
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case SPU::ORv16i8:
|
||||
case SPU::ORv8i16:
|
||||
case SPU::ORv4i32:
|
||||
@ -198,18 +226,14 @@ SPUInstrInfo::isStoreToStackSlot(const MachineInstr *MI,
|
||||
case SPU::STQDr8: {
|
||||
const MachineOperand MOp1 = MI->getOperand(1);
|
||||
const MachineOperand MOp2 = MI->getOperand(2);
|
||||
if (MOp1.isImm()
|
||||
&& (MOp2.isFI()
|
||||
|| (MOp2.isReg() && MOp2.getReg() == SPU::R1))) {
|
||||
if (MOp2.isFI())
|
||||
FrameIndex = MOp2.getIndex();
|
||||
else
|
||||
FrameIndex = MOp1.getImm() / SPUFrameInfo::stackSlotSize();
|
||||
if (MOp1.isImm() && MOp2.isFI()) {
|
||||
FrameIndex = MOp2.getIndex();
|
||||
return MI->getOperand(0).getReg();
|
||||
}
|
||||
break;
|
||||
}
|
||||
case SPU::STQXv16i8:
|
||||
#if 0
|
||||
case SPU::STQXv16i8:
|
||||
case SPU::STQXv8i16:
|
||||
case SPU::STQXv4i32:
|
||||
case SPU::STQXv4f32:
|
||||
@ -226,6 +250,7 @@ SPUInstrInfo::isStoreToStackSlot(const MachineInstr *MI,
|
||||
return MI->getOperand(0).getReg();
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@ -292,6 +317,8 @@ SPUInstrInfo::storeRegToStackSlot(MachineBasicBlock &MBB,
|
||||
opc = (isValidFrameIdx ? SPU::STQDr16 : SPU::STQXr16);
|
||||
} else if (RC == SPU::R8CRegisterClass) {
|
||||
opc = (isValidFrameIdx ? SPU::STQDr8 : SPU::STQXr8);
|
||||
} else if (RC == SPU::VECREGRegisterClass) {
|
||||
opc = (isValidFrameIdx) ? SPU::STQDv16i8 : SPU::STQXv16i8;
|
||||
} else {
|
||||
assert(0 && "Unknown regclass!");
|
||||
abort();
|
||||
@ -366,6 +393,8 @@ SPUInstrInfo::loadRegFromStackSlot(MachineBasicBlock &MBB,
|
||||
opc = (isValidFrameIdx ? SPU::LQDr16 : SPU::LQXr16);
|
||||
} else if (RC == SPU::R8CRegisterClass) {
|
||||
opc = (isValidFrameIdx ? SPU::LQDr8 : SPU::LQXr8);
|
||||
} else if (RC == SPU::VECREGRegisterClass) {
|
||||
opc = (isValidFrameIdx) ? SPU::LQDv16i8 : SPU::LQXv16i8;
|
||||
} else {
|
||||
assert(0 && "Unknown regclass in loadRegFromStackSlot!");
|
||||
abort();
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -66,6 +66,13 @@ def SPUselb_type: SDTypeProfile<1, 3, [
|
||||
def SPUvecshift_type: SDTypeProfile<1, 2, [
|
||||
SDTCisSameAs<0, 1>, SDTCisInt<2>]>;
|
||||
|
||||
// SPU gather bits:
|
||||
// This instruction looks at each vector (word|halfword|byte) slot's low bit
|
||||
// and forms a mask in the low order bits of the first word's preferred slot.
|
||||
def SPUgatherbits_type: SDTypeProfile<1, 1, [
|
||||
/* no type constraints defined */
|
||||
]>;
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Synthetic/pseudo-instructions
|
||||
//===----------------------------------------------------------------------===//
|
||||
@ -137,14 +144,17 @@ def SPUselmask: SDNode<"SPUISD::SELECT_MASK", SPUselmask_type, []>;
|
||||
// SPU select bits instruction
|
||||
def SPUselb: SDNode<"SPUISD::SELB", SPUselb_type, []>;
|
||||
|
||||
// SPU gather bits instruction:
|
||||
def SPUgatherbits: SDNode<"SPUISD::GATHER_BITS", SPUgatherbits_type, []>;
|
||||
|
||||
// SPU floating point interpolate
|
||||
def SPUinterpolate : SDNode<"SPUISD::FPInterp", SDTFPBinOp, []>;
|
||||
|
||||
// SPU floating point reciprocal estimate (used for fdiv)
|
||||
def SPUreciprocalEst: SDNode<"SPUISD::FPRecipEst", SDTFPUnaryOp, []>;
|
||||
|
||||
def SDTpromote_scalar: SDTypeProfile<1, 1, []>;
|
||||
def SPUpromote_scalar: SDNode<"SPUISD::PROMOTE_SCALAR", SDTpromote_scalar, []>;
|
||||
def SDTprefslot2vec: SDTypeProfile<1, 1, []>;
|
||||
def SPUprefslot2vec: SDNode<"SPUISD::PREFSLOT2VEC", SDTprefslot2vec, []>;
|
||||
|
||||
def SPU_vec_demote : SDTypeProfile<1, 1, []>;
|
||||
def SPUvec2prefslot: SDNode<"SPUISD::VEC2PREFSLOT", SPU_vec_demote, []>;
|
||||
|
@ -609,15 +609,15 @@ def symbolLSA: Operand<i32> {
|
||||
let PrintMethod = "printSymbolLSA";
|
||||
}
|
||||
|
||||
// memory s7imm(reg) operaand
|
||||
def memri7 : Operand<iPTR> {
|
||||
let PrintMethod = "printMemRegImmS7";
|
||||
// Shuffle address memory operaand [s7imm(reg) d-format]
|
||||
def shufaddr : Operand<iPTR> {
|
||||
let PrintMethod = "printShufAddr";
|
||||
let MIOperandInfo = (ops s7imm:$imm, ptr_rc:$reg);
|
||||
}
|
||||
|
||||
// memory s10imm(reg) operand
|
||||
def memri10 : Operand<iPTR> {
|
||||
let PrintMethod = "printMemRegImmS10";
|
||||
def dformaddr : Operand<iPTR> {
|
||||
let PrintMethod = "printDFormAddr";
|
||||
let MIOperandInfo = (ops s10imm:$imm, ptr_rc:$reg);
|
||||
}
|
||||
|
||||
|
@ -403,11 +403,6 @@ SPURegisterInfo::determineFrameLayout(MachineFunction &MF) const
|
||||
void SPURegisterInfo::processFunctionBeforeCalleeSavedScan(MachineFunction &MF,
|
||||
RegScavenger *RS)
|
||||
const {
|
||||
#if 0
|
||||
// Save and clear the LR state.
|
||||
SPUFunctionInfo *FI = MF.getInfo<SPUFunctionInfo>();
|
||||
FI->setUsesLR(MF.getRegInfo().isPhysRegUsed(LR));
|
||||
#endif
|
||||
// Mark LR and SP unused, since the prolog spills them to stack and
|
||||
// we don't want anyone else to spill them for us.
|
||||
//
|
||||
|
@ -26,6 +26,13 @@ SPULinuxTargetAsmInfo::SPULinuxTargetAsmInfo(const SPUTargetMachine &TM) :
|
||||
PrivateGlobalPrefix = ".L";
|
||||
// This corresponds to what the gcc SPU compiler emits, for consistency.
|
||||
CStringSection = ".rodata.str";
|
||||
|
||||
// BSS section needs to be emitted as ".section"
|
||||
BSSSection = "\t.section\t.bss";
|
||||
BSSSection_ = getUnnamedSection("\t.section\t.bss",
|
||||
SectionFlags::Writeable | SectionFlags::BSS,
|
||||
true);
|
||||
|
||||
}
|
||||
|
||||
/// PreferredEHDataFormat - This hook allows the target to select data
|
||||
|
@ -2,7 +2,7 @@
|
||||
; RUN: llvm-as -o - %s | llc -march=cellspu -mattr=large_mem > %t2.s
|
||||
; RUN: grep bisl %t1.s | count 7
|
||||
; RUN: grep ila %t1.s | count 1
|
||||
; RUN: grep rotqbyi %t1.s | count 4
|
||||
; RUN: grep rotqby %t1.s | count 6
|
||||
; RUN: grep lqa %t1.s | count 1
|
||||
; RUN: grep lqd %t1.s | count 12
|
||||
; RUN: grep dispatch_tab %t1.s | count 5
|
||||
|
144
test/CodeGen/CellSPU/icmp64.ll
Normal file
144
test/CodeGen/CellSPU/icmp64.ll
Normal file
@ -0,0 +1,144 @@
|
||||
; RUN: llvm-as -o - %s | llc -march=cellspu > %t1.s
|
||||
; RUN: grep ceq %t1.s | count 4
|
||||
; RUN: grep cgti %t1.s | count 4
|
||||
; RUN: grep gb %t1.s | count 4
|
||||
; RUN: grep fsm %t1.s | count 2
|
||||
; RUN: grep xori %t1.s | count 1
|
||||
; RUN: grep selb %t1.s | count 2
|
||||
|
||||
target datalayout = "E-p:32:32:128-f64:64:128-f32:32:128-i64:32:128-i32:32:128-i16:16:128-i8:8:128-i1:8:128-a0:0:128-v128:128:128-s0:128:128"
|
||||
target triple = "spu"
|
||||
|
||||
; $3 = %arg1, $4 = %arg2, $5 = %val1, $6 = %val2
|
||||
; $3 = %arg1, $4 = %val1, $5 = %val2
|
||||
;
|
||||
; i64 integer comparisons:
|
||||
define i64 @icmp_eq_select_i64(i64 %arg1, i64 %arg2, i64 %val1, i64 %val2) nounwind {
|
||||
entry:
|
||||
%A = icmp eq i64 %arg1, %arg2
|
||||
%B = select i1 %A, i64 %val1, i64 %val2
|
||||
ret i64 %B
|
||||
}
|
||||
|
||||
define i1 @icmp_eq_setcc_i64(i64 %arg1, i64 %arg2, i64 %val1, i64 %val2) nounwind {
|
||||
entry:
|
||||
%A = icmp eq i64 %arg1, %arg2
|
||||
ret i1 %A
|
||||
}
|
||||
|
||||
define i64 @icmp_ne_select_i64(i64 %arg1, i64 %arg2, i64 %val1, i64 %val2) nounwind {
|
||||
entry:
|
||||
%A = icmp ne i64 %arg1, %arg2
|
||||
%B = select i1 %A, i64 %val1, i64 %val2
|
||||
ret i64 %B
|
||||
}
|
||||
|
||||
define i1 @icmp_ne_setcc_i64(i64 %arg1, i64 %arg2, i64 %val1, i64 %val2) nounwind {
|
||||
entry:
|
||||
%A = icmp ne i64 %arg1, %arg2
|
||||
ret i1 %A
|
||||
}
|
||||
|
||||
;; define i64 @icmp_ugt_select_i64(i64 %arg1, i64 %arg2, i64 %val1, i64 %val2) nounwind {
|
||||
;; entry:
|
||||
;; %A = icmp ugt i64 %arg1, %arg2
|
||||
;; %B = select i1 %A, i64 %val1, i64 %val2
|
||||
;; ret i64 %B
|
||||
;; }
|
||||
;;
|
||||
;; define i1 @icmp_ugt_setcc_i64(i64 %arg1, i64 %arg2, i64 %val1, i64 %val2) nounwind {
|
||||
;; entry:
|
||||
;; %A = icmp ugt i64 %arg1, %arg2
|
||||
;; ret i1 %A
|
||||
;; }
|
||||
;;
|
||||
;; define i64 @icmp_uge_select_i64(i64 %arg1, i64 %arg2, i64 %val1, i64 %val2) nounwind {
|
||||
;; entry:
|
||||
;; %A = icmp uge i64 %arg1, %arg2
|
||||
;; %B = select i1 %A, i64 %val1, i64 %val2
|
||||
;; ret i64 %B
|
||||
;; }
|
||||
;;
|
||||
;; define i1 @icmp_uge_setcc_i64(i64 %arg1, i64 %arg2, i64 %val1, i64 %val2) nounwind {
|
||||
;; entry:
|
||||
;; %A = icmp uge i64 %arg1, %arg2
|
||||
;; ret i1 %A
|
||||
;; }
|
||||
;;
|
||||
;; define i64 @icmp_ult_select_i64(i64 %arg1, i64 %arg2, i64 %val1, i64 %val2) nounwind {
|
||||
;; entry:
|
||||
;; %A = icmp ult i64 %arg1, %arg2
|
||||
;; %B = select i1 %A, i64 %val1, i64 %val2
|
||||
;; ret i64 %B
|
||||
;; }
|
||||
;;
|
||||
;; define i1 @icmp_ult_setcc_i64(i64 %arg1, i64 %arg2, i64 %val1, i64 %val2) nounwind {
|
||||
;; entry:
|
||||
;; %A = icmp ult i64 %arg1, %arg2
|
||||
;; ret i1 %A
|
||||
;; }
|
||||
;;
|
||||
;; define i64 @icmp_ule_select_i64(i64 %arg1, i64 %arg2, i64 %val1, i64 %val2) nounwind {
|
||||
;; entry:
|
||||
;; %A = icmp ule i64 %arg1, %arg2
|
||||
;; %B = select i1 %A, i64 %val1, i64 %val2
|
||||
;; ret i64 %B
|
||||
;; }
|
||||
;;
|
||||
;; define i1 @icmp_ule_setcc_i64(i64 %arg1, i64 %arg2, i64 %val1, i64 %val2) nounwind {
|
||||
;; entry:
|
||||
;; %A = icmp ule i64 %arg1, %arg2
|
||||
;; ret i1 %A
|
||||
;; }
|
||||
;;
|
||||
;; define i64 @icmp_sgt_select_i64(i64 %arg1, i64 %arg2, i64 %val1, i64 %val2) nounwind {
|
||||
;; entry:
|
||||
;; %A = icmp sgt i64 %arg1, %arg2
|
||||
;; %B = select i1 %A, i64 %val1, i64 %val2
|
||||
;; ret i64 %B
|
||||
;; }
|
||||
;;
|
||||
;; define i1 @icmp_sgt_setcc_i64(i64 %arg1, i64 %arg2, i64 %val1, i64 %val2) nounwind {
|
||||
;; entry:
|
||||
;; %A = icmp sgt i64 %arg1, %arg2
|
||||
;; ret i1 %A
|
||||
;; }
|
||||
;;
|
||||
;; define i64 @icmp_sge_select_i64(i64 %arg1, i64 %arg2, i64 %val1, i64 %val2) nounwind {
|
||||
;; entry:
|
||||
;; %A = icmp sge i64 %arg1, %arg2
|
||||
;; %B = select i1 %A, i64 %val1, i64 %val2
|
||||
;; ret i64 %B
|
||||
;; }
|
||||
;;
|
||||
;; define i1 @icmp_sge_setcc_i64(i64 %arg1, i64 %arg2, i64 %val1, i64 %val2) nounwind {
|
||||
;; entry:
|
||||
;; %A = icmp sge i64 %arg1, %arg2
|
||||
;; ret i1 %A
|
||||
;; }
|
||||
;;
|
||||
;; define i64 @icmp_slt_select_i64(i64 %arg1, i64 %arg2, i64 %val1, i64 %val2) nounwind {
|
||||
;; entry:
|
||||
;; %A = icmp slt i64 %arg1, %arg2
|
||||
;; %B = select i1 %A, i64 %val1, i64 %val2
|
||||
;; ret i64 %B
|
||||
;; }
|
||||
;;
|
||||
;; define i1 @icmp_slt_setcc_i64(i64 %arg1, i64 %arg2, i64 %val1, i64 %val2) nounwind {
|
||||
;; entry:
|
||||
;; %A = icmp slt i64 %arg1, %arg2
|
||||
;; ret i1 %A
|
||||
;; }
|
||||
;;
|
||||
;; define i64 @icmp_sle_select_i64(i64 %arg1, i64 %arg2, i64 %val1, i64 %val2) nounwind {
|
||||
;; entry:
|
||||
;; %A = icmp sle i64 %arg1, %arg2
|
||||
;; %B = select i1 %A, i64 %val1, i64 %val2
|
||||
;; ret i64 %B
|
||||
;; }
|
||||
;;
|
||||
;; define i1 @icmp_sle_setcc_i64(i64 %arg1, i64 %arg2, i64 %val1, i64 %val2) nounwind {
|
||||
;; entry:
|
||||
;; %A = icmp sle i64 %arg1, %arg2
|
||||
;; ret i1 %A
|
||||
;; }
|
@ -3,8 +3,17 @@
|
||||
; RUN: grep {stqd.*16(\$3)} %t1.s | count 4
|
||||
; RUN: grep 16256 %t1.s | count 2
|
||||
; RUN: grep 16384 %t1.s | count 1
|
||||
; RUN: grep 771 %t1.s | count 4
|
||||
; RUN: grep 515 %t1.s | count 2
|
||||
; RUN: grep 1799 %t1.s | count 2
|
||||
; RUN: grep 1543 %t1.s | count 5
|
||||
; RUN: grep 1029 %t1.s | count 3
|
||||
; RUN: grep {shli.*, 4} %t1.s | count 4
|
||||
; RUN: grep stqx %t1.s | count 4
|
||||
; RUN: grep ilhu %t1.s | count 11
|
||||
; RUN: grep iohl %t1.s | count 8
|
||||
; RUN: grep shufb %t1.s | count 15
|
||||
; RUN: grep frds %t1.s | count 1
|
||||
|
||||
; ModuleID = 'stores.bc'
|
||||
target datalayout = "E-p:32:32:128-f64:64:128-f32:32:128-i64:32:128-i32:32:128-i16:16:128-i8:8:128-i1:8:128-a0:0:128-v128:128:128-s0:128:128"
|
||||
@ -89,3 +98,54 @@ entry:
|
||||
store <4 x float> < float 1.000000e+00, float 1.000000e+00, float 1.000000e+00, float 1.000000e+00 >, <4 x float>* %arrayidx
|
||||
ret void
|
||||
}
|
||||
|
||||
; Test truncating stores:
|
||||
|
||||
define zeroext i8 @tstore_i16_i8(i16 signext %val, i8* %dest) nounwind {
|
||||
entry:
|
||||
%conv = trunc i16 %val to i8
|
||||
store i8 %conv, i8* %dest
|
||||
ret i8 %conv
|
||||
}
|
||||
|
||||
define zeroext i8 @tstore_i32_i8(i32 %val, i8* %dest) nounwind {
|
||||
entry:
|
||||
%conv = trunc i32 %val to i8
|
||||
store i8 %conv, i8* %dest
|
||||
ret i8 %conv
|
||||
}
|
||||
|
||||
define signext i16 @tstore_i32_i16(i32 %val, i16* %dest) nounwind {
|
||||
entry:
|
||||
%conv = trunc i32 %val to i16
|
||||
store i16 %conv, i16* %dest
|
||||
ret i16 %conv
|
||||
}
|
||||
|
||||
define zeroext i8 @tstore_i64_i8(i64 %val, i8* %dest) nounwind {
|
||||
entry:
|
||||
%conv = trunc i64 %val to i8
|
||||
store i8 %conv, i8* %dest
|
||||
ret i8 %conv
|
||||
}
|
||||
|
||||
define signext i16 @tstore_i64_i16(i64 %val, i16* %dest) nounwind {
|
||||
entry:
|
||||
%conv = trunc i64 %val to i16
|
||||
store i16 %conv, i16* %dest
|
||||
ret i16 %conv
|
||||
}
|
||||
|
||||
define i32 @tstore_i64_i32(i64 %val, i32* %dest) nounwind {
|
||||
entry:
|
||||
%conv = trunc i64 %val to i32
|
||||
store i32 %conv, i32* %dest
|
||||
ret i32 %conv
|
||||
}
|
||||
|
||||
define float @tstore_f64_f32(double %val, float* %dest) nounwind {
|
||||
entry:
|
||||
%conv = fptrunc double %val to float
|
||||
store float %conv, float* %dest
|
||||
ret float %conv
|
||||
}
|
||||
|
@ -35,7 +35,7 @@ target triple = "spu"
|
||||
; int i2; // offset 12 [ignored]
|
||||
; unsigned char c4; // offset 16 [ignored]
|
||||
; unsigned char c5; // offset 17 [ignored]
|
||||
; unsigned char c6; // offset 18 [ignored]
|
||||
; unsigned char c6; // offset 18 (rotate left by 14 bytes to byte 3)
|
||||
; unsigned char c7; // offset 19 (no rotate, in preferred slot)
|
||||
; int i3; // offset 20 [ignored]
|
||||
; int i4; // offset 24 [ignored]
|
||||
|
@ -1,16 +1,12 @@
|
||||
; RUN: llvm-as -o - %s | llc -march=cellspu > %t1.s
|
||||
; RUN: grep shufb %t1.s | count 9
|
||||
; RUN: grep shufb %t1.s | count 10
|
||||
; RUN: grep {ilhu.*1799} %t1.s | count 1
|
||||
; RUN: grep {ilhu.*771} %t1.s | count 3
|
||||
; RUN: grep {ilhu.*771} %t1.s | count 1
|
||||
; RUN: grep {ilhu.*1543} %t1.s | count 1
|
||||
; RUN: grep {ilhu.*1029} %t1.s | count 1
|
||||
; RUN: grep {ilhu.*515} %t1.s | count 1
|
||||
; RUN: grep {iohl.*1799} %t1.s | count 1
|
||||
; RUN: grep {iohl.*771} %t1.s | count 3
|
||||
; RUN: grep {iohl.*1543} %t1.s | count 2
|
||||
; RUN: grep {iohl.*515} %t1.s | count 1
|
||||
; RUN: grep xsbh %t1.s | count 6
|
||||
; RUN: grep sfh %t1.s | count 5
|
||||
; RUN: grep {ilhu.*515} %t1.s | count 2
|
||||
; RUN: grep xsbh %t1.s | count 2
|
||||
; RUN: grep sfh %t1.s | count 1
|
||||
|
||||
; ModuleID = 'trunc.bc'
|
||||
target datalayout = "E-p:32:32:128-i1:8:128-i8:8:128-i16:16:128-i32:32:128-i64:32:128-f32:32:128-f64:64:128-v64:64:64-v128:128:128-a0:0:128-s0:128:128"
|
||||
@ -41,23 +37,22 @@ target triple = "spu"
|
||||
; ret i64 %0
|
||||
;}
|
||||
|
||||
define i8 @trunc_i64_i8(i64 %u, i8 %v) nounwind readnone {
|
||||
define <16 x i8> @trunc_i64_i8(i64 %u, <16 x i8> %v) nounwind readnone {
|
||||
entry:
|
||||
%0 = trunc i64 %u to i8
|
||||
%1 = sub i8 %0, %v
|
||||
ret i8 %1
|
||||
%tmp1 = insertelement <16 x i8> %v, i8 %0, i32 10
|
||||
ret <16 x i8> %tmp1
|
||||
}
|
||||
define i16 @trunc_i64_i16(i64 %u, i16 %v) nounwind readnone {
|
||||
define <8 x i16> @trunc_i64_i16(i64 %u, <8 x i16> %v) nounwind readnone {
|
||||
entry:
|
||||
%0 = trunc i64 %u to i16
|
||||
%1 = sub i16 %0, %v
|
||||
ret i16 %1
|
||||
%tmp1 = insertelement <8 x i16> %v, i16 %0, i32 6
|
||||
ret <8 x i16> %tmp1
|
||||
}
|
||||
define i32 @trunc_i64_i32(i64 %u, i32 %v) nounwind readnone {
|
||||
entry:
|
||||
%0 = trunc i64 %u to i32
|
||||
%1 = sub i32 %0, %v
|
||||
ret i32 %1
|
||||
ret i32 %0
|
||||
}
|
||||
|
||||
define i8 @trunc_i32_i8(i32 %u, i8 %v) nounwind readnone {
|
||||
@ -66,16 +61,16 @@ entry:
|
||||
%1 = sub i8 %0, %v
|
||||
ret i8 %1
|
||||
}
|
||||
define i16 @trunc_i32_i16(i32 %u, i16 %v) nounwind readnone {
|
||||
define <8 x i16> @trunc_i32_i16(i32 %u, <8 x i16> %v) nounwind readnone {
|
||||
entry:
|
||||
%0 = trunc i32 %u to i16
|
||||
%1 = sub i16 %0, %v
|
||||
ret i16 %1
|
||||
%tmp1 = insertelement <8 x i16> %v, i16 %0, i32 3
|
||||
ret <8 x i16> %tmp1
|
||||
}
|
||||
|
||||
define i8 @trunc_i16_i8(i16 %u, i8 %v) nounwind readnone {
|
||||
define <16 x i8> @trunc_i16_i8(i16 %u, <16 x i8> %v) nounwind readnone {
|
||||
entry:
|
||||
%0 = trunc i16 %u to i8
|
||||
%1 = sub i8 %0, %v
|
||||
ret i8 %1
|
||||
%tmp1 = insertelement <16 x i8> %v, i8 %0, i32 5
|
||||
ret <16 x i8> %tmp1
|
||||
}
|
||||
|
69
test/CodeGen/CellSPU/useful-harnesses/i32operations.c
Normal file
69
test/CodeGen/CellSPU/useful-harnesses/i32operations.c
Normal file
@ -0,0 +1,69 @@
|
||||
#include <stdio.h>
|
||||
|
||||
typedef unsigned int uint32_t;
|
||||
typedef int int32_t;
|
||||
|
||||
const char *boolstring(int val) {
|
||||
return val ? "true" : "false";
|
||||
}
|
||||
|
||||
int i32_eq(int32_t a, int32_t b) {
|
||||
return (a == b);
|
||||
}
|
||||
|
||||
int i32_neq(int32_t a, int32_t b) {
|
||||
return (a != b);
|
||||
}
|
||||
|
||||
int32_t i32_eq_select(int32_t a, int32_t b, int32_t c, int32_t d) {
|
||||
return ((a == b) ? c : d);
|
||||
}
|
||||
|
||||
int32_t i32_neq_select(int32_t a, int32_t b, int32_t c, int32_t d) {
|
||||
return ((a != b) ? c : d);
|
||||
}
|
||||
|
||||
struct pred_s {
|
||||
const char *name;
|
||||
int (*predfunc)(int32_t, int32_t);
|
||||
int (*selfunc)(int32_t, int32_t, int32_t, int32_t);
|
||||
};
|
||||
|
||||
struct pred_s preds[] = {
|
||||
{ "eq", i32_eq, i32_eq_select },
|
||||
{ "neq", i32_neq, i32_neq_select }
|
||||
};
|
||||
|
||||
int main(void) {
|
||||
int i;
|
||||
int32_t a = 1234567890;
|
||||
int32_t b = 345678901;
|
||||
int32_t c = 1234500000;
|
||||
int32_t d = 10001;
|
||||
int32_t e = 10000;
|
||||
|
||||
printf("a = %12d (0x%08x)\n", a, a);
|
||||
printf("b = %12d (0x%08x)\n", b, b);
|
||||
printf("c = %12d (0x%08x)\n", c, c);
|
||||
printf("d = %12d (0x%08x)\n", d, d);
|
||||
printf("e = %12d (0x%08x)\n", e, e);
|
||||
printf("----------------------------------------\n");
|
||||
|
||||
for (i = 0; i < sizeof(preds)/sizeof(preds[0]); ++i) {
|
||||
printf("a %s a = %s\n", preds[i].name, boolstring((*preds[i].predfunc)(a, a)));
|
||||
printf("a %s a = %s\n", preds[i].name, boolstring((*preds[i].predfunc)(a, a)));
|
||||
printf("a %s b = %s\n", preds[i].name, boolstring((*preds[i].predfunc)(a, b)));
|
||||
printf("a %s c = %s\n", preds[i].name, boolstring((*preds[i].predfunc)(a, c)));
|
||||
printf("d %s e = %s\n", preds[i].name, boolstring((*preds[i].predfunc)(d, e)));
|
||||
printf("e %s e = %s\n", preds[i].name, boolstring((*preds[i].predfunc)(e, e)));
|
||||
|
||||
printf("a %s a ? c : d = %d\n", preds[i].name, (*preds[i].selfunc)(a, a, c, d));
|
||||
printf("a %s a ? c : d == c (%s)\n", preds[i].name, boolstring((*preds[i].selfunc)(a, a, c, d) == c));
|
||||
printf("a %s b ? c : d = %d\n", preds[i].name, (*preds[i].selfunc)(a, b, c, d));
|
||||
printf("a %s b ? c : d == d (%s)\n", preds[i].name, boolstring((*preds[i].selfunc)(a, b, c, d) == d));
|
||||
|
||||
printf("----------------------------------------\n");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
68
test/CodeGen/CellSPU/useful-harnesses/i64operations.c
Normal file
68
test/CodeGen/CellSPU/useful-harnesses/i64operations.c
Normal file
@ -0,0 +1,68 @@
|
||||
#include <stdio.h>
|
||||
|
||||
typedef unsigned long long int uint64_t;
|
||||
typedef long long int int64_t;
|
||||
|
||||
const char *boolstring(int val) {
|
||||
return val ? "true" : "false";
|
||||
}
|
||||
|
||||
int i64_eq(int64_t a, int64_t b) {
|
||||
return (a == b);
|
||||
}
|
||||
|
||||
int i64_neq(int64_t a, int64_t b) {
|
||||
return (a != b);
|
||||
}
|
||||
|
||||
int64_t i64_eq_select(int64_t a, int64_t b, int64_t c, int64_t d) {
|
||||
return ((a == b) ? c : d);
|
||||
}
|
||||
|
||||
int64_t i64_neq_select(int64_t a, int64_t b, int64_t c, int64_t d) {
|
||||
return ((a != b) ? c : d);
|
||||
}
|
||||
|
||||
struct pred_s {
|
||||
const char *name;
|
||||
int (*predfunc)(int64_t, int64_t);
|
||||
int64_t (*selfunc)(int64_t, int64_t, int64_t, int64_t);
|
||||
};
|
||||
|
||||
struct pred_s preds[] = {
|
||||
{ "eq", i64_eq, i64_eq_select },
|
||||
{ "neq", i64_neq, i64_neq_select }
|
||||
};
|
||||
|
||||
int main(void) {
|
||||
int i;
|
||||
int64_t a = 1234567890000LL;
|
||||
int64_t b = 2345678901234LL;
|
||||
int64_t c = 1234567890001LL;
|
||||
int64_t d = 10001LL;
|
||||
int64_t e = 10000LL;
|
||||
|
||||
printf("a = %16lld (0x%016llx)\n", a, a);
|
||||
printf("b = %16lld (0x%016llx)\n", b, b);
|
||||
printf("c = %16lld (0x%016llx)\n", c, c);
|
||||
printf("d = %16lld (0x%016llx)\n", d, d);
|
||||
printf("e = %16lld (0x%016llx)\n", e, e);
|
||||
printf("----------------------------------------\n");
|
||||
|
||||
for (i = 0; i < sizeof(preds)/sizeof(preds[0]); ++i) {
|
||||
printf("a %s a = %s\n", preds[i].name, boolstring((*preds[i].predfunc)(a, a)));
|
||||
printf("a %s b = %s\n", preds[i].name, boolstring((*preds[i].predfunc)(a, b)));
|
||||
printf("a %s c = %s\n", preds[i].name, boolstring((*preds[i].predfunc)(a, c)));
|
||||
printf("d %s e = %s\n", preds[i].name, boolstring((*preds[i].predfunc)(d, e)));
|
||||
printf("e %s e = %s\n", preds[i].name, boolstring((*preds[i].predfunc)(e, e)));
|
||||
|
||||
printf("a %s a ? c : d = %lld\n", preds[i].name, (*preds[i].selfunc)(a, a, c, d));
|
||||
printf("a %s a ? c : d == c (%s)\n", preds[i].name, boolstring((*preds[i].selfunc)(a, a, c, d) == c));
|
||||
printf("a %s b ? c : d = %lld\n", preds[i].name, (*preds[i].selfunc)(a, b, c, d));
|
||||
printf("a %s b ? c : d == d (%s)\n", preds[i].name, boolstring((*preds[i].selfunc)(a, b, c, d) == d));
|
||||
|
||||
printf("----------------------------------------\n");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
Loading…
Reference in New Issue
Block a user