-
Notifications
You must be signed in to change notification settings - Fork 171
WASM_X64: Support Data Segment #1585
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
c51cbb5
to
acf01fb
Compare
Example: (lp) lpython$ cat integration_tests/test_complex_01.py
from ltypes import i32, i64, f32, f64, c32, c64
def test_real_imag():
x: c64
x = c64(2) + 3j
a: f64
b: f64
eps: f64
eps = 1e-12
a = x.real
b = x.imag
assert abs(a - 2.0) <= eps
assert abs(b - 3.0) <= eps
print(x)
def test_complex():
x: c64
x = complex(4.5, 6.7)
eps: f64
eps = 1e-12
assert abs(x.real - 4.5) <= eps
assert abs(x.imag - 6.7) <= eps
x = complex(-4, 2)
assert abs(x.real - (-4.0)) <= eps
assert abs(x.imag - 2.0) <= eps
x = complex(4, 7.89)
assert abs(x.real - 4.0) <= eps
assert abs(x.imag - 7.89) <= eps
x = complex(5.6, 0)
assert abs(x.real - 5.6) <= eps
assert abs(x.imag - 0.0) <= eps
a: f64
a = 534.6
x = complex(a, -a) # (f64, f64)
assert abs(x.real - 534.60000000000002274) <= eps
assert abs(x.imag - (-534.60000000000002274)) <= eps
a2: f32
a2 = -f32(423.5430806348152437)
a3: f32
a3 = f32(34.5)
x2: c32
x2 = c32(complex(a2, a3)) # (f32, f32)
assert f64(abs(x2.imag - f32(34.5))) <= eps
i1: i32
i1 = -5
i2: i64
i2 = -i64(6)
x = complex(a3, a) # (f32, f64)
x = complex(a, a3) # (f64, f32)
x = complex(i1, i2) # (i32, i64)
x = complex(i1, -i1) # (i32, i32)
x = complex(-i2, -i2) # (i64, i64)
x = complex(i2, -i1) # (i64, i32)
print(x)
def test_complex_unary_minus():
c: c32
c = c32(complex(3, 4.5))
_c: c32
_c = -c
assert abs(f64(_c.real) - (-3.0)) <= 1e-12
assert abs(f64(_c.imag) - (-4.5)) <= 1e-12
_c = c32(complex(5, -78))
_c = -_c
assert abs(f64(_c.real) - (-5.0)) <= 1e-12
assert abs(f64(_c.imag) - 78.0) <= 1e-12
c2: c64
c2 = complex(-4.5, -7.8)
c2 = -c2
assert abs(c2.real - 4.5) <= 1e-12
assert abs(c2.imag - 7.8) <= 1e-12
c2 = c64(3) + 4j
c2 = -c2
assert abs(c2.real - (-3.0)) <= 1e-12
assert abs(c2.imag - (-4.0)) <= 1e-12
print(c, _c, c2)
def test_complex_not():
c: c32
c = c32(complex(4, 5))
b: bool
b = not c
assert not b
c2: c64
c2 = complex(0, 0)
b = not c2
assert b
print(c,c2, b)
def check():
test_real_imag()
test_complex()
test_complex_unary_minus()
test_complex_not()
check() ASM Binary Format:
ASM Text Format: (wasm_asm) lpython$ nasm -fbin main.asm && chmod +x main
(wasm_asm) lpython$ ./main
(2.000000000,3.000000000)
(-6.000000000,5.000000000)
(3.000000000,4.50000000) (-5.000000000,78.000000000) (-3.000000000,-4.000000000)
(4.000000000,5.000000000) (0.000000000,0.000000000) 1
(wasm_asm) lpython$ readelf -h main
ELF Header:
Magic: 7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00
Class: ELF64
Data: 2's complement, little endian
Version: 1 (current)
OS/ABI: UNIX - System V
ABI Version: 0
Type: EXEC (Executable file)
Machine: Advanced Micro Devices X86-64
Version: 0x1
Entry point address: 0x804cba9
Start of program headers: 64 (bytes into file)
Start of section headers: 0 (bytes into file)
Flags: 0x0
Size of this header: 64 (bytes)
Size of program headers: 56 (bytes)
Number of program headers: 3
Size of section headers: 0 (bytes)
Number of section headers: 0
Section header string table index: 0
(wasm_asm) lpython$ readelf -l main
Elf file type is EXEC (Executable file)
Entry point 0x804cba9
There are 3 program headers, starting at offset 64
Program Headers:
Type Offset VirtAddr PhysAddr
FileSiz MemSiz Flags Align
LOAD 0x0000000000000000 0x0000000008048000 0x0000000008048000
0x0000000000001000 0x0000000000001000 R 0x1000
LOAD 0x0000000000001000 0x0000000008049000 0x0000000008049000
0x00000000000047c9 0x00000000000047c9 R E 0x1000
LOAD 0x00000000000063a4 0x000000000804e3a4 0x000000000804e3a4
0x0000000000000100 0x0000000000000100 RW 0x1000
(wasm_asm) lpython$ |
acf01fb
to
f22efa5
Compare
src/libasr/codegen/x86_assembler.h
Outdated
for (size_t i = 0; i < padding_size; i++) { | ||
m_code.push_back(m_al, 0); | ||
} | ||
EMIT("times " + std::to_string(padding_size) + " db 0"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Line 473: I think the padding_size
computed here is valid only for the binary that we generate. For assembly text format, while encoding the text_segment
, since nasm
can encode instructions using different number of bytes than our encoding, the padding size required by nasm
binary could be different from that of our binary.
I am looking into the possibilities of computing the padding size dynamically in assembly text format.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For NASM use the $ and $$ trick that we use to compute the size of the binary for the header.
f22efa5
to
ab72766
Compare
ab72766
to
1b62e6b
Compare
This is ready. Please review and share feedback. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this looks great!
Should we add some tests for this new feature?
Sure, we can add tests. I think the test (lp) lpython$ lpython integration_tests/test_complex_01.py --backend wasm_x64 -o tmp > main.asm
(lp) lpython$ ./tmp
(2.000000000,3.000000000)
(-6.000000000,5.000000000)
(3.000000000,4.50000000) (-5.000000000,78.000000000) (-3.000000000,-4.000000000)
(4.000000000,5.000000000) (0.000000000,0.000000000) 1
(lp) lpython$
(wasm_asm) lpython$ nasm -fbin main.asm && chmod +x main
(wasm_asm) lpython$ ./main
(2.000000000,3.000000000)
(-6.000000000,5.000000000)
(3.000000000,4.50000000) (-5.000000000,78.000000000) (-3.000000000,-4.000000000)
(4.000000000,5.000000000) (0.000000000,0.000000000) 1
(wasm_asm) lpython$ (In the above example, I added some print statements to the test PS: The |
As this PR seems approved, I am merging this. I will work on further changes/suggestions (if any) in another PR. |
I see, perfect! I don't see any global variables in https://github.com/lcompilers/lpython/blob/1dc74c6200cac7c983f3ae15d3dce25f37c55f3f/integration_tests/test_complex_01.py, which line is a global variable? What capability does this new RW data segment allows us to do? One is that the code segment becomes read-only, which is good. The other might be that now we should be able to resize it, thus allow arbitrary length heap allocation. Anything else? |
lpython/src/libasr/codegen/asr_to_wasm.cpp Lines 74 to 79 in 1dc74c6
We currently use global variable for temporary operations like stack manipulation (for example: to swap the top and top-second stack elements). (The For example, the global get/set operations are used here lpython/src/libasr/codegen/asr_to_wasm.cpp Lines 1699 to 1710 in 1dc74c6
and here lpython/src/libasr/codegen/asr_to_wasm.cpp Lines 2615 to 2621 in 1dc74c6
The |
I think it can allow us compile-time memory allocation (For example: we can have a label and can emit Using the above approach, I think we can now support arrays by initializing memory for them in the data segment. For dynamic/runtime memory allocation (which could be needed for allocatable arrays), I think we should try to see/use system calls for memory allocation. |
I see, perfect, thanks for the explanation! |
towards #1539