Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
54 changes: 41 additions & 13 deletions src/compiler/evm_frontend/evm_mir_compiler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1413,6 +1413,18 @@ typename EVMMirBuilder::Operand EVMMirBuilder::handleMul(Operand MultiplicandOp,
return Operand(intxToU256Value(A * B));
}

if (MultiplicandOp.isZeroConstant() || MultiplierOp.isZeroConstant()) {
return Operand(U256Value{0, 0, 0, 0});
}

if (MultiplicandOp.isOneConstant()) {
return MultiplierOp;
}

if (MultiplierOp.isOneConstant()) {
return MultiplicandOp;
}

// Phase 4: u64 fast path - one operand fits in u64 (4x1 multiplication)
bool AIsU64 = MultiplicandOp.isConstU64();
bool BIsU64 = MultiplierOp.isConstU64();
Expand Down Expand Up @@ -1998,7 +2010,8 @@ typename EVMMirBuilder::Operand EVMMirBuilder::handleExp(Operand BaseOp,
}

EVMMirBuilder::U256Inst EVMMirBuilder::handleCompareEQZ(const U256Inst &LHS,
MType *ResultType) {
MType *ResultType,
bool IsNegated) {
U256Inst Result = {};
MType *MirI64Type =
EVMFrontendContext::getMIRTypeFromEVMType(EVMType::UINT64);
Expand All @@ -2016,7 +2029,8 @@ EVMMirBuilder::U256Inst EVMMirBuilder::handleCompareEQZ(const U256Inst &LHS,

// Final result is 1 if all are zero, 0 otherwise
MInstruction *Zero = createIntConstInstruction(MirI64Type, 0);
auto Predicate = CmpInstruction::Predicate::ICMP_EQ;
auto Predicate = IsNegated ? CmpInstruction::Predicate::ICMP_NE
: CmpInstruction::Predicate::ICMP_EQ;
MInstruction *CmpResult = createInstruction<CmpInstruction>(
false, Predicate, ResultType, OrResult, Zero);

Expand Down Expand Up @@ -2140,19 +2154,11 @@ typename EVMMirBuilder::Operand EVMMirBuilder::handleNot(const Operand &LHSOp) {
return Operand(U256Value{~V[0], ~V[1], ~V[2], ~V[3]});
}

U256Inst Result = {};
U256Inst LHS = extractU256Operand(LHSOp);

MType *MirI64Type =
EVMFrontendContext::getMIRTypeFromEVMType(EVMType::UINT64);

for (size_t I = 0; I < EVM_ELEMENTS_COUNT; ++I) {
MInstruction *LocalResult =
createInstruction<NotInstruction>(false, MirI64Type, LHS[I]);
Result[I] = protectUnsafeValue(LocalResult, MirI64Type);
if (LHSOp.isDeferredBitwiseNot()) {
return Operand(LHSOp.getDeferredBaseComponents(), EVMType::UINT256);
}

return Operand(Result, EVMType::UINT256);
return Operand::createDeferredBitwiseNot(extractU256Operand(LHSOp));
}

// ==================== u64 Fast Path Helpers ====================
Expand Down Expand Up @@ -3792,6 +3798,23 @@ EVMMirBuilder::U256Inst EVMMirBuilder::extractU256Operand(const Operand &Opnd) {
return Result;
}

if (Opnd.isDeferredBitwiseNot()) {
const U256Inst &Base = Opnd.getDeferredBaseComponents();
MType *MirI64Type =
EVMFrontendContext::getMIRTypeFromEVMType(EVMType::UINT64);
for (size_t I = 0; I < EVM_ELEMENTS_COUNT; ++I) {
MInstruction *LocalResult =
createInstruction<NotInstruction>(false, MirI64Type, Base[I]);
Result[I] = protectUnsafeValue(LocalResult, MirI64Type);
}
return Result;
}

if (Opnd.isDeferredZeroTest()) {
return handleCompareEQZ(Opnd.getDeferredBaseComponents(), &Ctx.I64Type,
Opnd.isDeferredZeroTestNegated());
}

if (Opnd.isU256MultiComponent()) {
U256Inst Instrs = Opnd.getU256Components();
if (Instrs[0] != nullptr) {
Expand Down Expand Up @@ -4344,6 +4367,11 @@ EVMMirBuilder::convertOperandToUNInstruction(const Operand &Param) {
for (size_t I = 0; I < N; ++I) {
Result[I] = Components[I];
}
} else if (Param.isDeferredValue()) {
auto Components = extractU256Operand(Param);
for (size_t I = 0; I < N; ++I) {
Result[I] = Components[I];
}
} else if (Param.isU256MultiComponent()) {
auto Components = Param.getU256Components();
for (size_t I = 0; I < N; ++I) {
Expand Down
104 changes: 102 additions & 2 deletions src/compiler/evm_frontend/evm_mir_compiler.h
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,8 @@ class EVMMirBuilder final {

class Operand {
public:
enum class DeferredKind : uint8_t { NONE, BITWISE_NOT, ZERO_TEST };

Operand() = default;
Operand(MInstruction *Instr, EVMType Type) : Instr(Instr), Type(Type) {}
Operand(Variable *Var, EVMType Type) : Var(Var), Type(Type) {}
Expand All @@ -138,21 +140,66 @@ class EVMMirBuilder final {
Operand(const U256Value &ConstValue)
: Type(EVMType::UINT256), ConstValue(ConstValue), IsConstant(true) {}

static Operand createDeferredBitwiseNot(U256Inst BaseComponents) {
Operand Result;
Result.Type = EVMType::UINT256;
Result.DeferredValueKind = DeferredKind::BITWISE_NOT;
Result.U256Components = BaseComponents;
return Result;
}

static Operand createDeferredZeroTest(U256Inst BaseComponents,
bool IsNegated) {
Operand Result;
Result.Type = EVMType::UINT256;
Result.DeferredValueKind = DeferredKind::ZERO_TEST;
Result.U256Components = BaseComponents;
Result.DeferredZeroTestNegated = IsNegated;
return Result;
}

MInstruction *getInstr() const { return Instr; }
Variable *getVar() const { return Var; }
EVMType getType() const { return Type; }

bool isEmpty() const {
return !Instr && !Var && !IsU256MultiComponent && !IsConstant &&
Type == EVMType::VOID;
DeferredValueKind == DeferredKind::NONE && Type == EVMType::VOID;
}

bool isU256MultiComponent() const { return IsU256MultiComponent; }
bool isConstant() const { return IsConstant; }
bool isZeroConstant() const {
return IsConstant && ConstValue[0] == 0 && ConstValue[1] == 0 &&
ConstValue[2] == 0 && ConstValue[3] == 0;
}
bool isOneConstant() const {
return IsConstant && ConstValue[0] == 1 && ConstValue[1] == 0 &&
ConstValue[2] == 0 && ConstValue[3] == 0;
}
bool isAllOnesConstant() const {
return IsConstant && ConstValue[0] == UINT64_MAX &&
ConstValue[1] == UINT64_MAX && ConstValue[2] == UINT64_MAX &&
ConstValue[3] == UINT64_MAX;
}
bool isConstU64() const {
return IsConstant && ConstValue[1] == 0 && ConstValue[2] == 0 &&
ConstValue[3] == 0;
}
bool isDeferredValue() const {
return DeferredValueKind != DeferredKind::NONE;
}
bool isDeferredBitwiseNot() const {
return DeferredValueKind == DeferredKind::BITWISE_NOT;
}
bool isDeferredZeroTest() const {
return DeferredValueKind == DeferredKind::ZERO_TEST;
}
bool isDeferredZeroTestNegated() const {
ZEN_ASSERT(DeferredValueKind == DeferredKind::ZERO_TEST &&
"Not a deferred zero-test value");
return DeferredZeroTestNegated;
}

const U256Inst &getU256Components() const {
ZEN_ASSERT(IsU256MultiComponent && "Not a multi-component U256");
Expand All @@ -166,6 +213,11 @@ class EVMMirBuilder final {
ZEN_ASSERT(IsConstant && "Not a constant value");
return ConstValue;
}
const U256Inst &getDeferredBaseComponents() const {
ZEN_ASSERT(DeferredValueKind != DeferredKind::NONE &&
"Not a deferred value");
return U256Components;
}

constexpr bool isReg() { return false; }
constexpr bool isTempReg() { return true; }
Expand All @@ -182,6 +234,8 @@ class EVMMirBuilder final {
U256Value ConstValue = {};
bool IsConstant = false;
bool IsU256MultiComponent = false;
DeferredKind DeferredValueKind = DeferredKind::NONE;
bool DeferredZeroTestNegated = false;
};

bool compile(CompilerContext *Context);
Expand Down Expand Up @@ -243,6 +297,21 @@ class EVMMirBuilder final {
return Operand(intxToU256Value(Res));
}

if constexpr (Operator == BinaryOperator::BO_ADD) {
if (LHSOp.isZeroConstant()) {
return RHSOp;
}
if (RHSOp.isZeroConstant()) {
return LHSOp;
}
}

if constexpr (Operator == BinaryOperator::BO_SUB) {
if (RHSOp.isZeroConstant()) {
return LHSOp;
}
}

// Phase 2: u64 fast path for ADD - share zero const for upper RHS limbs
if constexpr (Operator == BinaryOperator::BO_ADD) {
bool LHSIsU64 = LHSOp.isConstU64();
Expand Down Expand Up @@ -343,6 +412,14 @@ class EVMMirBuilder final {
uint64_t R = (V[0] == 0 && V[1] == 0 && V[2] == 0 && V[3] == 0) ? 1 : 0;
return Operand(U256Value{R, 0, 0, 0});
}

if (LHSOp.isDeferredZeroTest()) {
return Operand::createDeferredZeroTest(
LHSOp.getDeferredBaseComponents(),
!LHSOp.isDeferredZeroTestNegated());
}

return Operand::createDeferredZeroTest(extractU256Operand(LHSOp), false);
} else {
if (LHSOp.isConstant() && RHSOp.isConstant()) {
intx::uint256 L = u256ValueToIntx(LHSOp.getConstValue());
Expand Down Expand Up @@ -426,6 +503,28 @@ class EVMMirBuilder final {
return Operand(Res);
}

if constexpr (Operator == BinaryOperator::BO_AND) {
if (LHSOp.isZeroConstant() || RHSOp.isZeroConstant()) {
return Operand(U256Value{0, 0, 0, 0});
}
if (LHSOp.isAllOnesConstant()) {
return RHSOp;
}
if (RHSOp.isAllOnesConstant()) {
return LHSOp;
}
}

if constexpr (Operator == BinaryOperator::BO_OR ||
Operator == BinaryOperator::BO_XOR) {
if (LHSOp.isZeroConstant()) {
return RHSOp;
}
if (RHSOp.isZeroConstant()) {
return LHSOp;
}
}

// Phase 1: u64 fast path for AND - upper limbs are annihilated to 0
if constexpr (Operator == BinaryOperator::BO_AND) {
if (LHSOp.isConstU64() || RHSOp.isConstU64()) {
Expand Down Expand Up @@ -744,7 +843,8 @@ class EVMMirBuilder final {
}
}

U256Inst handleCompareEQZ(const U256Inst &LHS, MType *ResultType);
U256Inst handleCompareEQZ(const U256Inst &LHS, MType *ResultType,
bool IsNegated = false);

U256Inst handleCompareEQ(const U256Inst &LHS, const U256Inst &RHS,
MType *ResultType);
Expand Down
33 changes: 27 additions & 6 deletions src/compiler/target/x86/x86_cg_peephole.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ void X86CgPeephole::peepholeOptimize(CgBasicBlock &MBB,
void X86CgPeephole::optimizeCmp(CgBasicBlock &MBB,
CgBasicBlock::iterator &MII) {
auto MIE = MBB.end();
// cmp/test -> setcc cond -> test -> jne
// cmp/test -> setcc cond -> [movzx] -> test -> jne
// optimized to: cmp/test -> jcc cond
auto LocalMII = MII;
LocalMII++;
Expand All @@ -42,12 +42,28 @@ void X86CgPeephole::optimizeCmp(CgBasicBlock &MBB,
if (!Op1.isReg())
return;
auto CC = Inst1.getOperand(1).getImm();
unsigned TestReg = Op1.getReg();
CgInstruction *MovzxInst = nullptr;

LocalMII++;
if (LocalMII == MIE)
return;
auto &Inst2 = *LocalMII;
switch (Inst2.getOpcode()) {
if (Inst2.getOpcode() == X86::MOVZX32rr8) {
const auto &MovzxDst = Inst2.getOperand(0);
const auto &MovzxSrc = Inst2.getOperand(1);
if (!MovzxDst.isReg() || !MovzxSrc.isReg() ||
MovzxSrc.getReg() != Op1.getReg())
return;
TestReg = MovzxDst.getReg();
MovzxInst = &Inst2;
LocalMII++;
if (LocalMII == MIE)
return;
}

auto &TestInst = *LocalMII;
switch (TestInst.getOpcode()) {
case X86::TEST8rr:
case X86::TEST16rr:
case X86::TEST32rr:
Expand All @@ -56,8 +72,10 @@ void X86CgPeephole::optimizeCmp(CgBasicBlock &MBB,
default:
return;
}
const auto &Op2 = Inst2.getOperand(0);
if (!Op2.isReg() || Op2.getReg() != Op1.getReg())
const auto &TestOp0 = TestInst.getOperand(0);
const auto &TestOp1 = TestInst.getOperand(1);
if (!TestOp0.isReg() || !TestOp1.isReg() || TestOp0.getReg() != TestReg ||
TestOp1.getReg() != TestReg)
return;

LocalMII++;
Expand All @@ -70,7 +88,10 @@ void X86CgPeephole::optimizeCmp(CgBasicBlock &MBB,
return; // TODO, other optimization, use opposite condition code

Inst1.eraseFromParent();
Inst2.eraseFromParent();
if (MovzxInst != nullptr) {
MovzxInst->eraseFromParent();
}
TestInst.eraseFromParent();
Inst3.getOperand(1).setImm(CC);
}
} // namespace COMPILER
Expand All @@ -85,4 +106,4 @@ void X86CgPeephole::optimizeBranchInBlockEnd(CgBasicBlock &MBB,
// remove the unconditional branch
MI.eraseFromParent();
}
}
}
Loading
Loading