| 1921 | } |
| 1922 | |
| 1923 | void OpDispatchBuilder::ADXOp(OpcodeArgs) { |
| 1924 | const auto OpSize = OpSizeFromSrc(Op); |
| 1925 | |
| 1926 | // Only 32/64-bit anyway so allow garbage, we use 32-bit ops. |
| 1927 | auto* Src = LoadSource(GPRClass, Op, Op->Src[0], Op->Flags, {.AllowUpperGarbage = true}); |
| 1928 | auto* Before = LoadSource(GPRClass, Op, Op->Dest, Op->Flags, {.AllowUpperGarbage = true}); |
| 1929 | |
| 1930 | // Handles ADCX and ADOX |
| 1931 | const bool IsADCX = Op->OP == 0x1F6; |
| 1932 | auto Zero = Constant(0); |
| 1933 | |
| 1934 | // Before we go trashing NZCV, save the current NZCV state. |
| 1935 | Ref OldNZCV = GetNZCV(); |
| 1936 | |
| 1937 | // We want to use arm64 adc. For ADOX, copy the overflow flag into CF. For |
| 1938 | // ADCX, we just rectify the carry. |
| 1939 | if (IsADCX) { |
| 1940 | RectifyCarryInvert(false); |
| 1941 | } else { |
| 1942 | // If overflow, 0 - 0 sets carry. Else, forces carry to 0. |
| 1943 | _CondSubNZCV(OpSize::i32Bit, Zero, Zero, {COND_FU}, 0x0 /* nzcv */); |
| 1944 | } |
| 1945 | |
| 1946 | // Do the actual add. |
| 1947 | HandleNZCV_RMW(); |
| 1948 | auto Result = _AdcWithFlags(OpSize, Src, Before); |
| 1949 | StoreResult(GPRClass, Op, Result, OpSize::iInvalid); |
| 1950 | |
| 1951 | // Now restore all flags except the one we're updating. |
| 1952 | if (CTX->HostFeatures.SupportsFlagM) { |
| 1953 | // For ADOX, we need to copy the new carry into the overflow flag. If carry is clear (ULT with uninverted |
| 1954 | // carry), 0 - 0 clears overflow. Else, force overflow on. |
| 1955 | if (!IsADCX) { |
| 1956 | _CondSubNZCV(OpSize::i32Bit, Zero, Zero, {COND_ULT}, 0x1 /* nzcV */); |
| 1957 | } |
| 1958 | |
| 1959 | _RmifNZCV(OldNZCV, 28, IsADCX ? 0xd /* NzcV */ : 0xe /* NZCv */); |
| 1960 | } else { |
| 1961 | // For either operation, insert the new flag into the old NZCV. |
| 1962 | bool SavedCFInvert = CFInverted; |
| 1963 | CFInverted = false; |
| 1964 | Ref OutputCF = GetRFLAG(X86State::RFLAG_CF_RAW_LOC, IsADCX); |
| 1965 | CFInverted = IsADCX ? true : SavedCFInvert; |
| 1966 | |
| 1967 | Ref NewNZCV = _Bfi(OpSize::i32Bit, 1, IsADCX ? 29 : 28, OldNZCV, OutputCF); |
| 1968 | SetNZCV(NewNZCV); |
| 1969 | } |
| 1970 | } |
| 1971 | |
| 1972 | void OpDispatchBuilder::RCROp1Bit(OpcodeArgs) { |
| 1973 | // Calculate flags early. |
nothing calls this directly
no outgoing calls
no test coverage detected