Skip to content

Commit 2bbba8e

Browse files
feat: print works in soroban
Signed-off-by: salaheldinsoliman <[email protected]>
1 parent 06798cd commit 2bbba8e

File tree

5 files changed

+241
-34
lines changed

5 files changed

+241
-34
lines changed

src/codegen/dispatch/soroban.rs

+35-24
Original file line numberDiff line numberDiff line change
@@ -102,35 +102,46 @@ pub fn function_dispatch(
102102

103103
wrapper_cfg.add(&mut vartab, placeholder);
104104

105-
// set the msb 8 bits of the return value to 6, the return value is 64 bits.
106-
// FIXME: this assumes that the solidity function always returns one value.
107-
let shifted = Expression::ShiftLeft {
108-
loc: pt::Loc::Codegen,
109-
ty: Type::Uint(64),
110-
left: value[0].clone().into(),
111-
right: Expression::NumberLiteral {
105+
if value.len() == 1 {
106+
// set the msb 8 bits of the return value to 6, the return value is 64 bits.
107+
// FIXME: this assumes that the solidity function always returns one value.
108+
let shifted = Expression::ShiftLeft {
112109
loc: pt::Loc::Codegen,
113110
ty: Type::Uint(64),
114-
value: BigInt::from(8_u64),
115-
}
116-
.into(),
117-
};
111+
left: value[0].clone().into(),
112+
right: Expression::NumberLiteral {
113+
loc: pt::Loc::Codegen,
114+
ty: Type::Uint(64),
115+
value: BigInt::from(8_u64),
116+
}
117+
.into(),
118+
};
118119

119-
let tag = Expression::NumberLiteral {
120-
loc: pt::Loc::Codegen,
121-
ty: Type::Uint(64),
122-
value: BigInt::from(6_u64),
123-
};
120+
let tag = Expression::NumberLiteral {
121+
loc: pt::Loc::Codegen,
122+
ty: Type::Uint(64),
123+
value: BigInt::from(6_u64),
124+
};
124125

125-
let added = Expression::Add {
126-
loc: pt::Loc::Codegen,
127-
ty: Type::Uint(64),
128-
overflowing: false,
129-
left: shifted.into(),
130-
right: tag.into(),
131-
};
126+
let added = Expression::Add {
127+
loc: pt::Loc::Codegen,
128+
ty: Type::Uint(64),
129+
overflowing: false,
130+
left: shifted.into(),
131+
right: tag.into(),
132+
};
133+
134+
wrapper_cfg.add(&mut vartab, Instr::Return { value: vec![added] });
135+
} else {
136+
// return 2 as numberliteral
137+
let two = Expression::NumberLiteral {
138+
loc: pt::Loc::Codegen,
139+
ty: Type::Uint(64),
140+
value: BigInt::from(2_u64),
141+
};
132142

133-
wrapper_cfg.add(&mut vartab, Instr::Return { value: vec![added] });
143+
wrapper_cfg.add(&mut vartab, Instr::Return { value: vec![two] });
144+
}
134145

135146
vartab.finalize(ns, &mut wrapper_cfg);
136147
cfg.public = false;

src/emit/expression.rs

+52-2
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ use inkwell::{AddressSpace, IntPredicate};
1717
use num_bigint::Sign;
1818
use num_traits::ToPrimitive;
1919
use std::collections::HashMap;
20+
use std::ops::Deref;
21+
use inkwell::types::BasicTypeEnum;
2022

2123
/// The expression function recursively emits code for expressions. The BasicEnumValue it
2224
/// returns depends on the context; if it is simple integer, bool or bytes32 expression, the value
@@ -1198,6 +1200,7 @@ pub(super) fn expression<'a, T: TargetRuntime<'a> + ?Sized>(
11981200
expr,
11991201
..
12001202
} => {
1203+
println!("bytes cast");
12011204
let e = expression(target, bin, expr, vartab, function, ns).into_int_value();
12021205

12031206
let size = e.get_type().get_bit_width() / 8;
@@ -1538,7 +1541,12 @@ pub(super) fn expression<'a, T: TargetRuntime<'a> + ?Sized>(
15381541
initializer,
15391542
..
15401543
} => {
1541-
if matches!(ty, Type::Slice(_)) {
1544+
println!("alloc dynamic bytes");
1545+
println!("TYYY {:?}", ty);
1546+
println!("SIZE {:?}", size);
1547+
println!("INITIALIZER {:?}", initializer);
1548+
if matches!(ty, Type::Slice(_)) {
1549+
println!("ty is slice");
15421550
let init = initializer.as_ref().unwrap();
15431551

15441552
let data = bin.emit_global_string("const_string", init, true);
@@ -1553,7 +1561,49 @@ pub(super) fn expression<'a, T: TargetRuntime<'a> + ?Sized>(
15531561
.into(),
15541562
])
15551563
.into()
1556-
} else {
1564+
}
1565+
else if let Expression::NumberLiteral{loc, ty, value} = size.clone().deref() {
1566+
1567+
1568+
//matches!(size.clone().deref(), Expression::NumberLiteral{loc, ty: sesa, value}) {
1569+
1570+
println!("size is number literal");
1571+
println!("ty {:?}", ty);
1572+
1573+
let init = initializer.as_ref().unwrap();
1574+
1575+
let data = bin.emit_global_string("const_string", init, true);
1576+
1577+
1578+
let typee = BasicTypeEnum::StructType(
1579+
bin.context.struct_type(
1580+
&[
1581+
bin.llvm_type(ty, ns)
1582+
.ptr_type(AddressSpace::default())
1583+
.into(),
1584+
bin.context
1585+
.custom_width_int_type(ns.target.ptr_size().into())
1586+
.into(),
1587+
],
1588+
false,
1589+
),
1590+
).into_struct_type();
1591+
1592+
println!("typee {:?}", typee);
1593+
1594+
1595+
1596+
typee.const_named_struct(&[
1597+
data.into(),
1598+
bin.context
1599+
.custom_width_int_type(ns.target.ptr_size().into())
1600+
.const_int(init.len() as u64, false)
1601+
.into(),
1602+
])
1603+
.into()
1604+
1605+
}
1606+
else {
15571607
let elem = match ty {
15581608
Type::Slice(_) | Type::String | Type::DynamicBytes => Type::Bytes(1),
15591609
_ => ty.array_elem(),

src/emit/soroban/mod.rs

+12
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ use std::sync;
2222
const SOROBAN_ENV_INTERFACE_VERSION: u64 = 90194313216;
2323
pub const PUT_CONTRACT_DATA: &str = "l._";
2424
pub const GET_CONTRACT_DATA: &str = "l.1";
25+
pub const LOG_FROM_LINEAR_MEMORY: &str = "x._";
2526

2627
pub struct SorobanTarget;
2728

@@ -231,12 +232,23 @@ impl SorobanTarget {
231232
.i64_type()
232233
.fn_type(&[ty.into(), ty.into()], false);
233234

235+
let log_function_ty = binary
236+
.context
237+
.i64_type()
238+
.fn_type(&[ty.into(), ty.into(), ty.into(), ty.into()], false);
239+
234240
binary
235241
.module
236242
.add_function(PUT_CONTRACT_DATA, function_ty_1, Some(Linkage::External));
237243
binary
238244
.module
239245
.add_function(GET_CONTRACT_DATA, function_ty, Some(Linkage::External));
246+
247+
binary.module.add_function(
248+
LOG_FROM_LINEAR_MEMORY,
249+
log_function_ty,
250+
Some(Linkage::External),
251+
);
240252
}
241253

242254
fn emit_initializer(binary: &mut Binary, _ns: &ast::Namespace) {

src/emit/soroban/target.rs

+139-5
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,10 @@
22

33
use crate::codegen::cfg::HashTy;
44
use crate::codegen::Expression;
5-
use crate::emit::binary::Binary;
6-
use crate::emit::soroban::{SorobanTarget, GET_CONTRACT_DATA, PUT_CONTRACT_DATA};
5+
use crate::emit::binary::{self, Binary};
6+
use crate::emit::soroban::{
7+
SorobanTarget, GET_CONTRACT_DATA, LOG_FROM_LINEAR_MEMORY, PUT_CONTRACT_DATA,
8+
};
79
use crate::emit::ContractArgs;
810
use crate::emit::{TargetRuntime, Variable};
911
use crate::emit_context;
@@ -13,10 +15,11 @@ use crate::sema::ast::{Function, Namespace, Type};
1315

1416
use inkwell::types::{BasicTypeEnum, IntType};
1517
use inkwell::values::{
16-
ArrayValue, BasicMetadataValueEnum, BasicValue, BasicValueEnum, FunctionValue, IntValue,
17-
PointerValue,
18+
AnyValue, ArrayValue, AsValueRef, BasicMetadataValueEnum, BasicValue, BasicValueEnum,
19+
FunctionValue, IntValue, PointerValue,
1820
};
1921

22+
use inkwell::AddressSpace;
2023
use solang_parser::pt::Loc;
2124

2225
use std::collections::HashMap;
@@ -236,7 +239,138 @@ impl<'a> TargetRuntime<'a> for SorobanTarget {
236239

237240
/// Prints a string
238241
/// TODO: Implement this function, with a call to the `log` function in the Soroban runtime.
239-
fn print(&self, bin: &Binary, string: PointerValue, length: IntValue) {}
242+
fn print(&self, bin: &Binary, string: PointerValue, length: IntValue) {
243+
if string.is_const() && length.is_const() {
244+
println!("msg_pos: {:?}", string);
245+
println!("length: {:?}", length);
246+
247+
let msg_pos = bin
248+
.builder
249+
.build_ptr_to_int(string, bin.context.i64_type(), "msg_pos")
250+
.unwrap();
251+
let msg_pos = msg_pos.const_cast(bin.context.i64_type(), false);
252+
253+
println!("msg_pos extracted: {:?}", msg_pos);
254+
println!("=============================================================");
255+
256+
let length = length.const_cast(bin.context.i64_type(), false);
257+
258+
let eight = bin.context.i64_type().const_int(8, false);
259+
let four = bin.context.i64_type().const_int(4, false);
260+
let zero = bin.context.i64_type().const_int(0, false);
261+
let thirty_two = bin.context.i64_type().const_int(32, false);
262+
263+
// encode msg_pos and length
264+
let msg_pos_encoded = bin
265+
.builder
266+
.build_left_shift(msg_pos, thirty_two, "temp")
267+
.unwrap();
268+
let msg_pos_encoded = bin
269+
.builder
270+
.build_int_add(msg_pos_encoded, four, "msg_pos_encoded")
271+
.unwrap();
272+
273+
let length_encoded = bin
274+
.builder
275+
.build_left_shift(length, thirty_two, "temp")
276+
.unwrap();
277+
let length_encoded = bin
278+
.builder
279+
.build_int_add(length_encoded, four, "length_encoded")
280+
.unwrap();
281+
282+
let zero_encoded = bin.builder.build_left_shift(zero, eight, "temp").unwrap();
283+
284+
let eight_encoded = bin.builder.build_left_shift(eight, eight, "temp").unwrap();
285+
let eight_encoded = bin
286+
.builder
287+
.build_int_add(eight_encoded, four, "eight_encoded")
288+
.unwrap();
289+
290+
let call_res = bin
291+
.builder
292+
.build_call(
293+
bin.module.get_function(LOG_FROM_LINEAR_MEMORY).unwrap(),
294+
&[
295+
msg_pos_encoded.into(),
296+
length_encoded.into(),
297+
msg_pos_encoded.into(),
298+
four.into(),
299+
],
300+
"log",
301+
)
302+
.unwrap();
303+
} else {
304+
println!("in else: ");
305+
306+
println!("msg_pos: {:?}", string);
307+
println!("length: {:?}", length);
308+
309+
310+
/*println!("msg_pos: {:?}", string);
311+
println!("length: {:?}", length);
312+
313+
let msg_pos = bin.builder.build_ptr_to_int(string, bin.context.i64_type(), "msg_pos").unwrap();
314+
//let msg_pos = msg_pos.const_cast(bin.context.i64_type(), false);
315+
316+
317+
318+
println!("msg_pos extracted: {:?}", msg_pos);
319+
println!("=============================================================");
320+
321+
//let length = length.const_cast(bin.context.i64_type(), false);
322+
323+
324+
let eight = bin.context.i64_type().const_int(8, false);
325+
let four = bin.context.i64_type().const_int(4, false);
326+
let zero = bin.context.i64_type().const_int(0, false);
327+
let thirty_two = bin.context.i64_type().const_int(32, false);
328+
329+
// encode msg_pos and length
330+
let msg_pos_encoded = bin.builder.build_left_shift(msg_pos, thirty_two, "temp").unwrap();
331+
let msg_pos_encoded = bin.builder.build_int_add(msg_pos_encoded, four, "msg_pos_encoded").unwrap();
332+
333+
println!("CAN MSG ENCODE");
334+
335+
336+
337+
//let length = bin.builder.build_int_z_extend(length, bin.context.i64_type(), "extended").unwrap();
338+
339+
340+
let length_type = length.get_type();
341+
println!("LENGTH TYPE: {:?}", length_type);
342+
343+
//let length = bin.builder.build_int_z_extend(length, bin.context.i64_type(), "extended").unwrap();
344+
//let length = bin.builder.build_int_cast(length, bin.context.i64_type(), "extended").unwrap();
345+
346+
let length_encoded = bin.builder.build_left_shift(length, thirty_two, "temp").unwrap();
347+
let length_encoded = bin.builder.build_int_add(length_encoded, four, "length_encoded").unwrap();
348+
349+
println!("CAN LENGTH ENCODE");
350+
351+
352+
let zero_encoded = bin.builder.build_left_shift(zero, eight, "temp").unwrap();
353+
354+
355+
let eight_encoded = bin.builder.build_left_shift(eight, eight, "temp").unwrap();
356+
let eight_encoded = bin.builder.build_int_add(eight_encoded, four, "eight_encoded").unwrap();
357+
358+
359+
360+
361+
let call_res = bin.builder.build_call(
362+
bin.module.get_function(LOG_FROM_LINEAR_MEMORY).unwrap(),
363+
&[
364+
msg_pos_encoded.into(),
365+
length_encoded.into(),
366+
msg_pos_encoded.into(),
367+
four.into(),
368+
],
369+
"log",
370+
).unwrap();
371+
*/
372+
}
373+
}
240374

241375
/// Return success without any result
242376
fn return_empty_abi(&self, bin: &Binary) {

src/linker/soroban_wasm.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,7 @@ use wasm_encoder::{
1111
};
1212
use wasmparser::{Global, Import, Parser, Payload::*, SectionLimited, TypeRef};
1313

14-
use crate::emit::soroban::GET_CONTRACT_DATA;
15-
use crate::emit::soroban::PUT_CONTRACT_DATA;
14+
use crate::emit::soroban::{GET_CONTRACT_DATA, LOG_FROM_LINEAR_MEMORY, PUT_CONTRACT_DATA};
1615

1716
pub fn link(input: &[u8], name: &str) -> Vec<u8> {
1817
let dir = tempdir().expect("failed to create temp directory for linking");
@@ -82,7 +81,7 @@ fn generate_module(input: &[u8]) -> Vec<u8> {
8281
module.finish()
8382
}
8483

85-
/// Resolve all pallet contracts runtime imports
84+
/// Resolve all soroban contracts runtime imports
8685
fn generate_import_section(section: SectionLimited<Import>, module: &mut Module) {
8786
let mut imports = ImportSection::new();
8887
for import in section.into_iter().map(|import| import.unwrap()) {
@@ -98,6 +97,7 @@ fn generate_import_section(section: SectionLimited<Import>, module: &mut Module)
9897
};
9998
let module_name = match import.name {
10099
GET_CONTRACT_DATA | PUT_CONTRACT_DATA => "l",
100+
LOG_FROM_LINEAR_MEMORY => "x",
101101
_ => panic!("got func {:?}", import),
102102
};
103103
// parse the import name to all string after the the first dot

0 commit comments

Comments
 (0)