MCPcopy Create free account
hub / github.com/FEX-Emu/FEX / ALUOp

Method ALUOp

FEXCore/Source/Interface/Core/OpcodeDispatcher.cpp:4449–4551  ·  view source on GitHub ↗

Source from the content-addressed store, hash-verified

4447}
4448
4449void OpDispatchBuilder::ALUOp(OpcodeArgs, FEXCore::IR::IROps ALUIROp, FEXCore::IR::IROps AtomicFetchOp, unsigned SrcIdx) {
4450 // On x86, the canonical way to zero a register is XOR with itself. Detect and
4451 // emit optimal arm64 assembly.
4452 if (!DestIsLockedMem(Op) && ALUIROp == FEXCore::IR::IROps::OP_XOR && Op->Dest.IsGPR() && Op->Src[SrcIdx].IsGPR() &&
4453 Op->Dest.Data.GPR == Op->Src[SrcIdx].Data.GPR) {
4454
4455 // Set flags for zero result with inverted carry. We subtract an arbitrary
4456 // register from itself to get the zero, since `subs wzr, #0` is not
4457 // encodable. This is optimal and works regardless of the opsize.
4458 auto Zero = LoadGPR(Op->Dest.Data.GPR.GPR);
4459 HandleNZ00Write();
4460 InvalidateAF();
4461 CalculatePF(SubWithFlags(OpSize::i32Bit, Zero, Zero));
4462 CFInverted = true;
4463 FlushRegisterCache();
4464
4465 // Move 0 into the register
4466 StoreResult(GPRClass, Op, Constant(0), OpSize::iInvalid);
4467 return;
4468 }
4469
4470 auto Size = OpSizeFromDst(Op);
4471 auto ResultSize = Size;
4472
4473 auto RoundedSize = Size;
4474 if (ALUIROp != FEXCore::IR::IROps::OP_ANDWITHFLAGS) {
4475 RoundedSize = std::max(OpSize::i32Bit, RoundedSize);
4476 }
4477
4478 // X86 basic ALU ops just do the operation between the destination and a single source
4479 Ref Src = LoadSource(GPRClass, Op, Op->Src[SrcIdx], Op->Flags, {.AllowUpperGarbage = true});
4480
4481 // Try to eliminate the masking after 8/16-bit operations with constants, by
4482 // promoting to a full size operation that preserves the upper bits.
4483 uint64_t Const;
4484 bool IsConst = IsValueConstant(WrapNode(Src), &Const);
4485 if (Size < OpSize::i32Bit && !DestIsLockedMem(Op) && Op->Dest.IsGPR() && !Op->Dest.Data.GPR.HighBits && IsConst &&
4486 (ALUIROp == IR::IROps::OP_XOR || ALUIROp == IR::IROps::OP_OR || ALUIROp == IR::IROps::OP_ANDWITHFLAGS)) {
4487
4488 RoundedSize = ResultSize = GetGPROpSize();
4489 LOGMAN_THROW_A_FMT(Const < (1ull << IR::OpSizeAsBits(Size)), "does not clobber");
4490
4491 // For AND, we can play the same trick but we instead need the upper bits of
4492 // the constant to be all-1s instead of all-0s to preserve. We also can't
4493 // use andwithflags in this case, since we've promoted to 64-bit so the
4494 // negate flag would be wrong, but using the regular logical operation path
4495 // instead still ends up a net win for uops.
4496 //
4497 // In the common case where the constant is of the form (1 << x) - 1, the
4498 // adjusted constant here will inline into the arm64 and instruction, so if
4499 // flags are not needed, we save an instruction overall.
4500 if (ALUIROp == IR::IROps::OP_ANDWITHFLAGS) {
4501 Src = Constant(Const | ~((1ull << IR::OpSizeAsBits(Size)) - 1));
4502 ALUIROp = IR::IROps::OP_AND;
4503 }
4504 }
4505
4506 Ref Result {};

Callers

nothing calls this directly

Calls 3

OpSizeAsBitsFunction · 0.85
DeriveOpFunction · 0.85
IsGPRMethod · 0.45

Tested by

no test coverage detected