Skip to content

Commit 61d6c78

Browse files
committed
feat(slang): rewrite logical AND/OR as sol.if + i1 alloca
Replace scf.if + ui256 pattern with sol.if + i1 alloca for short-circuit evaluation of && and ||. AND allocates i1, stores false, evaluates LHS, and conditionally stores RHS in then-branch. OR stores true and conditionally stores RHS in else-branch.
1 parent c96f4b4 commit 61d6c78

File tree

1 file changed

+44
-27
lines changed
  • solx-slang/src/ast/contract/function/expression

1 file changed

+44
-27
lines changed

solx-slang/src/ast/contract/function/expression/logical.rs

Lines changed: 44 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ use crate::ast::contract::function::expression::ExpressionEmitter;
1313
use crate::ast::contract::function::expression::operator::Operator;
1414

1515
impl<'state, 'context, 'block> ExpressionEmitter<'state, 'context, 'block> {
16-
/// Emits a `sol.cmp` comparison, cast to `ui256` via `sol.cast`.
16+
/// Emits a `sol.cmp` comparison.
1717
///
1818
/// # Errors
1919
///
@@ -27,7 +27,6 @@ impl<'state, 'context, 'block> ExpressionEmitter<'state, 'context, 'block> {
2727
) -> anyhow::Result<(Value<'context, 'block>, BlockRef<'context, 'block>)> {
2828
let (lhs, block) = self.emit_value(left, block)?;
2929
let (rhs, block) = self.emit_value(right, block)?;
30-
// Cast both operands to a common type for comparison.
3130
let common_type = if lhs.r#type() == rhs.r#type() {
3231
lhs.r#type()
3332
} else {
@@ -37,14 +36,13 @@ impl<'state, 'context, 'block> ExpressionEmitter<'state, 'context, 'block> {
3736
let rhs = self.state.builder.emit_sol_cast(rhs, common_type, &block);
3837
let predicate = Operator::from_str(operator)?.cmp_predicate();
3938
let comparison = self.state.builder.emit_sol_cmp(lhs, rhs, predicate, &block);
40-
let ui256 = self.state.builder.get_type(solx_mlir::Builder::UI256);
41-
let value = self.state.builder.emit_sol_cast(comparison, ui256, &block);
42-
Ok((value, block))
39+
Ok((comparison, block))
4340
}
4441

45-
/// Emits short-circuit `&&` using value-producing `scf.if`.
42+
/// Emits short-circuit `&&` using `sol.if` with an `i1` alloca.
4643
///
47-
/// Result is always a canonical boolean (0 or 1).
44+
/// Matches solc's pattern: allocate a boolean result variable, default to
45+
/// `false`, and only evaluate the RHS when the LHS is true.
4846
///
4947
/// # Errors
5048
///
@@ -58,28 +56,39 @@ impl<'state, 'context, 'block> ExpressionEmitter<'state, 'context, 'block> {
5856
let (lhs, block) = self.emit_value(left, block)?;
5957
let lhs_bool = self.emit_is_nonzero(lhs, &block);
6058

61-
let ui256 = self.state.builder.get_type(solx_mlir::Builder::UI256);
62-
let (then_block, else_block, result) =
63-
self.state.builder.emit_scf_if(lhs_bool, ui256, &block)?;
59+
let i1_type = self.state.builder.get_type(solx_mlir::Builder::I1);
60+
let result_ptr = self.state.builder.emit_sol_alloca(i1_type, &block);
61+
// TODO: solc uses `arith.constant false` here; consider switching to
62+
// arith dialect for i1 constants to match solc output exactly.
63+
let false_val = self.state.builder.emit_sol_constant(0, i1_type, &block);
64+
self.state
65+
.builder
66+
.emit_sol_store(false_val, result_ptr, &block);
6467

65-
// Then: LHS was true — evaluate RHS and yield normalized result.
68+
let (then_block, else_block) = self.state.builder.emit_sol_if(lhs_bool, &block);
69+
70+
// Then: LHS was true — evaluate RHS and store result.
6671
let (rhs, then_end) = self.emit_value(right, then_block)?;
6772
let rhs_bool = self.emit_is_nonzero(rhs, &then_end);
68-
let rhs_normalized = self.state.builder.emit_sol_cast(rhs_bool, ui256, &then_end);
6973
self.state
7074
.builder
71-
.emit_scf_yield(&[rhs_normalized], &then_end);
75+
.emit_sol_store(rhs_bool, result_ptr, &then_end);
76+
self.state.builder.emit_sol_yield(&then_end);
7277

73-
// Else: LHS was false — yield 0.
74-
let zero = self.state.builder.emit_sol_constant(0, ui256, &else_block);
75-
self.state.builder.emit_scf_yield(&[zero], &else_block);
78+
// Else: LHS was false — result stays false.
79+
self.state.builder.emit_sol_yield(&else_block);
7680

81+
let result = self
82+
.state
83+
.builder
84+
.emit_sol_load(result_ptr, i1_type, &block)?;
7785
Ok((result, block))
7886
}
7987

80-
/// Emits short-circuit `||` using value-producing `scf.if`.
88+
/// Emits short-circuit `||` using `sol.if` with an `i1` alloca.
8189
///
82-
/// Result is always a canonical boolean (0 or 1).
90+
/// Matches solc's pattern: allocate a boolean result variable, default to
91+
/// `true`, and only evaluate the RHS when the LHS is false.
8392
///
8493
/// # Errors
8594
///
@@ -93,22 +102,30 @@ impl<'state, 'context, 'block> ExpressionEmitter<'state, 'context, 'block> {
93102
let (lhs, block) = self.emit_value(left, block)?;
94103
let lhs_bool = self.emit_is_nonzero(lhs, &block);
95104

96-
let ui256 = self.state.builder.get_type(solx_mlir::Builder::UI256);
97-
let (then_block, else_block, result) =
98-
self.state.builder.emit_scf_if(lhs_bool, ui256, &block)?;
105+
let i1_type = self.state.builder.get_type(solx_mlir::Builder::I1);
106+
let result_ptr = self.state.builder.emit_sol_alloca(i1_type, &block);
107+
let true_val = self.state.builder.emit_sol_constant(1, i1_type, &block);
108+
self.state
109+
.builder
110+
.emit_sol_store(true_val, result_ptr, &block);
99111

100-
// Then: LHS was true — yield 1.
101-
let one = self.state.builder.emit_sol_constant(1, ui256, &then_block);
102-
self.state.builder.emit_scf_yield(&[one], &then_block);
112+
let (then_block, else_block) = self.state.builder.emit_sol_if(lhs_bool, &block);
103113

104-
// Else: LHS was false — evaluate RHS and yield normalized result.
114+
// Then: LHS was true — result stays true.
115+
self.state.builder.emit_sol_yield(&then_block);
116+
117+
// Else: LHS was false — evaluate RHS and store result.
105118
let (rhs, else_end) = self.emit_value(right, else_block)?;
106119
let rhs_bool = self.emit_is_nonzero(rhs, &else_end);
107-
let rhs_normalized = self.state.builder.emit_sol_cast(rhs_bool, ui256, &else_end);
108120
self.state
109121
.builder
110-
.emit_scf_yield(&[rhs_normalized], &else_end);
122+
.emit_sol_store(rhs_bool, result_ptr, &else_end);
123+
self.state.builder.emit_sol_yield(&else_end);
111124

125+
let result = self
126+
.state
127+
.builder
128+
.emit_sol_load(result_ptr, i1_type, &block)?;
112129
Ok((result, block))
113130
}
114131
}

0 commit comments

Comments
 (0)