Skip to content
Draft
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
3 changes: 3 additions & 0 deletions src/compiler/cgir/lowering.h
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,9 @@ template <typename T> class CgLowering {
case MInstruction::ADC:
ResultReg = SELF.lowerAdcExpr(llvm::cast<AdcInstruction>(Inst));
break;
case MInstruction::SBB:
ResultReg = SELF.lowerSbbExpr(llvm::cast<SbbInstruction>(Inst));
break;
case MInstruction::CMP:
ResultReg = SELF.lowerCmpExpr(llvm::cast<CmpInstruction>(Inst));
break;
Expand Down
7 changes: 2 additions & 5 deletions src/compiler/evm_frontend/evm_analyzer.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,11 +30,11 @@ namespace COMPILER {
// clang-format off
static constexpr uint32_t MIR_OPCODE_WEIGHT[256] = {
// 0x00 STOP ADD MUL SUB DIV SDIV MOD SMOD
5, 12, 80, 20, 5, 5, 5, 5,
5, 12, 80, 12, 5, 5, 5, 5,
// 0x08 ADDMOD MULMOD EXP SIGNEXT (0x0c-0x0f undefined)
5, 5, 5, 20, 2, 2, 2, 2,
// 0x10 LT GT SLT SGT EQ ISZERO AND OR
12, 12, 12, 12, 12, 8, 8, 8,
8, 8, 12, 12, 12, 8, 8, 8,
// 0x18 XOR NOT BYTE SHL SHR SAR CLZ (0x1f)
8, 8, 8, 15, 15, 15, 8, 2,
// 0x20 KECCAK256 (0x21-0x2f undefined)
Expand Down Expand Up @@ -79,9 +79,6 @@ inline bool isRAExpensiveOpcode(uint8_t Op) {
switch (Op) {
case 0x02: // MUL — ~50-60 MIR, heavy partial-product fan-out
case 0x0b: // SIGNEXTEND — ~21 Selects, two dependency chain loops
case 0x1b: // SHL — ~92 Selects, nested J,K loops
case 0x1c: // SHR — ~96 Selects, nested J,K loops
case 0x1d: // SAR — ~52 Selects, sign-extended variant
return true;
default:
return false;
Expand Down
742 changes: 360 additions & 382 deletions src/compiler/evm_frontend/evm_mir_compiler.cpp

Large diffs are not rendered by default.

109 changes: 87 additions & 22 deletions src/compiler/evm_frontend/evm_mir_compiler.h
Original file line number Diff line number Diff line change
Expand Up @@ -224,6 +224,33 @@ class EVMMirBuilder final {

template <BinaryOperator Operator>
Operand handleBinaryArithmetic(const Operand &LHSOp, const Operand &RHSOp) {
// Constant folding: if both operands are compile-time constants, compute
// the result directly and return a constant Operand.
if (LHSOp.isConstant() && RHSOp.isConstant()) {
intx::uint256 L = u256FromLimbs(LHSOp.getConstValue());
intx::uint256 R = u256FromLimbs(RHSOp.getConstValue());
intx::uint256 Res;
if constexpr (Operator == BinaryOperator::BO_ADD)
Res = L + R;
else if constexpr (Operator == BinaryOperator::BO_SUB)
Res = L - R;
else
ZEN_ASSERT_TODO();
return createU256ConstOperand(Res);
}

// Identity / annihilation shortcuts for single constant operand.
if constexpr (Operator == BinaryOperator::BO_ADD) {
if (LHSOp.isConstant() && isU256Zero(LHSOp.getConstValue()))
return RHSOp;
if (RHSOp.isConstant() && isU256Zero(RHSOp.getConstValue()))
return LHSOp;
}
if constexpr (Operator == BinaryOperator::BO_SUB) {
if (RHSOp.isConstant() && isU256Zero(RHSOp.getConstValue()))
return LHSOp;
}

U256Inst Result = {};
U256Inst LHS = extractU256Operand(LHSOp);
U256Inst RHS = extractU256Operand(RHSOp);
Expand Down Expand Up @@ -266,31 +293,29 @@ class EVMMirBuilder final {
}
}
} else if constexpr (Operator == BinaryOperator::BO_SUB) {
// Borrow placeholder (not consumed by x86 lowering; the hardware CF
// from the preceding SUB/SBB is used directly, mirroring the ADC
// carry chain pattern).
MInstruction *Borrow = createIntConstInstruction(MirI64Type, 0);

// Pre-materialize all operand components into variables before the
// SUB/SBB borrow chain. This prevents lazy expression lowering from
// emitting flag-clobbering instructions between the SUB and SBB
// instructions that form the borrow chain.
for (size_t I = 0; I < EVM_ELEMENTS_COUNT; ++I) {
// Sub: LHS[I] - RHS[I] - Borrow
MInstruction *Diff1 = createInstruction<BinaryInstruction>(
false, OP_sub, MirI64Type, LHS[I], RHS[I]);
MInstruction *Diff2 = createInstruction<BinaryInstruction>(
false, OP_sub, MirI64Type, Diff1, Borrow);

Result[I] = protectUnsafeValue(Diff2, MirI64Type);

// (LHS[I] < RHS[I]) || (Diff1 < Borrow)
if (I < EVM_ELEMENTS_COUNT - 1) {
auto LTPredicate = CmpInstruction::Predicate::ICMP_ULT;
MInstruction *Borrow1 = createInstruction<CmpInstruction>(
false, LTPredicate, &Ctx.I64Type, LHS[I], RHS[I]);
MInstruction *Borrow2 = createInstruction<CmpInstruction>(
false, LTPredicate, &Ctx.I64Type, Diff1, Borrow);
// NOLINTBEGIN(readability-identifier-naming)
MInstruction *Borrow1_64 = zeroExtendToI64(Borrow1);
MInstruction *Borrow2_64 = zeroExtendToI64(Borrow2);
// NOLINTEND(readability-identifier-naming)

Borrow = createInstruction<BinaryInstruction>(
false, OP_or, MirI64Type, Borrow1_64, Borrow2_64);
LHS[I] = protectUnsafeValue(LHS[I], MirI64Type);
RHS[I] = protectUnsafeValue(RHS[I], MirI64Type);
}

for (size_t I = 0; I < EVM_ELEMENTS_COUNT; ++I) {
if (I == 0) {
MInstruction *LocalResult = createInstruction<BinaryInstruction>(
false, OP_sub, MirI64Type, LHS[I], RHS[I]);
Result[I] = protectUnsafeValue(LocalResult, MirI64Type);
} else {
MInstruction *LocalResult = createInstruction<SbbInstruction>(
false, MirI64Type, LHS[I], RHS[I], Borrow);
Result[I] = protectUnsafeValue(LocalResult, MirI64Type);
}
}
} else {
Expand All @@ -317,6 +342,34 @@ class EVMMirBuilder final {
// EVM bitwise opcode: and, or, xor
template <BinaryOperator Operator>
Operand handleBitwiseOp(const Operand &LHSOp, const Operand &RHSOp) {
if (LHSOp.isConstant() && RHSOp.isConstant()) {
intx::uint256 L = u256FromLimbs(LHSOp.getConstValue());
intx::uint256 R = u256FromLimbs(RHSOp.getConstValue());
intx::uint256 Res;
if constexpr (Operator == BinaryOperator::BO_AND)
Res = L & R;
else if constexpr (Operator == BinaryOperator::BO_OR)
Res = L | R;
else if constexpr (Operator == BinaryOperator::BO_XOR)
Res = L ^ R;
else
ZEN_ASSERT_TODO();
return createU256ConstOperand(Res);
}
// AND with 0 -> 0, OR/XOR with 0 -> identity
if constexpr (Operator == BinaryOperator::BO_AND) {
if ((LHSOp.isConstant() && isU256Zero(LHSOp.getConstValue())) ||
(RHSOp.isConstant() && isU256Zero(RHSOp.getConstValue())))
return createU256ConstOperand(intx::uint256{0});
}
if constexpr (Operator == BinaryOperator::BO_OR ||
Operator == BinaryOperator::BO_XOR) {
if (LHSOp.isConstant() && isU256Zero(LHSOp.getConstValue()))
return RHSOp;
if (RHSOp.isConstant() && isU256Zero(RHSOp.getConstValue()))
return LHSOp;
}

U256Inst Result = {};
U256Inst LHS = extractU256Operand(LHSOp);
U256Inst RHS = extractU256Operand(RHSOp);
Expand Down Expand Up @@ -482,6 +535,18 @@ class EVMMirBuilder final {
MInstruction *getInstanceStackPeekInt(int32_t IndexFromTop);
void drainGas();

static intx::uint256 u256FromLimbs(const U256Value &V) {
intx::uint256 R = 0;
for (int I = EVM_ELEMENTS_COUNT - 1; I >= 0; --I) {
R = (R << 64) | intx::uint256{V[static_cast<size_t>(I)]};
}
return R;
}

static bool isU256Zero(const U256Value &V) {
return (V[0] | V[1] | V[2] | V[3]) == 0;
}

// Create a full U256 operand from intx::uint256 value
Operand createU256ConstOperand(const intx::uint256 &V);

Expand Down
1 change: 1 addition & 0 deletions src/compiler/mir/instruction.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ class MInstruction : public NonCopyable {
UNARY,
BINARY,
ADC,
SBB,
CMP,
CONVERSION,
SELECT,
Expand Down
5 changes: 5 additions & 0 deletions src/compiler/mir/instructions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,11 @@ void MInstruction::print(llvm::raw_ostream &OS) const {
<< getOperand<2>() << ')';
break;
}
case SBB: {
OS << "sbb (" << getOperand<0>() << ", " << getOperand<1>() << ", "
<< getOperand<2>() << ')';
break;
}
case BR: {
auto *br = llvm::cast<BrInstruction>(this);
OS << "br @" << br->getTargetBlock()->getIdx() << '\n';
Expand Down
23 changes: 23 additions & 0 deletions src/compiler/mir/instructions.h
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,29 @@ class AdcInstruction : public FixedOperandInstruction<3> {
}
};

class SbbInstruction : public FixedOperandInstruction<3> {
public:
template <typename... Arguments>
static SbbInstruction *create(Arguments &&...Args) {
return FixedOperandInstruction::create<SbbInstruction>(
std::forward<Arguments>(Args)...);
}

static bool classof(const MInstruction *Inst) {
return Inst->getOpcode() == OP_sbb;
}

private:
friend class FixedOperandInstruction;
SbbInstruction(MType *Type, MInstruction *Operand1, MInstruction *Operand2,
MInstruction *Borrow)
: FixedOperandInstruction(MInstruction::SBB, OP_sbb, 3, Type) {
setOperand<0>(Operand1);
setOperand<1>(Operand2);
setOperand<2>(Borrow);
}
};

class UnaryInstruction : public FixedOperandInstruction<1> {
public:
template <typename... Arguments>
Expand Down
1 change: 1 addition & 0 deletions src/compiler/mir/opcodes.def
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ OPCODE(dread) // OP_OTHER_EXPR_START
OPCODE(const)
OPCODE(cmp)
OPCODE(adc)
OPCODE(sbb)
OPCODE(select)
OPCODE(load)
OPCODE(wasm_sadd128_overflow)
Expand Down
4 changes: 4 additions & 0 deletions src/compiler/mir/pass/visitor.h
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,9 @@ class MVisitor {
case MInstruction::ADC:
visitAdcInstruction(static_cast<AdcInstruction &>(I));
break;
case MInstruction::SBB:
visitSbbInstruction(static_cast<SbbInstruction &>(I));
break;
case MInstruction::OVERFLOW_I128_BINARY:
visitWasmOverflowI128BinaryInstruction(
static_cast<WasmOverflowI128BinaryInstruction &>(I));
Expand Down Expand Up @@ -132,6 +135,7 @@ class MVisitor {
virtual void visitBinaryInstruction(BinaryInstruction &I) { VISIT_OPERAND_2 }
virtual void visitCmpInstruction(CmpInstruction &I) { VISIT_OPERAND_2 }
virtual void visitAdcInstruction(AdcInstruction &I) { VISIT_OPERAND_3 }
virtual void visitSbbInstruction(SbbInstruction &I) { VISIT_OPERAND_3 }
virtual void visitSelectInstruction(SelectInstruction &I) { VISIT_OPERAND_3 }
virtual void visitDassignInstruction(DassignInstruction &I) {
VISIT_OPERAND_1
Expand Down
34 changes: 34 additions & 0 deletions src/compiler/target/x86/x86lowering.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -942,6 +942,40 @@ CgRegister X86CgLowering::lowerAdcExpr(const AdcInstruction &Inst) {
}
}

CgRegister X86CgLowering::lowerSbbExpr(const SbbInstruction &Inst) {
const MInstruction *LHS = Inst.getOperand<0>();
const MInstruction *RHS = Inst.getOperand<1>();

MVT VT = getMVT(*Inst.getType());
ZEN_ASSERT(VT.isInteger());
const TargetRegisterClass *RC = TLI.getRegClassFor(VT);

CgRegister LHSReg = lowerExpr(*LHS);
CgRegister RHSReg = lowerExpr(*RHS);

CgRegister DiffReg = fastEmitCopy(RC, LHSReg);
switch (VT.SimpleTy) {
case MVT::i8:
MF->createCgInstruction(*CurBB, TII.get(X86::SBB8rr), DiffReg, RHSReg,
DiffReg);
return DiffReg;
case MVT::i16:
MF->createCgInstruction(*CurBB, TII.get(X86::SBB16rr), DiffReg, RHSReg,
DiffReg);
return DiffReg;
case MVT::i32:
MF->createCgInstruction(*CurBB, TII.get(X86::SBB32rr), DiffReg, RHSReg,
DiffReg);
return DiffReg;
case MVT::i64:
MF->createCgInstruction(*CurBB, TII.get(X86::SBB64rr), DiffReg, RHSReg,
DiffReg);
return DiffReg;
default:
throw getError(ErrorCode::NoMatchedInstruction);
}
}

CgRegister
X86CgLowering::lowerEvmUmul128Expr(const EvmUmul128Instruction &Inst) {
// 64x64->128 bit multiplication using x86 MUL64r
Expand Down
1 change: 1 addition & 0 deletions src/compiler/target/x86/x86lowering.h
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ class X86CgLowering : public CgLowering<X86CgLowering> {
CgRegister lowerEvmUmul128Expr(const EvmUmul128Instruction &Inst);
CgRegister lowerEvmUmul128HiExpr(const EvmUmul128HiInstruction &Inst);
CgRegister lowerAdcExpr(const AdcInstruction &Inst);
CgRegister lowerSbbExpr(const SbbInstruction &Inst);

// ==================== Memory Instructions ====================

Expand Down
Loading