Skip to content

Commit 69d5af4

Browse files
committed
[mlir] Support try with new-expression calls
1 parent 73437d7 commit 69d5af4

4 files changed

Lines changed: 656 additions & 372 deletions

File tree

libsolidity/codegen/mlir/SolidityToMLIR.cpp

Lines changed: 31 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1968,9 +1968,12 @@ SolidityToMLIRPass::genExprs(FunctionCall const &call) {
19681968

19691969
// Keep the creation result typed as the FE return contract type so
19701970
// payability is preserved (contract vs contract<payable>).
1971-
resVals.push_back(b.create<mlir::sol::NewOp>(
1971+
auto newOp = b.create<mlir::sol::NewOp>(
19721972
loc, getType(calleeTy->returnParameterTypes().front()), objName, value,
1973-
salt, args));
1973+
salt, args);
1974+
if (call.annotation().tryCall)
1975+
newOp.setTryCall(true);
1976+
resVals.push_back(newOp.getResult());
19741977
return resVals;
19751978
}
19761979

@@ -2712,14 +2715,35 @@ void SolidityToMLIRPass::lower(ForStatement const &forStmt) {
27122715
void SolidityToMLIRPass::lower(TryStatement const &tryStmt) {
27132716
mlir::Location loc = getLoc(tryStmt);
27142717

2715-
// TODO: sol.new
2716-
// `try` is the one frontend-level construct that needs the otherwise-hidden
2717-
// status of a high-level external call. Lower it through `genExternalCall`
2718-
// which exposes both status and results explicitly.
27192718
auto const *callExpr =
27202719
dynamic_cast<FunctionCall const *>(&tryStmt.externalCall());
27212720
assert(callExpr && "Expected FunctionCall expression in TryStatement");
2722-
auto [status, results] = genExternalCall(*callExpr);
2721+
auto const *calleeTy = dynamic_cast<FunctionType const *>(
2722+
callExpr->expression().annotation().type);
2723+
assert(calleeTy);
2724+
2725+
mlir::Value status;
2726+
mlir::SmallVector<mlir::Value> results;
2727+
if (calleeTy->kind() == FunctionType::Kind::Creation) {
2728+
// genExprs propagates tryCall onto the sol.new (suppressing the
2729+
// forwarding-revert); status is `addr != 0`
2730+
results.append(genExprs(*callExpr));
2731+
assert(results.size() == 1 && "new returns exactly one contract value");
2732+
auto addrTy =
2733+
mlir::sol::AddressType::get(b.getContext(), /*payable=*/false);
2734+
auto ui160Ty = b.getIntegerType(160, /*isSigned=*/false);
2735+
mlir::Value addr =
2736+
b.create<mlir::sol::AddressCastOp>(loc, addrTy, results.front());
2737+
mlir::Value addrUi = b.create<mlir::sol::AddressCastOp>(loc, ui160Ty, addr);
2738+
mlir::Value zero = genUnsignedConst(0, /*numBits=*/160, loc);
2739+
status = b.create<mlir::sol::CmpOp>(loc, mlir::sol::CmpPredicate::ne,
2740+
addrUi, zero);
2741+
} else {
2742+
auto extResult = genExternalCall(*callExpr);
2743+
status = extResult.status;
2744+
results = std::move(extResult.results);
2745+
}
2746+
27232747
auto tryOp = b.create<mlir::sol::TryOp>(loc, status);
27242748

27252749
// Lower success clause.

0 commit comments

Comments
 (0)