- 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:
Scott Michel 2008-12-27 04:51:36 +00:00
parent 1323e8bf6a
commit f0569be4a9
19 changed files with 1504 additions and 648 deletions

View File

@ -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 << ")";
}

View 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>;

View File

@ -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

View File

@ -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*>

View File

@ -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 {

View File

@ -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

View File

@ -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, []>;

View File

@ -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);
}

View File

@ -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.
//

View File

@ -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

View File

@ -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

View 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
;; }

View File

@ -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
}

View File

@ -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]

View File

@ -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
}

View 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;
}

View 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;
}