- 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
This commit is contained in:
Scott Michel 2009-01-06 03:36:14 +00:00
parent 5ddefdaa34
commit dd950096b9
9 changed files with 559 additions and 160 deletions

View File

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

View File

@ -48,8 +48,8 @@ class I64SETCCNegCond<PatFrag cond, CodeFrag compare>:
// 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

View File

@ -21,10 +21,11 @@ class CCIfSubtarget<string F, CCAction A>
// 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]>>
]>;

View File

@ -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);
SDValue shufMask;
return DAG.getNode(SPUISD::VEC2PREFSLOT, VT, DAG.getNode(ISD::BIT_CONVERT,
VecVT, zextShuffle));
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: {

View File

@ -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() &&

View File

@ -1140,48 +1140,66 @@ class XSBHVecInst<ValueType vectype>:
XSBHInst<(outs VECREG:$rDst), (ins VECREG:$rSrc),
[(set (v8i16 VECREG:$rDst), (sext (vectype VECREG:$rSrc)))]>;
class XSBHInRegInst<RegisterClass rclass>:
class XSBHInRegInst<RegisterClass rclass, list<dag> pattern>:
XSBHInst<(outs rclass:$rDst), (ins rclass:$rSrc),
[(set rclass:$rDst, (sext_inreg rclass:$rSrc, i8))]>;
pattern>;
multiclass ExtendByteHalfword {
def v16i8: XSBHVecInst<v8i16>;
def r16: XSBHInRegInst<R16C>;
def r8: XSBHInst<(outs R16C:$rDst), (ins R8C:$rSrc),
[(set R16C:$rDst, (sext R8C:$rSrc))]>;
def v16i8: XSBHVecInst<v8i16>;
def r8: XSBHInst<(outs R16C:$rDst), (ins R8C:$rSrc),
[(set R16C:$rDst, (sext R8C:$rSrc))]>;
def r16: XSBHInRegInst<R16C,
[(set R16C:$rDst, (sext_inreg R16C:$rSrc, i8))]>;
// 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<R32C>;
def r32: XSBHInRegInst<R32C, [/* no pattern */]>;
// Same as the 32-bit version, but for i64
def r64: XSBHInRegInst<R64C, [/* no pattern */]>;
}
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<dag OOL, dag IOL, list<dag> pattern>:
RRForm_1<0b01101101010, OOL, IOL, "xshw\t$rDest, $rSrc",
IntegerOp, pattern>;
def XSHWr16:
RRForm_1<0b01101101010, (outs R32C:$rDst), (ins R16C:$rSrc),
"xshw\t$rDst, $rSrc", IntegerOp,
[(set R32C:$rDst, (sext R16C:$rSrc))]>;
class XSHWVecInst<ValueType in_vectype, ValueType out_vectype>:
XSHWInst<(outs VECREG:$rDest), (ins VECREG:$rSrc),
[(set (out_vectype VECREG:$rDest),
(sext (in_vectype VECREG:$rSrc)))]>;
class XSHWInRegInst<RegisterClass rclass, list<dag> pattern>:
XSHWInst<(outs rclass:$rDest), (ins rclass:$rSrc),
pattern>;
class XSHWRegInst<RegisterClass rclass>:
XSHWInst<(outs rclass:$rDest), (ins R16C:$rSrc),
[(set rclass:$rDest, (sext R16C:$rSrc))]>;
multiclass ExtendHalfwordWord {
def v4i32: XSHWVecInst<v4i32, v8i16>;
def r16: XSHWRegInst<R32C>;
def r32: XSHWInRegInst<R32C,
[(set R32C:$rDest, (sext_inreg R32C:$rSrc, i16))]>;
def r64: XSHWInRegInst<R64C, [/* no pattern */]>;
}
defm XSHW : ExtendHalfwordWord;
// Sign-extend words to doublewords (32->64 bits)
class XSWDInst<dag OOL, dag IOL, list<dag> 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<ValueType in_vectype, ValueType out_vectype>:
XSWDInst<(outs VECREG:$rDst), (ins VECREG:$rSrc),
@ -1411,6 +1429,18 @@ class ORCvtVecGPRC:
class ORCvtGPRCReg<RegisterClass rclass>:
ORCvtForm<(outs rclass:$rT), (ins GPRC:$rA)>;
class ORCvtFormR32Reg<RegisterClass rclass>:
ORCvtForm<(outs rclass:$rT), (ins R32C:$rA)>;
class ORCvtFormRegR32<RegisterClass rclass>:
ORCvtForm<(outs R32C:$rT), (ins rclass:$rA)>;
class ORCvtFormR64Reg<RegisterClass rclass>:
ORCvtForm<(outs rclass:$rT), (ins R64C:$rA)>;
class ORCvtFormRegR64<RegisterClass rclass>:
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<R16C>;
def r8_r32: ORCvtFormRegR32<R8C>;
// Conversion from R32C to register
def r32_r16: ORCvtFormR32Reg<R16C>;
def r32_r8: ORCvtFormR32Reg<R8C>;
// Conversion from register to R64C:
def r32_r64: ORCvtFormR64Reg<R32C>;
def r16_r64: ORCvtFormR64Reg<R16C>;
def r8_r64: ORCvtFormR64Reg<R8C>;
// Conversion from R64C to register
def r64_r32: ORCvtFormRegR64<R32C>;
def r64_r16: ORCvtFormRegR64<R16C>;
def r64_r8: ORCvtFormRegR64<R8C>;
}
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<ValueType vectype>:
ROTQMBYIInst<(outs VECREG:$rT), (ins VECREG:$rA, rotNeg7imm:$val),
[/* no pattern */]>;
class ROTQMBYIRegInst<RegisterClass rclass, Operand optype, ValueType inttype, PatLeaf pred>:
class ROTQMBYIRegInst<RegisterClass rclass, Operand optype, ValueType inttype,
PatLeaf pred>:
ROTQMBYIInst<(outs rclass:$rT), (ins rclass:$rA, optype:$val),
[/* no pattern */]>;
// 128-bit zero extension form:
class ROTQMBYIZExtInst<RegisterClass rclass, Operand optype, PatLeaf pred>:
ROTQMBYIInst<(outs GPRC:$rT), (ins rclass:$rA, optype:$val),
[/* no pattern */]>;
multiclass RotateQuadBytesImm
{
def v16i8: ROTQMBYIVecInst<v16i8>;
@ -2733,6 +2787,11 @@ multiclass RotateQuadBytesImm
def r128: ROTQMBYIRegInst<GPRC, rotNeg7imm, i32, uimm7>;
def r64: ROTQMBYIRegInst<R64C, rotNeg7imm, i32, uimm7>;
def r128_zext_r8: ROTQMBYIZExtInst<R8C, rotNeg7imm, uimm7>;
def r128_zext_r16: ROTQMBYIZExtInst<R16C, rotNeg7imm, uimm7>;
def r128_zext_r32: ROTQMBYIZExtInst<R32C, rotNeg7imm, uimm7>;
def r128_zext_r64: ROTQMBYIZExtInst<R64C, rotNeg7imm, uimm7>;
}
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"

View File

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

View File

@ -1,20 +1,12 @@
#include <stdio.h>
#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;
}
/* ~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~- */
uint64_t
i64_shl_const(uint64_t a)
{
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;
}
uint64_t
i64_shl(uint64_t a, int amt)
{
int64_t
i64_shl(int64_t a, int amt) {
return a << amt;
}
uint64_t
i64_srl_const(uint64_t a)
{
u64_shl_const(uint64_t a) {
return a << 10;
}
uint64_t
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
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");
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("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");
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;

View File

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