case HWIntrinsicInfo::SimdBinaryRMWOp:
genHWIntrinsicSimdBinaryRMWOp(node);
break;
+ case HWIntrinsicInfo::SimdTernaryRMWOp:
+ genHWIntrinsicSimdTernaryRMWOp(node);
+ break;
+ case HWIntrinsicInfo::Sha1HashOp:
+ genHWIntrinsicShaHashOp(node);
+ break;
+ case HWIntrinsicInfo::Sha1RotateOp:
+ genHWIntrinsicShaRotateOp(node);
+ break;
+
default:
NYI("HWIntrinsic form not implemented");
}
genProduceReg(node);
}
+//------------------------------------------------------------------------
+// genHWIntrinsicSimdTernaryRMWOp:
+//
+// Produce code for a GT_HWIntrinsic node with form SimdTernaryRMWOp
+//
+// Consumes three SIMD operands and produces a SIMD result.
+// First operand is both source and destination.
+//
+// Arguments:
+// node - the GT_HWIntrinsic node
+//
+// Return Value:
+// None.
+//
+void CodeGen::genHWIntrinsicSimdTernaryRMWOp(GenTreeHWIntrinsic* node)
+{
+ GenTreeArgList* argList = node->gtGetOp1()->AsArgList();
+ GenTree* op1 = argList->Current();
+ GenTree* op2 = argList->Rest()->Current();
+ GenTree* op3 = argList->Rest()->Rest()->Current();
+ var_types baseType = node->gtSIMDBaseType;
+ regNumber targetReg = node->gtRegNum;
+
+ assert(targetReg != REG_NA);
+ var_types targetType = node->TypeGet();
+
+ genConsumeRegs(op1);
+ genConsumeRegs(op2);
+ genConsumeRegs(op3);
+
+ regNumber op1Reg = op1->gtRegNum;
+ regNumber op2Reg = op2->gtRegNum;
+ regNumber op3Reg = op3->gtRegNum;
+
+ assert(genIsValidFloatReg(op1Reg));
+ assert(genIsValidFloatReg(op2Reg));
+ assert(genIsValidFloatReg(op3Reg));
+ assert(genIsValidFloatReg(targetReg));
+ assert(targetReg != op2Reg);
+ assert(targetReg != op3Reg);
+
+ instruction ins = getOpForHWIntrinsic(node, baseType);
+ assert(ins != INS_invalid);
+
+ bool is16Byte = (node->gtSIMDSize > 8);
+ emitAttr attr = is16Byte ? EA_16BYTE : EA_8BYTE;
+
+ if (targetReg != op1Reg)
+ {
+ getEmitter()->emitIns_R_R(INS_mov, attr, targetReg, op1Reg);
+ }
+
+ getEmitter()->emitIns_R_R_R(ins, attr, targetReg, op2Reg, op3Reg);
+
+ genProduceReg(node);
+}
+
+//------------------------------------------------------------------------
+// genHWIntrinsicShaHashOp:
+//
+// Produce code for a GT_HWIntrinsic node with form Sha1HashOp.
+// Used in Arm64 SHA1 Hash operations.
+//
+// Consumes three operands and returns a Simd result.
+// First Simd operand is both source and destination.
+// Second Operand is an unsigned int.
+// Third operand is a simd operand.
+
+// Arguments:
+// node - the GT_HWIntrinsic node
+//
+// Return Value:
+// None.
+//
+void CodeGen::genHWIntrinsicShaHashOp(GenTreeHWIntrinsic* node)
+{
+ GenTreeArgList* argList = node->gtGetOp1()->AsArgList();
+ GenTree* op1 = argList->Current();
+ GenTree* op2 = argList->Rest()->Current();
+ GenTree* op3 = argList->Rest()->Rest()->Current();
+ var_types baseType = node->gtSIMDBaseType;
+ regNumber targetReg = node->gtRegNum;
+
+ assert(targetReg != REG_NA);
+ var_types targetType = node->TypeGet();
+
+ genConsumeRegs(op1);
+ genConsumeRegs(op2);
+ genConsumeRegs(op3);
+
+ regNumber op1Reg = op1->gtRegNum;
+ regNumber op2Reg = op2->gtRegNum;
+ regNumber op3Reg = op3->gtRegNum;
+
+ assert(genIsValidFloatReg(op1Reg));
+ assert(genIsValidFloatReg(op3Reg));
+ assert(targetReg != op2Reg);
+ assert(targetReg != op3Reg);
+
+ instruction ins = getOpForHWIntrinsic(node, baseType);
+ assert(ins != INS_invalid);
+
+ bool is16Byte = (node->gtSIMDSize > 8);
+ emitAttr attr = is16Byte ? EA_16BYTE : EA_8BYTE;
+
+ assert(genIsValidIntReg(op2Reg));
+ regNumber elementReg = op2->gtRegNum;
+ regNumber tmpReg = node->GetSingleTempReg(RBM_ALLFLOAT);
+
+ getEmitter()->emitIns_R_R(INS_fmov, EA_4BYTE, tmpReg, elementReg);
+
+ if (targetReg != op1Reg)
+ {
+ getEmitter()->emitIns_R_R(INS_mov, attr, targetReg, op1Reg);
+ }
+
+ getEmitter()->emitIns_R_R_R(ins, attr, targetReg, tmpReg, op3Reg);
+
+ genProduceReg(node);
+}
+
+//------------------------------------------------------------------------
+// genHWIntrinsicShaRotateOp:
+//
+// Produce code for a GT_HWIntrinsic node with form Sha1RotateOp.
+// Used in Arm64 SHA1 Rotate operations.
+//
+// Consumes one integer operand and returns unsigned int result.
+//
+// Arguments:
+// node - the GT_HWIntrinsic node
+//
+// Return Value:
+// None.
+//
+void CodeGen::genHWIntrinsicShaRotateOp(GenTreeHWIntrinsic* node)
+{
+ GenTree* op1 = node->gtGetOp1();
+ regNumber targetReg = node->gtRegNum;
+ emitAttr attr = emitActualTypeSize(node);
+
+ assert(targetReg != REG_NA);
+ var_types targetType = node->TypeGet();
+
+ genConsumeOperands(node);
+
+ regNumber op1Reg = op1->gtRegNum;
+
+ instruction ins = getOpForHWIntrinsic(node, node->TypeGet());
+ assert(ins != INS_invalid);
+
+ regNumber elementReg = op1->gtRegNum;
+ regNumber tmpReg = node->GetSingleTempReg(RBM_ALLFLOAT);
+ getEmitter()->emitIns_R_R(INS_fmov, EA_4BYTE, tmpReg, elementReg);
+ getEmitter()->emitIns_R_R(ins, EA_4BYTE, tmpReg, tmpReg);
+ getEmitter()->emitIns_R_R(INS_fmov, attr, targetReg, tmpReg);
+
+ genProduceReg(node);
+}
+
#endif // FEATURE_HW_INTRINSICS
/*****************************************************************************
void genHWIntrinsicSimdSetAllOp(GenTreeHWIntrinsic* node);
void genHWIntrinsicSimdUnaryOp(GenTreeHWIntrinsic* node);
void genHWIntrinsicSimdBinaryRMWOp(GenTreeHWIntrinsic* node);
+void genHWIntrinsicSimdTernaryRMWOp(GenTreeHWIntrinsic* node);
+void genHWIntrinsicShaHashOp(GenTreeHWIntrinsic* node);
+void genHWIntrinsicShaRotateOp(GenTreeHWIntrinsic* node);
template <typename HWIntrinsicSwitchCaseBody>
void genHWIntrinsicSwitchTable(regNumber swReg, regNumber tmpReg, int swMax, HWIntrinsicSwitchCaseBody emitSwCase);
#endif // defined(_TARGET_XARCH_)
assert(isValidImmCondFlags(emitGetInsSC(id)));
break;
+ case IF_DR_2J: // DR_2J ................ ......nnnnnddddd Sd Sn (sha1h)
+ assert(isValidGeneralDatasize(id->idOpSize()));
+ assert(isVectorRegister(id->idReg1()));
+ assert(isVectorRegister(id->idReg2()));
+ break;
+
case IF_DR_3A: // DR_3A X..........mmmmm ......nnnnnmmmmm Rd Rn Rm
assert(isValidGeneralDatasize(id->idOpSize()));
assert(isIntegerRegister(id->idReg1())); // SP
case IF_DV_2A: // DV_2A .Q.......X...... ......nnnnnddddd Vd Vn (fabs, fcvt - vector)
case IF_DV_2M: // DV_2M .Q......XX...... ......nnnnnddddd Vd Vn (abs, neg - vector)
- case IF_DV_2P: // DV_2P ................ ......nnnnnddddd Vd Vn (aes*)
+ case IF_DV_2P: // DV_2P ................ ......nnnnnddddd Vd Vn (aes*, sha1su1)
assert(isValidVectorDatasize(id->idOpSize()));
assert(isValidArrangement(id->idOpSize(), id->idInsOpt()));
assert(isVectorRegister(id->idReg1()));
assert(isVectorRegister(id->idReg3()));
break;
+ case IF_DV_3F: // DV_3F ...........mmmmm ......nnnnnddddd Vd Vn Vm
+ assert(isValidVectorDatasize(id->idOpSize()));
+ assert(isValidArrangement(id->idOpSize(), id->idInsOpt()));
+ assert(isVectorRegister(id->idReg1()));
+ assert(isVectorRegister(id->idReg2()));
+ assert(isVectorRegister(id->idReg3()));
+ break;
+
case IF_DV_4A: // DR_4A .........X.mmmmm .aaaaannnnnddddd Rd Rn Rm Ra (scalar)
assert(isValidGeneralDatasize(id->idOpSize()));
assert(isVectorRegister(id->idReg1()));
case IF_DR_3C: // DR_3C X..........mmmmm xxxsssnnnnnddddd Rd Rn Rm ext(Rm) LSL imm(0-4)
case IF_DR_3D: // DR_3D X..........mmmmm cccc..nnnnnddddd Rd Rn Rm cond
case IF_DR_3E: // DR_3E X........X.mmmmm ssssssnnnnnddddd Rd Rn Rm imm(0-63)
+ case IF_DV_3F: // DV_3F ...........mmmmm ......nnnnnddddd Vd Vn Vm (vector) - Vd both source and dest
case IF_DR_4A: // DR_4A X..........mmmmm .aaaaannnnnddddd Rd Rn Rm Ra
return true;
- case IF_DV_2C: // DV_2C .Q.........iiiii ......nnnnnddddd Vd Rn (dup/ins - vector from general)
- case IF_DV_2D: // DV_2D .Q.........iiiii ......nnnnnddddd Vd Vn[] (dup - vector)
- case IF_DV_2E: // DV_2E ...........iiiii ......nnnnnddddd Vd Vn[] (dup - scalar)
- case IF_DV_2F: // DV_2F ...........iiiii .jjjj.nnnnnddddd Vd[] Vn[] (ins - element)
- case IF_DV_2G: // DV_2G .........X...... ......nnnnnddddd Vd Vn (fmov, fcvtXX - register)
- case IF_DV_2I: // DV_2I X........X...... ......nnnnnddddd Vd Rn (fmov - from general)
- case IF_DV_2J: // DV_2J ........SS.....D D.....nnnnnddddd Vd Vn (fcvt)
- case IF_DV_2K: // DV_2K .........X.mmmmm ......nnnnn..... Vn Vm (fcmp)
- case IF_DV_2L: // DV_2L ........XX...... ......nnnnnddddd Vd Vn (abs, neg - scalar)
- case IF_DV_2M: // DV_2M .Q......XX...... ......nnnnnddddd Vd Vn (abs, neg - vector)
- case IF_DV_2P: // DV_2P ................ ......nnnnnddddd Vd Vn (aes*) - Vd both source and dest
+ case IF_DV_2C: // DV_2C .Q.........iiiii ......nnnnnddddd Vd Rn (dup/ins - vector from general)
+ case IF_DV_2D: // DV_2D .Q.........iiiii ......nnnnnddddd Vd Vn[] (dup - vector)
+ case IF_DV_2E: // DV_2E ...........iiiii ......nnnnnddddd Vd Vn[] (dup - scalar)
+ case IF_DV_2F: // DV_2F ...........iiiii .jjjj.nnnnnddddd Vd[] Vn[] (ins - element)
+ case IF_DV_2G: // DV_2G .........X...... ......nnnnnddddd Vd Vn (fmov, fcvtXX - register)
+ case IF_DV_2I: // DV_2I X........X...... ......nnnnnddddd Vd Rn (fmov - from general)
+ case IF_DV_2J: // DV_2J ........SS.....D D.....nnnnnddddd Vd Vn (fcvt)
+ case IF_DV_2K: // DV_2K .........X.mmmmm ......nnnnn..... Vn Vm (fcmp)
+ case IF_DV_2L: // DV_2L ........XX...... ......nnnnnddddd Vd Vn (abs, neg - scalar)
+ case IF_DV_2M: // DV_2M .Q......XX...... ......nnnnnddddd Vd Vn (abs, neg - vector)
+ case IF_DV_2P: // DV_2P ................ ......nnnnnddddd Vd Vn (aes*, sha1su1) - Vd both source and
+ // destination
+
case IF_DV_3A: // DV_3A .Q......XX.mmmmm ......nnnnnddddd Vd Vn Vm (vector)
case IF_DV_3AI: // DV_3AI .Q......XXLMmmmm ....H.nnnnnddddd Vd Vn Vm[] (vector)
case IF_DV_3B: // DV_3B .Q.......X.mmmmm ......nnnnnddddd Vd Vn Vm (vector)
case IF_DR_2G:
case IF_DR_2H:
case IF_DR_2I:
+ case IF_DR_2J:
case IF_DR_3A:
case IF_DR_3B:
case IF_DR_3C:
case IF_DV_3D:
case IF_DV_3DI:
case IF_DV_3E:
+ case IF_DV_3F:
case IF_DV_4A:
case IF_SN_0A:
case IF_SI_0A:
fmt = IF_DV_2P;
break;
+ case INS_sha1h:
+ assert(insOptsNone(opt));
+ assert(isVectorRegister(reg1));
+ assert(isVectorRegister(reg2));
+ fmt = IF_DR_2J;
+ break;
+
+ case INS_sha1su1:
+ assert(isVectorRegister(reg1));
+ assert(isVectorRegister(reg2));
+ assert(isValidVectorDatasize(size));
+ elemsize = optGetElemsize(opt);
+ assert(elemsize == EA_4BYTE);
+ fmt = IF_DV_2P;
+ break;
+
default:
unreached();
break;
fmt = IF_LS_3D;
break;
+ case INS_sha1su0:
+ case INS_sha1c:
+ case INS_sha1p:
+ case INS_sha1m:
+ assert(isValidVectorDatasize(size));
+ assert(isVectorRegister(reg1));
+ assert(isVectorRegister(reg2));
+ assert(isVectorRegister(reg3));
+ if (opt == INS_OPTS_NONE)
+ {
+ elemsize = EA_4BYTE;
+ opt = optMakeArrangement(size, elemsize);
+ }
+ assert(isValidArrangement(size, opt));
+ fmt = IF_DV_3F;
+ break;
+
default:
unreached();
break;
}
break;
+ case IF_DR_2J: // DR_2J ................ ......nnnnnddddd Sd Sn (sha1h)
+ code = emitInsCode(ins, fmt);
+ code |= insEncodeReg_Vd(id->idReg1()); // ddddd
+ code |= insEncodeReg_Vn(id->idReg2()); // nnnnn
+ dst += emitOutput_Instr(dst, code);
+ break;
+
case IF_DR_3A: // DR_3A X..........mmmmm ......nnnnnmmmmm Rd Rn Rm
code = emitInsCode(ins, fmt);
code |= insEncodeDatasize(id->idOpSize()); // X
dst += emitOutput_Instr(dst, code);
break;
- case IF_DV_2P: // DV_2P ............... ......nnnnnddddd Vd Vn (aes*)
+ case IF_DV_2P: // DV_2P ............... ......nnnnnddddd Vd Vn (aes*, sha1su1)
elemsize = optGetElemsize(id->idInsOpt());
code = emitInsCode(ins, fmt);
code |= insEncodeReg_Vd(id->idReg1()); // ddddd
break;
case IF_DV_3E: // DV_3E ...........mmmmm ......nnnnnddddd Vd Vn Vm (scalar)
+ case IF_DV_3F: // DV_3F ...........mmmmm ......nnnnnddddd Vd Vn Vm (vector) - source dest regs overlap
code = emitInsCode(ins, fmt);
code |= insEncodeReg_Vd(id->idReg1()); // ddddd
code |= insEncodeReg_Vn(id->idReg2()); // nnnnn
break;
case IF_DR_2E: // DR_2E X..........mmmmm ...........ddddd Rd Rm
+ case IF_DR_2J: // DR_2J ................ ......nnnnnddddd Sd Sn
emitDispReg(id->idReg1(), size, true);
emitDispReg(id->idReg2(), size, false);
break;
case IF_DV_2A: // DV_2A .Q.......X...... ......nnnnnddddd Vd Vn (fabs, fcvt - vector)
case IF_DV_2M: // DV_2M .Q......XX...... ......nnnnnddddd Vd Vn (abs, neg - vector)
- case IF_DV_2P: // DV_2P ................ ......nnnnnddddd Vd Vn (aes*)
+ case IF_DV_2P: // DV_2P ................ ......nnnnnddddd Vd Vn (aes*, sha1su1)
emitDispVectorReg(id->idReg1(), id->idInsOpt(), true);
emitDispVectorReg(id->idReg2(), id->idInsOpt(), false);
break;
emitDispReg(id->idReg3(), size, false);
break;
+ case IF_DV_3F: // DV_3F ..........mmmmm ......nnnnnddddd Vd Vn Vm (vector)
+ if ((ins == INS_sha1c) || (ins == INS_sha1m) || (ins == INS_sha1p))
+ {
+ // Qd, Sn, Vm (vector)
+ emitDispReg(id->idReg1(), size, true);
+ emitDispReg(id->idReg2(), EA_4BYTE, true);
+ emitDispVectorReg(id->idReg3(), id->idInsOpt(), false);
+ }
+ else
+ {
+ emitDispVectorReg(id->idReg1(), id->idInsOpt(), true);
+ emitDispVectorReg(id->idReg2(), id->idInsOpt(), true);
+ emitDispVectorReg(id->idReg3(), id->idInsOpt(), false);
+ }
+ break;
+
case IF_DV_3DI: // DV_3DI .........XLmmmmm ....H.nnnnnddddd Vd Vn Vm[] (scalar by elem)
emitDispReg(id->idReg1(), size, true);
emitDispReg(id->idReg2(), size, true);
IF_DEF(DR_2G, IS_NONE, NONE) // DR_2G X............... ......nnnnnddddd Rd Rn
IF_DEF(DR_2H, IS_NONE, NONE) // DR_2H X........X...... ......nnnnnddddd Rd Rn
IF_DEF(DR_2I, IS_NONE, NONE) // DR_2I X..........mmmmm cccc..nnnnn.nzcv Rn Rm nzcv cond
+IF_DEF(DR_2J, IS_NONE, NONE) // DR_2J ................ ......nnnnnddddd Sd Sn
IF_DEF(DR_3A, IS_NONE, NONE) // DR_3A X..........mmmmm ......nnnnnddddd Rd Rn Rm
IF_DEF(DR_3B, IS_NONE, NONE) // DR_3B X.......sh.mmmmm ssssssnnnnnddddd Rd Rn Rm {LSL,LSR,ASR} imm(0-63)
IF_DEF(DV_3D, IS_NONE, NONE) // DV_3D .........X.mmmmm ......nnnnnddddd Vd Vn Vm (scalar)
IF_DEF(DV_3DI, IS_NONE, NONE) // DV_3DI .........XLmmmmm ....H.nnnnnddddd Vd Vn Vm[] (scalar by elem)
IF_DEF(DV_3E, IS_NONE, NONE) // DV_3E ...........mmmmm ......nnnnnddddd Vd Vn Vm (scalar)
+IF_DEF(DV_3F, IS_NONE, NONE) // DV_3F ...........mmmmm ......nnnnnddddd Qd Sn Vm (Qd used as both source and destination)
IF_DEF(DV_4A, IS_NONE, NONE) // DV_4A .........X.mmmmm .aaaaannnnnddddd Vd Vn Vm Va (scalar)
case HWIntrinsicInfo::SimdSetAllOp:
case HWIntrinsicInfo::SimdUnaryOp:
case HWIntrinsicInfo::SimdBinaryRMWOp:
+ case HWIntrinsicInfo::SimdTernaryRMWOp:
+ case HWIntrinsicInfo::Sha1HashOp:
simdClass = sig->retTypeClass;
break;
case HWIntrinsicInfo::SimdExtractOp:
return gtNewSimdHWIntrinsicNode(simdType, op1, op2, intrinsic, simdBaseType, simdSizeBytes);
+ case HWIntrinsicInfo::SimdTernaryRMWOp:
case HWIntrinsicInfo::SimdSelectOp:
// op1 is the first operand
// op2 is the second operand
return gtNewSimdHWIntrinsicNode(simdType, op1, op2, op3, intrinsic, simdBaseType, simdSizeBytes);
+ case HWIntrinsicInfo::Sha1HashOp:
+ op3 = impSIMDPopStack(simdType);
+ op2 = impPopStack().val;
+ op1 = impSIMDPopStack(simdType);
+
+ return gtNewSimdHWIntrinsicNode(simdType, op1, op2, op3, intrinsic, simdBaseType, simdSizeBytes);
+
+ case HWIntrinsicInfo::Sha1RotateOp:
+ assert(sig->numArgs == 1);
+ return gtNewScalarHWIntrinsicNode(TYP_UINT, impPopStack().val, NI_ARM64_Sha1FixedRotate);
+
default:
JITDUMP("Not implemented hardware intrinsic form");
assert(!"Unimplemented SIMD Intrinsic form");
IsSupported, // The IsSupported property will use this form
Unsupported, // Any intrisic which is unsupported and must throw PlatformNotSupportException will use this form
// Non SIMD forms
- UnaryOp, // Non SIMD intrinsics which take a single argument
- CrcOp, // Crc intrinsics.
+ UnaryOp, // Non SIMD intrinsics which take a single argument
+ CrcOp, // Crc intrinsics.
+ Sha1RotateOp, // SHA1 Hash Rotate intrinsics. Takes hash index unsigned int and returns unsigned int.
+
// SIMD common forms
- SimdBinaryOp, // SIMD intrinsics which take two vector operands and return a vector
- SimdUnaryOp, // SIMD intrinsics which take one vector operand and return a vector
- SimdBinaryRMWOp, // Same as SimdBinaryOp , with first source vector used as destination vector also.
+ SimdBinaryOp, // SIMD intrinsics which take two vector operands and return a vector
+ SimdUnaryOp, // SIMD intrinsics which take one vector operand and return a vector
+ SimdBinaryRMWOp, // Same as SimdBinaryOp , with first source vector used as destination vector also.
+ SimdTernaryRMWOp, // SIMD intrinsics which take three vector operands and return a vector ,
+ // with destination vector same as first source vector
// SIMD custom forms
SimdExtractOp, // SIMD intrinsics which take one vector operand and a lane index and return an element
SimdInsertOp, // SIMD intrinsics which take one vector operand and a lane index and value and return a vector
SimdSelectOp, // BitwiseSelect intrinsic which takes three vector operands and returns a vector
SimdSetAllOp, // Simd intrinsics which take one numeric operand and return a vector
+ Sha1HashOp // SIMD instrisics for SHA1 Hash operations. Takes two vectors and hash index and returns vector
};
// Flags will be used to handle secondary meta-data which will help
HARDWARE_INTRINSIC(NI_ARM64_AesMixColumns, Aes, MixColumns, SimdUnaryOp, INS_invalid, INS_invalid, INS_aesmc, None )
HARDWARE_INTRINSIC(NI_ARM64_AesInvMixColumns, Aes, InverseMixColumns, SimdUnaryOp, INS_invalid, INS_invalid, INS_aesimc, None )
+//Sha1
+HARDWARE_INTRINSIC(NI_ARM64_Sha1Choose, Sha1, HashChoose, Sha1HashOp, INS_invalid, INS_invalid, INS_sha1c, None )
+HARDWARE_INTRINSIC(NI_ARM64_Sha1Parity, Sha1, HashParity, Sha1HashOp, INS_invalid, INS_invalid, INS_sha1p, None )
+HARDWARE_INTRINSIC(NI_ARM64_Sha1Majority, Sha1, HashMajority, Sha1HashOp, INS_invalid, INS_invalid, INS_sha1m, None )
+HARDWARE_INTRINSIC(NI_ARM64_Sha1FixedRotate, Sha1, FixedRotate, Sha1RotateOp, INS_invalid, INS_invalid, INS_sha1h, None )
+HARDWARE_INTRINSIC(NI_ARM64_Sha1SchedulePart1, Sha1, SchedulePart1, SimdTernaryRMWOp, INS_invalid, INS_invalid, INS_sha1su0, None )
+HARDWARE_INTRINSIC(NI_ARM64_Sha1SchedulePart2, Sha1, SchedulePart2, SimdBinaryRMWOp, INS_invalid, INS_invalid, INS_sha1su1, None )
+
#endif
INST1(rorv, "rorv", 0, 0, IF_DR_3A, 0x1AC02C00)
// rorv Rd,Rn,Rm DR_3A X0011010110mmmmm 001011nnnnnddddd 1AC0 2C00
+
+INST1(sha1c, "sha1c", 0, 0, IF_DV_3F, 0x5E000000)
+ // sha1c Qd, Sn Vm.4S DV_3F 01011110000mmmmm 000000nnnnnddddd 5E00 0000 Qd Sn Vm.4S (vector)
+
+INST1(sha1m, "sha1m", 0, 0, IF_DV_3F, 0x5E002000)
+ // sha1m Qd, Sn Vm.4S DV_3F 01011110000mmmmm 001000nnnnnddddd 5E00 0000 Qd Sn Vm.4S (vector)
+
+INST1(sha1p, "sha1p", 0, 0, IF_DV_3F, 0x5E001000)
+ // sha1m Qd, Sn Vm.4S DV_3F 01011110000mmmmm 000100nnnnnddddd 5E00 0000 Qd Sn Vm.4S (vector)
+
+INST1(sha1h, "sha1h", 0, 0, IF_DR_2J, 0x5E280800)
+ // sha1h Sd, Sn DR_2H 0101111000101000 000010nnnnnddddd 5E28 0800 Sn Sn
+
+INST1(sha1su0, "sha1su0", 0, 0, IF_DV_3F, 0x5E003000)
+ // sha1su0 Vd.4S,Vn.4S,Vm.4S DV_3F 01011110000mmmmm 001100nnnnnddddd 5E00 3000 Vd.4S Vn.4S Vm.4S (vector)
+
+INST1(sha1su1, "sha1su1", 0, 0, IF_DV_2P, 0x5E281800)
+ // sha1su1 Vd.4S, Vn.4S DV_2P 0101111000101000 000110nnnnnddddd 5E28 1800 Vd.4S Vn.4S (vector)
INST1(sbfm, "sbfm", 0, 0, IF_DI_2D, 0x13000000)
// sbfm Rd,Rn,imr,ims DI_2D X00100110Nrrrrrr ssssssnnnnnddddd 1300 0000 imr, ims
switch (compiler->getHWIntrinsicInfo(intrinsicID).form)
{
+ case HWIntrinsicInfo::Sha1HashOp:
+ info->setInternalCandidates(this, RBM_ALLFLOAT);
+ info->internalFloatCount = 1;
+ if (!op2->isContained())
+ {
+ LocationInfoListNode* op2Info = useList.Begin()->Next();
+ op2Info->info.isDelayFree = true;
+ GenTree* op3 = intrinsicTree->gtOp.gtOp1->AsArgList()->Rest()->Rest()->Current();
+ assert(!op3->isContained());
+ LocationInfoListNode* op3Info = op2Info->Next();
+ op3Info->info.isDelayFree = true;
+ info->hasDelayFreeSrc = true;
+ info->isInternalRegDelayFree = true;
+ }
+ break;
+ case HWIntrinsicInfo::SimdTernaryRMWOp:
+ if (!op2->isContained())
+ {
+ LocationInfoListNode* op2Info = useList.Begin()->Next();
+ op2Info->info.isDelayFree = true;
+ GenTree* op3 = intrinsicTree->gtOp.gtOp1->AsArgList()->Rest()->Rest()->Current();
+ assert(!op3->isContained());
+ LocationInfoListNode* op3Info = op2Info->Next();
+ op3Info->info.isDelayFree = true;
+ info->hasDelayFreeSrc = true;
+ }
+ break;
+ case HWIntrinsicInfo::Sha1RotateOp:
+ info->setInternalCandidates(this, RBM_ALLFLOAT);
+ info->internalFloatCount = 1;
+ break;
+
case HWIntrinsicInfo::SimdExtractOp:
case HWIntrinsicInfo::SimdInsertOp:
if (!op2->isContained())
<ItemGroup Condition="'$(Platform)' == 'arm64'">
<Compile Include="$(BclSourcesRoot)\System\Runtime\Intrinsics\Arm\Arm64\Simd.cs" />
<Compile Include="$(BclSourcesRoot)\System\Runtime\Intrinsics\Arm\Arm64\Aes.cs" />
+ <Compile Include="$(BclSourcesRoot)\System\Runtime\Intrinsics\Arm\Arm64\Sha1.cs" />
</ItemGroup>
<ItemGroup Condition="'$(Platform)' != 'arm64'">
<Compile Include="$(BclSourcesRoot)\System\Runtime\Intrinsics\Arm\Arm64\Simd.PlatformNotSupported.cs" />
<Compile Include="$(BclSourcesRoot)\System\Runtime\Intrinsics\Arm\Arm64\Aes.PlatformNotSupported.cs" />
+ <Compile Include="$(BclSourcesRoot)\System\Runtime\Intrinsics\Arm\Arm64\Sha1.PlatformNotSupported.cs" />
</ItemGroup>
<ItemGroup>
<Compile Include="$(BclSourcesRoot)\System\AppContext\AppContext.cs" />
--- /dev/null
+using System.Runtime.CompilerServices;
+using System.Runtime.Intrinsics;
+
+namespace System.Runtime.Intrinsics.Arm.Arm64
+{
+ /// <summary>
+ /// This class provides access to the Arm64 SHA1 Crypto intrinsics
+ ///
+ /// Arm64 CPU indicate support for this feature by setting
+ /// ID_AA64ISAR0_EL1.SHA1 is 1 or better
+ /// </summary>
+ [CLSCompliant(false)]
+ public static class Sha1
+ {
+
+ public static bool IsSupported { get { return false; } }
+
+ // <summary>
+ /// Performs SHA1 hash update choose form.
+ /// vsha1cq_u32 (uint32x4_t hash_abcd, uint32_t hash_e, uint32x4_t wk)
+ ///</summary>
+ public static Vector128<uint> HashChoose(Vector128<uint> hash_abcd, uint hash_e, Vector128<uint>wk) { throw new PlatformNotSupportedException(); }
+
+ // <summary>
+ /// Performs SHA1 hash update majority form.
+ /// vsha1mq_u32 (uint32x4_t hash_abcd, uint32_t hash_e, uint32x4_t wk)
+ ///</summary>
+ public static Vector128<uint> HashMajority(Vector128<uint> hash_abcd, uint hash_e, Vector128<uint>wk) { throw new PlatformNotSupportedException(); }
+
+ // <summary>
+ /// Performs SHA1 hash update parity form.
+ /// vsha1pq_u32 (uint32x4_t hash_abcd, uint32_t hash_e, uint32x4_t wk)
+ ///</summary>
+ public static Vector128<uint> HashParity(Vector128<uint> hash_abcd, uint hash_e, Vector128<uint>wk) { throw new PlatformNotSupportedException(); }
+
+ // <summary>
+ /// Performs SHA1 fixed rotate
+ /// vsha1h_u32 (uint32_t hash_e)
+ ///</summary>
+ public static uint FixedRotate(uint hash_e) { throw new PlatformNotSupportedException(); }
+
+ // <summary>
+ /// Performs SHA1 schedule update 0
+ /// vsha1su0q_u32 (uint32x4_t w0_3, uint32x4_t w4_7, uint32x4_t w8_11)
+ ///</summary>
+ public static Vector128<uint> SchedulePart1(Vector128<uint> w0_3, Vector128<uint> w4_7, Vector128<uint> w8_11) { throw new PlatformNotSupportedException(); }
+
+ // <summary>
+ /// Performs SHA1 schedule update 1
+ /// vsha1su1q_u32 (uint32x4_t tw0_3, uint32x4_t w12_15)
+ ///</summary>
+ public static Vector128<uint> SchedulePart2(Vector128<uint> tw0_3, Vector128<uint> w12_15) { throw new PlatformNotSupportedException(); }
+ }
+}
--- /dev/null
+using System.Runtime.CompilerServices;
+using System.Runtime.Intrinsics;
+
+namespace System.Runtime.Intrinsics.Arm.Arm64
+{
+ /// <summary>
+ /// This class provides access to the Arm64 SHA1 Crypto intrinsics
+ ///
+ /// Arm64 CPU indicate support for this feature by setting
+ /// ID_AA64ISAR0_EL1.SHA1 is 1 or better
+ /// </summary>
+ [CLSCompliant(false)]
+ public static class Sha1
+ {
+ public static bool IsSupported { get => IsSupported; }
+
+ // <summary>
+ /// Performs SHA1 hash update choose form.
+ /// vsha1cq_u32 (uint32x4_t hash_abcd, uint32_t hash_e, uint32x4_t wk)
+ ///</summary>
+ public static Vector128<uint> HashChoose(Vector128<uint> hash_abcd, uint hash_e, Vector128<uint>wk) => HashChoose(hash_abcd, hash_e, wk);
+
+ // <summary>
+ /// Performs SHA1 hash update majority form.
+ /// vsha1mq_u32 (uint32x4_t hash_abcd, uint32_t hash_e, uint32x4_t wk)
+ ///</summary>
+ public static Vector128<uint> HashMajority(Vector128<uint> hash_abcd, uint hash_e, Vector128<uint>wk) => HashMajority(hash_abcd, hash_e, wk);
+
+ // <summary>
+ /// Performs SHA1 hash update parity form.
+ /// vsha1pq_u32 (uint32x4_t hash_abcd, uint32_t hash_e, uint32x4_t wk)
+ ///</summary>
+ public static Vector128<uint> HashParity(Vector128<uint> hash_abcd, uint hash_e, Vector128<uint>wk) => HashParity(hash_abcd, hash_e, wk);
+
+ // <summary>
+ /// Performs SHA1 fixed rotate
+ /// vsha1h_u32 (uint32_t hash_e)
+ ///</summary>
+ public static uint FixedRotate(uint hash_e) => FixedRotate(hash_e);
+
+ // <summary>
+ /// Performs SHA1 schedule update 0
+ /// vsha1su0q_u32 (uint32x4_t w0_3, uint32x4_t w4_7, uint32x4_t w8_11)
+ ///</summary>
+ public static Vector128<uint> SchedulePart1(Vector128<uint> w0_3, Vector128<uint> w4_7, Vector128<uint> w8_11) => SchedulePart1(w0_3, w4_7, w8_11);
+
+ // <summary>
+ /// Performs SHA1 schedule update 1
+ /// vsha1su1q_u32 (uint32x4_t tw0_3, uint32x4_t w12_15)
+ ///</summary>
+ public static Vector128<uint> SchedulePart2(Vector128<uint> tw0_3, Vector128<uint> w12_15) => SchedulePart2(tw0_3, w12_15);
+ }
+}