From dd950096b96a1535976b2d0db3bd90153c0be82a Mon Sep 17 00:00:00 2001 From: Scott Michel Date: Tue, 6 Jan 2009 03:36:14 +0000 Subject: [PATCH] CellSPU: - Fix bugs 3194, 3195: i128 load/stores produce correct code (although, we need to ensure that i128 is 16-byte aligned in real life), and 128 zero- extends are supported. - New td file: SPU128InstrInfo.td: this is where all new i128 support should be put in the future. - Continue to hammer on i64 operations and test cases; ensure that the only remaining problem will be i64 mul. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@61784 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/Target/CellSPU/SPU128InstrInfo.td | 22 + lib/Target/CellSPU/SPU64InstrInfo.td | 4 +- lib/Target/CellSPU/SPUCallingConv.td | 9 +- lib/Target/CellSPU/SPUISelLowering.cpp | 64 ++- lib/Target/CellSPU/SPUInstrInfo.cpp | 27 +- lib/Target/CellSPU/SPUInstrInfo.td | 144 +++++-- test/CodeGen/CellSPU/i64ops.ll | 26 +- .../CellSPU/useful-harnesses/i64operations.c | 378 +++++++++++++----- .../CellSPU/useful-harnesses/i64operations.h | 43 ++ 9 files changed, 558 insertions(+), 159 deletions(-) create mode 100644 lib/Target/CellSPU/SPU128InstrInfo.td create mode 100644 test/CodeGen/CellSPU/useful-harnesses/i64operations.h diff --git a/lib/Target/CellSPU/SPU128InstrInfo.td b/lib/Target/CellSPU/SPU128InstrInfo.td new file mode 100644 index 00000000000..6612901d411 --- /dev/null +++ b/lib/Target/CellSPU/SPU128InstrInfo.td @@ -0,0 +1,22 @@ +//===--- SPU128InstrInfo.td - Cell SPU 128-bit operations -*- tablegen -*--===// +// +// Cell SPU 128-bit operations +// +// Primary author: Scott Michel (scottm@aero.org) +//===----------------------------------------------------------------------===// + +// zext 32->128: Zero extend 32-bit to 128-bit +def : Pat<(i128 (zext R32C:$rSrc)), + (ROTQMBYIr128_zext_r32 R32C:$rSrc, 12)>; + +// zext 64->128: Zero extend 64-bit to 128-bit +def : Pat<(i128 (zext R64C:$rSrc)), + (ROTQMBYIr128_zext_r64 R64C:$rSrc, 8)>; + +// zext 16->128: Zero extend 16-bit to 128-bit +def : Pat<(i128 (zext R16C:$rSrc)), + (ROTQMBYIr128_zext_r32 (ANDi16i32 R16C:$rSrc, (ILAr32 0xffff)), 12)>; + +// zext 8->128: Zero extend 8-bit to 128-bit +def : Pat<(i128 (zext R8C:$rSrc)), + (ROTQMBYIr128_zext_r32 (ANDIi8i32 R8C:$rSrc, 0xf), 12)>; diff --git a/lib/Target/CellSPU/SPU64InstrInfo.td b/lib/Target/CellSPU/SPU64InstrInfo.td index d6fc2bd1fcf..74c0ecad7f8 100644 --- a/lib/Target/CellSPU/SPU64InstrInfo.td +++ b/lib/Target/CellSPU/SPU64InstrInfo.td @@ -48,8 +48,8 @@ class I64SETCCNegCond: // is in a 32-bit register that contains a select mask pattern (i.e., gather // bits result): -def : Pat<(select R32C:$rC, R64C:$rB, R64C:$rA), - (SELBr64_cond R64C:$rA, R64C:$rB, (FSMr32 R32C:$rC))>; +def : Pat<(select R32C:$rCond, R64C:$rFalse, R64C:$rTrue), + (SELBr64_cond R64C:$rTrue, R64C:$rFalse, (FSMr32 R32C:$rCond))>; //-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~ // The i64 seteq fragment that does the scalar->vector conversion and diff --git a/lib/Target/CellSPU/SPUCallingConv.td b/lib/Target/CellSPU/SPUCallingConv.td index 4bad19850a0..5213e424523 100644 --- a/lib/Target/CellSPU/SPUCallingConv.td +++ b/lib/Target/CellSPU/SPUCallingConv.td @@ -21,10 +21,11 @@ class CCIfSubtarget // Return-value convention for Cell SPU: Everything can be passed back via $3: def RetCC_SPU : CallingConv<[ - CCIfType<[i8], CCAssignToReg<[R3]>>, - CCIfType<[i16], CCAssignToReg<[R3]>>, - CCIfType<[i32], CCAssignToReg<[R3]>>, - CCIfType<[i64], CCAssignToReg<[R3]>>, + CCIfType<[i8], CCAssignToReg<[R3]>>, + CCIfType<[i16], CCAssignToReg<[R3]>>, + CCIfType<[i32], CCAssignToReg<[R3]>>, + CCIfType<[i64], CCAssignToReg<[R3]>>, + CCIfType<[i128], CCAssignToReg<[R3]>>, CCIfType<[f32, f64], CCAssignToReg<[R3]>>, CCIfType<[v16i8, v8i16, v4i32, v2i64, v4f32, v2f64], CCAssignToReg<[R3]>> ]>; diff --git a/lib/Target/CellSPU/SPUISelLowering.cpp b/lib/Target/CellSPU/SPUISelLowering.cpp index c13d696f3cf..7e63a872883 100644 --- a/lib/Target/CellSPU/SPUISelLowering.cpp +++ b/lib/Target/CellSPU/SPUISelLowering.cpp @@ -114,7 +114,7 @@ SPUTargetLowering::SPUTargetLowering(SPUTargetMachine &TM) setOperationAction(ISD::ConstantFP, MVT::f64, Custom); // SPU's loads and stores have to be custom lowered: - for (unsigned sctype = (unsigned) MVT::i8; sctype < (unsigned) MVT::f128; + for (unsigned sctype = (unsigned) MVT::i8; sctype < (unsigned) MVT::i128; ++sctype) { MVT VT = (MVT::SimpleValueType)sctype; @@ -947,6 +947,9 @@ LowerFORMAL_ARGUMENTS(SDValue Op, SelectionDAG &DAG, int &VarArgsFrameIndex) case MVT::i64: ArgRegClass = &SPU::R64CRegClass; break; + case MVT::i128: + ArgRegClass = &SPU::GPRCRegClass; + break; case MVT::f32: ArgRegClass = &SPU::R32FPRegClass; break; @@ -1070,6 +1073,8 @@ LowerCALL(SDValue Op, SelectionDAG &DAG, const SPUSubtarget *ST) { switch (Arg.getValueType().getSimpleVT()) { default: assert(0 && "Unexpected ValueType for argument!"); + case MVT::i8: + case MVT::i16: case MVT::i32: case MVT::i64: case MVT::i128: @@ -1220,6 +1225,11 @@ LowerCALL(SDValue Op, SelectionDAG &DAG, const SPUSubtarget *ST) { ResultVals[0] = Chain.getValue(0); NumResults = 1; break; + case MVT::i128: + Chain = DAG.getCopyFromReg(Chain, SPU::R3, MVT::i128, InFlag).getValue(1); + ResultVals[0] = Chain.getValue(0); + NumResults = 1; + break; case MVT::f32: case MVT::f64: Chain = DAG.getCopyFromReg(Chain, SPU::R3, TheCall->getValueType(0), @@ -2182,24 +2192,48 @@ static SDValue LowerI64Math(SDValue Op, SelectionDAG &DAG, unsigned Opc) MVT Op0VT = Op0.getValueType(); MVT Op0VecVT = MVT::getVectorVT(Op0VT, (128 / Op0VT.getSizeInBits())); - assert(Op0VT == MVT::i32 - && "CellSPU: Zero/sign extending something other than i32"); - - DEBUG(cerr << "CellSPU.LowerI64Math: lowering zero/sign/any extend\n"); - SDValue PromoteScalar = DAG.getNode(SPUISD::PREFSLOT2VEC, Op0VecVT, Op0); // Use a shuffle to zero extend the i32 to i64 directly: - SDValue shufMask = DAG.getNode(ISD::BUILD_VECTOR, Op0VecVT, - DAG.getConstant(0x80808080, MVT::i32), DAG.getConstant(0x00010203, - MVT::i32), DAG.getConstant(0x80808080, MVT::i32), DAG.getConstant( - 0x08090a0b, MVT::i32)); - SDValue zextShuffle = DAG.getNode(SPUISD::SHUFB, Op0VecVT, PromoteScalar, - PromoteScalar, shufMask); - - return DAG.getNode(SPUISD::VEC2PREFSLOT, VT, DAG.getNode(ISD::BIT_CONVERT, - VecVT, zextShuffle)); + SDValue shufMask; + + switch (Op0VT.getSimpleVT()) { + default: + cerr << "CellSPU LowerI64Math: Unhandled zero/any extend MVT\n"; + abort(); + /*NOTREACHED*/ + break; + case MVT::i32: + shufMask = DAG.getNode(ISD::BUILD_VECTOR, MVT::v4i32, + DAG.getConstant(0x80808080, MVT::i32), + DAG.getConstant(0x00010203, MVT::i32), + DAG.getConstant(0x80808080, MVT::i32), + DAG.getConstant(0x08090a0b, MVT::i32)); + break; + + case MVT::i16: + shufMask = DAG.getNode(ISD::BUILD_VECTOR, MVT::v4i32, + DAG.getConstant(0x80808080, MVT::i32), + DAG.getConstant(0x80800203, MVT::i32), + DAG.getConstant(0x80808080, MVT::i32), + DAG.getConstant(0x80800a0b, MVT::i32)); + break; + + case MVT::i8: + shufMask = DAG.getNode(ISD::BUILD_VECTOR, MVT::v4i32, + DAG.getConstant(0x80808080, MVT::i32), + DAG.getConstant(0x80808003, MVT::i32), + DAG.getConstant(0x80808080, MVT::i32), + DAG.getConstant(0x8080800b, MVT::i32)); + break; + } + + SDValue zextShuffle = DAG.getNode(SPUISD::SHUFB, Op0VecVT, + PromoteScalar, PromoteScalar, shufMask); + + return DAG.getNode(SPUISD::VEC2PREFSLOT, VT, + DAG.getNode(ISD::BIT_CONVERT, VecVT, zextShuffle)); } case ISD::ADD: { diff --git a/lib/Target/CellSPU/SPUInstrInfo.cpp b/lib/Target/CellSPU/SPUInstrInfo.cpp index d88b2e9e82f..06ad50762f7 100644 --- a/lib/Target/CellSPU/SPUInstrInfo.cpp +++ b/lib/Target/CellSPU/SPUInstrInfo.cpp @@ -130,7 +130,32 @@ 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: + case SPU::ORi128_r64: + case SPU::ORi128_f64: + case SPU::ORi128_r32: + case SPU::ORi128_f32: + case SPU::ORi128_r16: + case SPU::ORi128_r8: + case SPU::ORi128_vec: + case SPU::ORr64_i128: + case SPU::ORf64_i128: + case SPU::ORr32_i128: + case SPU::ORf32_i128: + case SPU::ORr16_i128: + case SPU::ORr8_i128: + case SPU::ORvec_i128: + case SPU::ORr16_r32: + case SPU::ORr8_r32: + case SPU::ORr32_r16: + case SPU::ORr32_r8: + case SPU::ORr32_r64: + case SPU::ORr16_r64: + case SPU::ORr8_r64: + case SPU::ORr64_r32: + case SPU::ORr64_r16: + case SPU::ORr64_r8: + { assert(MI.getNumOperands() == 2 && MI.getOperand(0).isReg() && MI.getOperand(1).isReg() && diff --git a/lib/Target/CellSPU/SPUInstrInfo.td b/lib/Target/CellSPU/SPUInstrInfo.td index 1ceaf1abda8..6a0fde398b8 100644 --- a/lib/Target/CellSPU/SPUInstrInfo.td +++ b/lib/Target/CellSPU/SPUInstrInfo.td @@ -1140,48 +1140,66 @@ class XSBHVecInst: XSBHInst<(outs VECREG:$rDst), (ins VECREG:$rSrc), [(set (v8i16 VECREG:$rDst), (sext (vectype VECREG:$rSrc)))]>; -class XSBHInRegInst: +class XSBHInRegInst pattern>: XSBHInst<(outs rclass:$rDst), (ins rclass:$rSrc), - [(set rclass:$rDst, (sext_inreg rclass:$rSrc, i8))]>; + pattern>; multiclass ExtendByteHalfword { - def v16i8: XSBHVecInst; - def r16: XSBHInRegInst; - def r8: XSBHInst<(outs R16C:$rDst), (ins R8C:$rSrc), - [(set R16C:$rDst, (sext R8C:$rSrc))]>; + def v16i8: XSBHVecInst; + def r8: XSBHInst<(outs R16C:$rDst), (ins R8C:$rSrc), + [(set R16C:$rDst, (sext R8C:$rSrc))]>; + def r16: XSBHInRegInst; // 32-bit form for XSBH: used to sign extend 8-bit quantities to 16-bit // quantities to 32-bit quantities via a 32-bit register (see the sext 8->32 // pattern below). Intentionally doesn't match a pattern because we want the // sext 8->32 pattern to do the work for us, namely because we need the extra // XSHWr32. - def r32: XSBHInRegInst; + def r32: XSBHInRegInst; + + // Same as the 32-bit version, but for i64 + def r64: XSBHInRegInst; } defm XSBH : ExtendByteHalfword; // Sign extend halfwords to words: -def XSHWvec: - RRForm_1<0b01101101010, (outs VECREG:$rDest), (ins VECREG:$rSrc), - "xshw\t$rDest, $rSrc", IntegerOp, - [(set (v4i32 VECREG:$rDest), (sext (v8i16 VECREG:$rSrc)))]>; -def XSHWr32: - RRForm_1<0b01101101010, (outs R32C:$rDst), (ins R32C:$rSrc), - "xshw\t$rDst, $rSrc", IntegerOp, - [(set R32C:$rDst, (sext_inreg R32C:$rSrc, i16))]>; +class XSHWInst pattern>: + RRForm_1<0b01101101010, OOL, IOL, "xshw\t$rDest, $rSrc", + IntegerOp, pattern>; + +class XSHWVecInst: + XSHWInst<(outs VECREG:$rDest), (ins VECREG:$rSrc), + [(set (out_vectype VECREG:$rDest), + (sext (in_vectype VECREG:$rSrc)))]>; + +class XSHWInRegInst pattern>: + XSHWInst<(outs rclass:$rDest), (ins rclass:$rSrc), + pattern>; + +class XSHWRegInst: + XSHWInst<(outs rclass:$rDest), (ins R16C:$rSrc), + [(set rclass:$rDest, (sext R16C:$rSrc))]>; + +multiclass ExtendHalfwordWord { + def v4i32: XSHWVecInst; + + def r16: XSHWRegInst; + + def r32: XSHWInRegInst; + def r64: XSHWInRegInst; +} -def XSHWr16: - RRForm_1<0b01101101010, (outs R32C:$rDst), (ins R16C:$rSrc), - "xshw\t$rDst, $rSrc", IntegerOp, - [(set R32C:$rDst, (sext R16C:$rSrc))]>; +defm XSHW : ExtendHalfwordWord; // Sign-extend words to doublewords (32->64 bits) class XSWDInst pattern>: - RRForm_1<0b01100101010, OOL, IOL, - "xswd\t$rDst, $rSrc", IntegerOp, - pattern>; + RRForm_1<0b01100101010, OOL, IOL, "xswd\t$rDst, $rSrc", + IntegerOp, pattern>; class XSWDVecInst: XSWDInst<(outs VECREG:$rDst), (ins VECREG:$rSrc), @@ -1411,6 +1429,18 @@ class ORCvtVecGPRC: class ORCvtGPRCReg: ORCvtForm<(outs rclass:$rT), (ins GPRC:$rA)>; + +class ORCvtFormR32Reg: + ORCvtForm<(outs rclass:$rT), (ins R32C:$rA)>; + +class ORCvtFormRegR32: + ORCvtForm<(outs R32C:$rT), (ins rclass:$rA)>; + +class ORCvtFormR64Reg: + ORCvtForm<(outs rclass:$rT), (ins R64C:$rA)>; + +class ORCvtFormRegR64: + ORCvtForm<(outs R64C:$rT), (ins rclass:$rA)>; class ORCvtGPRCVec: ORCvtForm<(outs VECREG:$rT), (ins GPRC:$rA)>; @@ -1481,6 +1511,24 @@ multiclass BitwiseOr // Conversion from vector to GPRC def vec_i128: ORCvtGPRCVec; + + // Conversion from register to R32C: + def r16_r32: ORCvtFormRegR32; + def r8_r32: ORCvtFormRegR32; + + // Conversion from R32C to register + def r32_r16: ORCvtFormR32Reg; + def r32_r8: ORCvtFormR32Reg; + + // Conversion from register to R64C: + def r32_r64: ORCvtFormR64Reg; + def r16_r64: ORCvtFormR64Reg; + def r8_r64: ORCvtFormR64Reg; + + // Conversion from R64C to register + def r64_r32: ORCvtFormRegR64; + def r64_r16: ORCvtFormRegR64; + def r64_r8: ORCvtFormRegR64; } defm OR : BitwiseOr; @@ -2682,7 +2730,7 @@ def : Pat<(srl R32C:$rA, (i8 imm:$val)), (ROTMIr32 R32C:$rA, uimm7:$val)>; //-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~ -// ROTQMBYvec: This is a vector form merely so that when used in an +// ROTQMBY: This is a vector form merely so that when used in an // instruction pattern, type checking will succeed. This instruction assumes // that the user knew to negate $rB. //-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~ @@ -2720,10 +2768,16 @@ class ROTQMBYIVecInst: ROTQMBYIInst<(outs VECREG:$rT), (ins VECREG:$rA, rotNeg7imm:$val), [/* no pattern */]>; -class ROTQMBYIRegInst: +class ROTQMBYIRegInst: ROTQMBYIInst<(outs rclass:$rT), (ins rclass:$rA, optype:$val), [/* no pattern */]>; +// 128-bit zero extension form: +class ROTQMBYIZExtInst: + ROTQMBYIInst<(outs GPRC:$rT), (ins rclass:$rA, optype:$val), + [/* no pattern */]>; + multiclass RotateQuadBytesImm { def v16i8: ROTQMBYIVecInst; @@ -2733,6 +2787,11 @@ multiclass RotateQuadBytesImm def r128: ROTQMBYIRegInst; def r64: ROTQMBYIRegInst; + + def r128_zext_r8: ROTQMBYIZExtInst; + def r128_zext_r16: ROTQMBYIZExtInst; + def r128_zext_r32: ROTQMBYIZExtInst; + def r128_zext_r64: ROTQMBYIZExtInst; } defm ROTQMBYI : RotateQuadBytesImm; @@ -4339,6 +4398,13 @@ def : Pat<(sext_inreg R32C:$rSrc, i8), def : Pat<(i32 (sext R8C:$rSrc)), (XSHWr16 (XSBHr8 R8C:$rSrc))>; +// sext 8->64: Sign extend bytes to double word +def : Pat<(sext_inreg R64C:$rSrc, i8), + (XSWDr64_inreg (XSHWr64 (XSBHr64 R64C:$rSrc)))>; + +def : Pat<(i64 (sext R8C:$rSrc)), + (XSWDr64 (XSHWr16 (XSBHr8 R8C:$rSrc)))>; + // zext 8->16: Zero extend bytes to halfwords def : Pat<(i16 (zext R8C:$rSrc)), (ANDHIi8i16 R8C:$rSrc, 0xff)>; @@ -4347,14 +4413,29 @@ def : Pat<(i16 (zext R8C:$rSrc)), def : Pat<(i32 (zext R8C:$rSrc)), (ANDIi8i32 R8C:$rSrc, 0xff)>; -// anyext 8->16: Extend 8->16 bits, irrespective of sign +// zext 8->64: Zero extend bytes to double words +def : Pat<(i64 (zext R8C:$rSrc)), + (ORi64_v2i64 (SELBv4i32 (ROTQMBYv4i32 + (ORv4i32_i32 (ANDIi8i32 R8C:$rSrc, 0xff)), + 0x4), + (ILv4i32 0x0), + (FSMBIv4i32 0x0f0f)))>; + +// anyext 8->16: Extend 8->16 bits, irrespective of sign, preserves high bits def : Pat<(i16 (anyext R8C:$rSrc)), (ORHIi8i16 R8C:$rSrc, 0)>; -// anyext 8->32: Extend 8->32 bits, irrespective of sign +// anyext 8->32: Extend 8->32 bits, irrespective of sign, preserves high bits def : Pat<(i32 (anyext R8C:$rSrc)), (ORIi8i32 R8C:$rSrc, 0)>; +// sext 16->64: Sign extend halfword to double word +def : Pat<(sext_inreg R64C:$rSrc, i16), + (XSWDr64_inreg (XSHWr64 R64C:$rSrc))>; + +def : Pat<(sext R16C:$rSrc), + (XSWDr64 (XSHWr16 R16C:$rSrc))>; + // zext 16->32: Zero extend halfwords to words def : Pat<(i32 (zext R16C:$rSrc)), (ANDi16i32 R16C:$rSrc, (ILAr32 0xffff))>; @@ -4461,15 +4542,6 @@ def : Pat<(SPUindirect (SPUhi tconstpool:$in, 0), (SPUlo tconstpool:$in, 0)), (IOHLlo (ILHUhi tconstpool:$in), tconstpool:$in)>; -/* -def : Pat<(SPUindirect R32C:$sp, i32ImmSExt10:$imm), - (AIr32 R32C:$sp, i32ImmSExt10:$imm)>; - -def : Pat<(SPUindirect R32C:$sp, imm:$imm), - (Ar32 R32C:$sp, - (IOHLr32 (ILHUr32 (HI16 imm:$imm)), (LO16 imm:$imm)))>; - */ - def : Pat<(add (SPUhi tglobaladdr:$in, 0), (SPUlo tglobaladdr:$in, 0)), (IOHLlo (ILHUhi tglobaladdr:$in), tglobaladdr:$in)>; @@ -4488,3 +4560,5 @@ include "CellSDKIntrinsics.td" include "SPUMathInstr.td" // 64-bit "instructions"/support include "SPU64InstrInfo.td" +// 128-bit "instructions"/support +include "SPU128InstrInfo.td" diff --git a/test/CodeGen/CellSPU/i64ops.ll b/test/CodeGen/CellSPU/i64ops.ll index 51abd44a09e..d118c5f88c5 100644 --- a/test/CodeGen/CellSPU/i64ops.ll +++ b/test/CodeGen/CellSPU/i64ops.ll @@ -1,6 +1,8 @@ ; RUN: llvm-as -o - %s | llc -march=cellspu > %t1.s -; RUN: grep xswd %t1.s | count 1 -; RUN: grep shufb %t1.s | count 2 +; RUN: grep xswd %t1.s | count 3 +; RUN: grep xsbh %t1.s | count 1 +; RUN: grep xshw %t1.s | count 2 +; RUN: grep shufb %t1.s | count 4 ; RUN: grep cg %t1.s | count 1 ; RUN: grep addx %t1.s | count 1 @@ -8,11 +10,31 @@ 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" +define i64 @sext_i64_i8(i8 %a) nounwind { + %1 = sext i8 %a to i64 + ret i64 %1 +} + +define i64 @sext_i64_i16(i16 %a) nounwind { + %1 = sext i16 %a to i64 + ret i64 %1 +} + define i64 @sext_i64_i32(i32 %a) nounwind { %1 = sext i32 %a to i64 ret i64 %1 } +define i64 @zext_i64_i8(i8 %a) nounwind { + %1 = zext i8 %a to i64 + ret i64 %1 +} + +define i64 @zext_i64_i16(i16 %a) nounwind { + %1 = zext i16 %a to i64 + ret i64 %1 +} + define i64 @zext_i64_i32(i32 %a) nounwind { %1 = zext i32 %a to i64 ret i64 %1 diff --git a/test/CodeGen/CellSPU/useful-harnesses/i64operations.c b/test/CodeGen/CellSPU/useful-harnesses/i64operations.c index b93ce376103..7a4bf1ab0d2 100644 --- a/test/CodeGen/CellSPU/useful-harnesses/i64operations.c +++ b/test/CodeGen/CellSPU/useful-harnesses/i64operations.c @@ -1,20 +1,12 @@ #include - -#define TRUE_VAL (!0) -#define FALSE_VAL 0 -#define ARR_SIZE(arr) (sizeof(arr)/sizeof(arr[0])) - -typedef unsigned long long int uint64_t; -typedef long long int int64_t; - -/* ~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~- */ +#include "i64operations.h" int64_t tval_a = 1234567890003LL; int64_t tval_b = 2345678901235LL; int64_t tval_c = 1234567890001LL; int64_t tval_d = 10001LL; int64_t tval_e = 10000LL; -int64_t tval_f = -1068103409991LL; +uint64_t tval_f = 0xffffff0750135eb9; /* ~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~- */ @@ -132,44 +124,6 @@ i64_ult_select(uint64_t a, uint64_t b, uint64_t c, uint64_t d) { /* ~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~- */ -struct harness_int64_pred { - const char *fmt_string; - int64_t *lhs; - int64_t *rhs; - int64_t *select_a; - int64_t *select_b; - int expected; - int64_t *select_expected; -}; - -struct harness_uint64_pred { - const char *fmt_string; - uint64_t *lhs; - uint64_t *rhs; - uint64_t *select_a; - uint64_t *select_b; - int expected; - uint64_t *select_expected; -}; - -struct int64_pred_s { - const char *name; - int (*predfunc) (int64_t, int64_t); - int64_t (*selfunc) (int64_t, int64_t, int64_t, int64_t); - struct harness_int64_pred *tests; - int n_tests; -}; - -struct uint64_pred_s { - const char *name; - int (*predfunc) (uint64_t, uint64_t); - uint64_t (*selfunc) (uint64_t, uint64_t, uint64_t, uint64_t); - struct harness_uint64_pred *tests; - int n_tests; -}; - -/* ~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~- */ - struct harness_int64_pred int64_tests_eq[] = { {"a %s a", &tval_a, &tval_a, &tval_c, &tval_d, TRUE_VAL, &tval_c}, {"a %s b", &tval_a, &tval_b, &tval_c, &tval_d, FALSE_VAL, &tval_d}, @@ -304,8 +258,9 @@ compare_expect_int64(const struct int64_pred_s * pred) int j, failed = 0; for (j = 0; j < pred->n_tests; ++j) { - int pred_result = - (*pred->predfunc) (*pred->tests[j].lhs, *pred->tests[j].rhs); + int pred_result; + + pred_result = (*pred->predfunc) (*pred->tests[j].lhs, *pred->tests[j].rhs); if (pred_result != pred->tests[j].expected) { char str[64]; @@ -313,27 +268,39 @@ compare_expect_int64(const struct int64_pred_s * pred) sprintf(str, pred->tests[j].fmt_string, pred->name); printf("%s: returned value is %d, expecting %d\n", str, pred_result, pred->tests[j].expected); - printf(" lhs = %19lld (0x%016llx)\n", *pred->tests[j].lhs, *pred->tests[j].lhs); - printf(" rhs = %19lld (0x%016llx)\n", *pred->tests[j].rhs, *pred->tests[j].rhs); + printf(" lhs = %19lld (0x%016llx)\n", *pred->tests[j].lhs, + *pred->tests[j].lhs); + printf(" rhs = %19lld (0x%016llx)\n", *pred->tests[j].rhs, + *pred->tests[j].rhs); ++failed; } else { - int64_t selresult = (pred->selfunc) (*pred->tests[j].lhs, *pred->tests[j].rhs, - *pred->tests[j].select_a, *pred->tests[j].select_b); + int64_t selresult; + + selresult = (pred->selfunc) (*pred->tests[j].lhs, *pred->tests[j].rhs, + *pred->tests[j].select_a, + *pred->tests[j].select_b); + if (selresult != *pred->tests[j].select_expected) { char str[64]; sprintf(str, pred->tests[j].fmt_string, pred->name); printf("%s select: returned value is %d, expecting %d\n", str, pred_result, pred->tests[j].expected); - printf(" lhs = %19lld (0x%016llx)\n", *pred->tests[j].lhs, *pred->tests[j].lhs); - printf(" rhs = %19lld (0x%016llx)\n", *pred->tests[j].rhs, *pred->tests[j].rhs); - printf(" true = %19lld (0x%016llx)\n", *pred->tests[j].select_a, *pred->tests[j].select_a); - printf(" false = %19lld (0x%016llx)\n", *pred->tests[j].select_b, *pred->tests[j].select_b); + printf(" lhs = %19lld (0x%016llx)\n", *pred->tests[j].lhs, + *pred->tests[j].lhs); + printf(" rhs = %19lld (0x%016llx)\n", *pred->tests[j].rhs, + *pred->tests[j].rhs); + printf(" true = %19lld (0x%016llx)\n", *pred->tests[j].select_a, + *pred->tests[j].select_a); + printf(" false = %19lld (0x%016llx)\n", *pred->tests[j].select_b, + *pred->tests[j].select_b); ++failed; } } } + printf(" %d tests performed, should be %d.\n", j, pred->n_tests); + return failed; } @@ -343,77 +310,240 @@ compare_expect_uint64(const struct uint64_pred_s * pred) int j, failed = 0; for (j = 0; j < pred->n_tests; ++j) { - int pred_result = (*pred->predfunc) (*pred->tests[j].lhs, *pred->tests[j].rhs); + int pred_result; + pred_result = (*pred->predfunc) (*pred->tests[j].lhs, *pred->tests[j].rhs); if (pred_result != pred->tests[j].expected) { char str[64]; sprintf(str, pred->tests[j].fmt_string, pred->name); printf("%s: returned value is %d, expecting %d\n", str, pred_result, pred->tests[j].expected); - printf(" lhs = %19llu (0x%016llx)\n", *pred->tests[j].lhs, *pred->tests[j].lhs); - printf(" rhs = %19llu (0x%016llx)\n", *pred->tests[j].rhs, *pred->tests[j].rhs); + printf(" lhs = %19llu (0x%016llx)\n", *pred->tests[j].lhs, + *pred->tests[j].lhs); + printf(" rhs = %19llu (0x%016llx)\n", *pred->tests[j].rhs, + *pred->tests[j].rhs); ++failed; } else { - uint64_t selresult = (pred->selfunc) (*pred->tests[j].lhs, *pred->tests[j].rhs, - *pred->tests[j].select_a, *pred->tests[j].select_b); + uint64_t selresult; + + selresult = (pred->selfunc) (*pred->tests[j].lhs, *pred->tests[j].rhs, + *pred->tests[j].select_a, + *pred->tests[j].select_b); if (selresult != *pred->tests[j].select_expected) { char str[64]; sprintf(str, pred->tests[j].fmt_string, pred->name); printf("%s select: returned value is %d, expecting %d\n", str, pred_result, pred->tests[j].expected); - printf(" lhs = %19llu (0x%016llx)\n", *pred->tests[j].lhs, *pred->tests[j].lhs); - printf(" rhs = %19llu (0x%016llx)\n", *pred->tests[j].rhs, *pred->tests[j].rhs); - printf(" true = %19llu (0x%016llx)\n", *pred->tests[j].select_a, *pred->tests[j].select_a); - printf(" false = %19llu (0x%016llx)\n", *pred->tests[j].select_b, *pred->tests[j].select_b); + printf(" lhs = %19llu (0x%016llx)\n", *pred->tests[j].lhs, + *pred->tests[j].lhs); + printf(" rhs = %19llu (0x%016llx)\n", *pred->tests[j].rhs, + *pred->tests[j].rhs); + printf(" true = %19llu (0x%016llx)\n", *pred->tests[j].select_a, + *pred->tests[j].select_a); + printf(" false = %19llu (0x%016llx)\n", *pred->tests[j].select_b, + *pred->tests[j].select_b); ++failed; } } - } + printf(" %d tests performed, should be %d.\n", j, pred->n_tests); + return failed; } /* ~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~- */ +int +test_i64_sext_i32(int in, int64_t expected) { + int64_t result = (int64_t) in; + + if (result != expected) { + char str[64]; + sprintf(str, "i64_sext_i32(%d) returns %lld\n", in, result); + return 1; + } + + return 0; +} + +int +test_i64_sext_i16(short in, int64_t expected) { + int64_t result = (int64_t) in; + + if (result != expected) { + char str[64]; + sprintf(str, "i64_sext_i16(%hd) returns %lld\n", in, result); + return 1; + } + + return 0; +} + +int +test_i64_sext_i8(signed char in, int64_t expected) { + int64_t result = (int64_t) in; + + if (result != expected) { + char str[64]; + sprintf(str, "i64_sext_i8(%d) returns %lld\n", in, result); + return 1; + } + + return 0; +} + +int +test_i64_zext_i32(unsigned int in, uint64_t expected) { + uint64_t result = (uint64_t) in; + + if (result != expected) { + char str[64]; + sprintf(str, "i64_zext_i32(%u) returns %llu\n", in, result); + return 1; + } + + return 0; +} + +int +test_i64_zext_i16(unsigned short in, uint64_t expected) { + uint64_t result = (uint64_t) in; + + if (result != expected) { + char str[64]; + sprintf(str, "i64_zext_i16(%hu) returns %llu\n", in, result); + return 1; + } + + return 0; +} + +int +test_i64_zext_i8(unsigned char in, uint64_t expected) { + uint64_t result = (uint64_t) in; + + if (result != expected) { + char str[64]; + sprintf(str, "i64_zext_i8(%u) returns %llu\n", in, result); + return 1; + } + + return 0; +} + +/* ~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~- */ + +int64_t +i64_shl_const(int64_t a) { + return a << 10; +} + +int64_t +i64_shl(int64_t a, int amt) { + return a << amt; +} + uint64_t -i64_shl_const(uint64_t a) -{ +u64_shl_const(uint64_t a) { return a << 10; } uint64_t -i64_shl(uint64_t a, int amt) -{ +u64_shl(uint64_t a, int amt) { return a << amt; } +int64_t +i64_srl_const(int64_t a) { + return a >> 10; +} + +int64_t +i64_srl(int64_t a, int amt) { + return a >> amt; +} + uint64_t -i64_srl_const(uint64_t a) -{ +u64_srl_const(uint64_t a) { return a >> 10; } uint64_t -i64_srl(uint64_t a, int amt) -{ +u64_srl(uint64_t a, int amt) { return a >> amt; } int64_t -i64_sra_const(int64_t a) -{ +i64_sra_const(int64_t a) { return a >> 10; } int64_t -i64_sra(int64_t a, int amt) -{ +i64_sra(int64_t a, int amt) { + return a >> amt; +} + +uint64_t +u64_sra_const(uint64_t a) { + return a >> 10; +} + +uint64_t +u64_sra(uint64_t a, int amt) { return a >> amt; } +int +test_u64_constant_shift(const char *func_name, uint64_t (*func)(uint64_t), uint64_t a, uint64_t expected) { + uint64_t result = (*func)(a); + + if (result != expected) { + printf("%s(0x%016llx) returns 0x%016llx, expected 0x%016llx\n", func_name, a, result, expected); + return 1; + } + + return 0; +} + +int +test_i64_constant_shift(const char *func_name, int64_t (*func)(int64_t), int64_t a, int64_t expected) { + int64_t result = (*func)(a); + + if (result != expected) { + printf("%s(0x%016llx) returns 0x%016llx, expected 0x%016llx\n", func_name, a, result, expected); + return 1; + } + + return 0; +} + +int +test_u64_variable_shift(const char *func_name, uint64_t (*func)(uint64_t, int), uint64_t a, unsigned int b, uint64_t expected) { + uint64_t result = (*func)(a, b); + + if (result != expected) { + printf("%s(0x%016llx, %d) returns 0x%016llx, expected 0x%016llx\n", func_name, a, b, result, expected); + return 1; + } + + return 0; +} + +int +test_i64_variable_shift(const char *func_name, int64_t (*func)(int64_t, int), int64_t a, unsigned int b, int64_t expected) { + int64_t result = (*func)(a, b); + + if (result != expected) { + printf("%s(0x%016llx, %d) returns 0x%016llx, expected 0x%016llx\n", func_name, a, b, result, expected); + return 1; + } + + return 0; +} + /* ~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~- */ int @@ -423,12 +553,12 @@ main(void) const char *something_failed = " %d tests failed.\n"; const char *all_tests_passed = " All tests passed.\n"; - printf("a = %16lld (0x%016llx)\n", tval_a, tval_a); - printf("b = %16lld (0x%016llx)\n", tval_b, tval_b); - printf("c = %16lld (0x%016llx)\n", tval_c, tval_c); - printf("d = %16lld (0x%016llx)\n", tval_d, tval_d); - printf("e = %16lld (0x%016llx)\n", tval_e, tval_e); - printf("f = %16lld (0x%016llx)\n", tval_f, tval_f); + printf("tval_a = %20lld (0x%020llx)\n", tval_a, tval_a); + printf("tval_b = %20lld (0x%020llx)\n", tval_b, tval_b); + printf("tval_c = %20lld (0x%020llx)\n", tval_c, tval_c); + printf("tval_d = %20lld (0x%020llx)\n", tval_d, tval_d); + printf("tval_e = %20lld (0x%020llx)\n", tval_e, tval_e); + printf("tval_f = %20llu (0x%020llx)\n", tval_f, tval_f); printf("----------------------------------------\n"); for (i = 0; i < ARR_SIZE(int64_preds); ++i) { @@ -453,22 +583,70 @@ main(void) printf("----------------------------------------\n"); } - printf("a = 0x%016llx\n", tval_a); - printf("i64_shl_const(a) = 0x%016llx\n", i64_shl_const(tval_a)); - printf("i64_shl(a) = 0x%016llx\n", i64_shl(tval_a, 10)); - printf("i64_srl_const(a) = 0x%016llx\n", i64_srl_const(tval_a)); - printf("i64_srl(a) = 0x%016llx\n", i64_srl(tval_a, 10)); - printf("i64_sra_const(a) = 0x%016llx\n", i64_sra_const(tval_a)); - printf("i64_sra(a) = 0x%016llx\n", i64_sra(tval_a, 10)); + /*----------------------------------------------------------------------*/ + + puts("signed/zero-extend tests:"); + + failed = 0; + failed += test_i64_sext_i32(-1, -1LL); + failed += test_i64_sext_i32(10, 10LL); + failed += test_i64_sext_i32(0x7fffffff, 0x7fffffffLL); + failed += test_i64_sext_i16(-1, -1LL); + failed += test_i64_sext_i16(10, 10LL); + failed += test_i64_sext_i16(0x7fff, 0x7fffLL); + failed += test_i64_sext_i8(-1, -1LL); + failed += test_i64_sext_i8(10, 10LL); + failed += test_i64_sext_i8(0x7f, 0x7fLL); + + failed += test_i64_zext_i32(0xffffffff, 0x00000000ffffffffLLU); + failed += test_i64_zext_i32(0x01234567, 0x0000000001234567LLU); + failed += test_i64_zext_i16(0xffff, 0x000000000000ffffLLU); + failed += test_i64_zext_i16(0x569a, 0x000000000000569aLLU); + failed += test_i64_zext_i8(0xff, 0x00000000000000ffLLU); + failed += test_i64_zext_i8(0xa0, 0x00000000000000a0LLU); + + if (failed > 0) { + printf(" %d tests failed.\n", failed); + } else { + printf(" All tests passed.\n"); + } + + printf("----------------------------------------\n"); + + failed = 0; + puts("signed left/right shift tests:"); + failed += test_i64_constant_shift("i64_shl_const", i64_shl_const, tval_a, 0x00047dc7ec114c00LL); + failed += test_i64_variable_shift("i64_shl", i64_shl, tval_a, 10, 0x00047dc7ec114c00LL); + failed += test_i64_constant_shift("i64_srl_const", i64_srl_const, tval_a, 0x0000000047dc7ec1LL); + failed += test_i64_variable_shift("i64_srl", i64_srl, tval_a, 10, 0x0000000047dc7ec1LL); + failed += test_i64_constant_shift("i64_sra_const", i64_sra_const, tval_a, 0x0000000047dc7ec1LL); + failed += test_i64_variable_shift("i64_sra", i64_sra, tval_a, 10, 0x0000000047dc7ec1LL); + + if (failed > 0) { + printf(" %d tests ailed.\n", failed); + } else { + printf(" All tests passed.\n"); + } + printf("----------------------------------------\n"); - printf("f = 0x%016llx\n", tval_f); - printf("i64_shl_const(f) = 0x%016llx\n", i64_shl_const(tval_f)); - printf("i64_shl(f) = 0x%016llx\n", i64_shl(tval_f, 10)); - printf("i64_srl_const(f) = 0x%016llx\n", i64_srl_const(tval_f)); - printf("i64_srl(f) = 0x%016llx\n", i64_srl(tval_f, 10)); - printf("i64_sra_const(f) = 0x%016llx\n", i64_sra_const(tval_f)); - printf("i64_sra(f) = 0x%016llx\n", i64_sra(tval_f, 10)); + failed = 0; + puts("unsigned left/right shift tests:"); + failed += test_u64_constant_shift("u64_shl_const", u64_shl_const, tval_f, 0xfffc1d404d7ae400LL); + failed += test_u64_variable_shift("u64_shl", u64_shl, tval_f, 10, 0xfffc1d404d7ae400LL); + failed += test_u64_constant_shift("u64_srl_const", u64_srl_const, tval_f, 0x003fffffc1d404d7LL); + failed += test_u64_variable_shift("u64_srl", u64_srl, tval_f, 10, 0x003fffffc1d404d7LL); + failed += test_i64_constant_shift("i64_sra_const", i64_sra_const, tval_f, 0xffffffffc1d404d7LL); + failed += test_i64_variable_shift("i64_sra", i64_sra, tval_f, 10, 0xffffffffc1d404d7LL); + failed += test_u64_constant_shift("u64_sra_const", u64_sra_const, tval_f, 0x003fffffc1d404d7LL); + failed += test_u64_variable_shift("u64_sra", u64_sra, tval_f, 10, 0x003fffffc1d404d7LL); + + if (failed > 0) { + printf(" %d tests ailed.\n", failed); + } else { + printf(" All tests passed.\n"); + } + printf("----------------------------------------\n"); return 0; diff --git a/test/CodeGen/CellSPU/useful-harnesses/i64operations.h b/test/CodeGen/CellSPU/useful-harnesses/i64operations.h new file mode 100644 index 00000000000..7a02794cd7e --- /dev/null +++ b/test/CodeGen/CellSPU/useful-harnesses/i64operations.h @@ -0,0 +1,43 @@ +#define TRUE_VAL (!0) +#define FALSE_VAL 0 +#define ARR_SIZE(arr) (sizeof(arr)/sizeof(arr[0])) + +typedef unsigned long long int uint64_t; +typedef long long int int64_t; + +/* ~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~- */ +struct harness_int64_pred { + const char *fmt_string; + int64_t *lhs; + int64_t *rhs; + int64_t *select_a; + int64_t *select_b; + int expected; + int64_t *select_expected; +}; + +struct harness_uint64_pred { + const char *fmt_string; + uint64_t *lhs; + uint64_t *rhs; + uint64_t *select_a; + uint64_t *select_b; + int expected; + uint64_t *select_expected; +}; + +struct int64_pred_s { + const char *name; + int (*predfunc) (int64_t, int64_t); + int64_t (*selfunc) (int64_t, int64_t, int64_t, int64_t); + struct harness_int64_pred *tests; + int n_tests; +}; + +struct uint64_pred_s { + const char *name; + int (*predfunc) (uint64_t, uint64_t); + uint64_t (*selfunc) (uint64_t, uint64_t, uint64_t, uint64_t); + struct harness_uint64_pred *tests; + int n_tests; +}; -- 2.34.1