nac3artiq: supports running multiple kernels #124

Merged
sb10q merged 2 commits from fix_91 into master 2021-12-05 13:10:55 +08:00
Collaborator

Supports #91. This way of handling is actually quite efficient as we keep the parsed AST. We have to perform type inference again as python variables can change between kernel invocations, and their type can change. Example:

from min_artiq import *

test = 100.0

@nac3
class Demo:
    core: KernelInvariant[Core]
    led0: KernelInvariant[TTLOut]

    def __init__(self):
        self.core = Core()
        self.led0 = TTLOut(self.core, 18)

    @kernel
    def run(self):
        self.core.reset()
        self.led0.pulse(float(test)*ms)

if __name__ == "__main__":
    Demo().run()
    test = 200
    Demo().run()

Output:

; ModuleID = 'main'
source_filename = "main"

@"139905343409264" = global { double } { double 1.000000e-09 }
@"139905343409648" = global { { double }*, i32, i32 } { { double }* @"139905343409264", i32 18, i32 4608 }
@"139905343409888" = local_unnamed_addr global { { double }*, { { double }*, i32, i32 }* } { { double }* @"139905343409264", { { double }*, i32, i32 }* @"139905343409648" }
@now = external local_unnamed_addr global i64

declare void @rtio_output(i32 %0, i32 %1) local_unnamed_addr

define void @__modinit__() local_unnamed_addr {
init:
  tail call void @rtio_output(i32 4608, i32 1)
  %now_hi.i.i.i = load i32, i32* bitcast (i64* @now to i32*), align 4
  %now_lo.i.i.i = load i32, i32* bitcast (i64* getelementptr inbounds (i64, i64* @now, i64 1) to i32*), align 4
  %now_zext_hi.i.i.i = zext i32 %now_hi.i.i.i to i64
  %now_shifted_zext_hi.i.i.i = shl nuw i64 %now_zext_hi.i.i.i, 32
  %now_zext_lo.i.i.i = zext i32 %now_lo.i.i.i to i64
  %now_or.i.i.i = or i64 %now_shifted_zext_hi.i.i.i, %now_zext_lo.i.i.i
  %now_add.i.i.i = add i64 %now_or.i.i.i, 100000000
  %now_lshr.i.i.i = lshr i64 %now_add.i.i.i, 32
  %now_trunc.i.i.i = trunc i64 %now_lshr.i.i.i to i32
  %now_trunc1.i.i.i = trunc i64 %now_add.i.i.i to i32
  store atomic i32 %now_trunc.i.i.i, i32* bitcast (i64* @now to i32*) seq_cst, align 4
  store atomic i32 %now_trunc1.i.i.i, i32* bitcast (i64* getelementptr inbounds (i64, i64* @now, i64 1) to i32*) seq_cst, align 4
  tail call void @rtio_output(i32 4608, i32 0)
  ret void
}
; ModuleID = 'main'
source_filename = "main"

@"139903062922912" = global { double } { double 1.000000e-09 }
@"139903062923056" = global { { double }*, i32, i32 } { { double }* @"139903062922912", i32 18, i32 4608 }
@"139903062922480" = local_unnamed_addr global { { double }*, { { double }*, i32, i32 }* } { { double }* @"139903062922912", { { double }*, i32, i32 }* @"139903062923056" }
@now = external local_unnamed_addr global i64

declare void @rtio_output(i32 %0, i32 %1) local_unnamed_addr

define void @__modinit__() local_unnamed_addr {
init:
  tail call void @rtio_output(i32 4608, i32 1)
  %now_hi.i.i.i = load i32, i32* bitcast (i64* @now to i32*), align 4
  %now_lo.i.i.i = load i32, i32* bitcast (i64* getelementptr inbounds (i64, i64* @now, i64 1) to i32*), align 4
  %now_zext_hi.i.i.i = zext i32 %now_hi.i.i.i to i64
  %now_shifted_zext_hi.i.i.i = shl nuw i64 %now_zext_hi.i.i.i, 32
  %now_zext_lo.i.i.i = zext i32 %now_lo.i.i.i to i64
  %now_or.i.i.i = or i64 %now_shifted_zext_hi.i.i.i, %now_zext_lo.i.i.i
  %now_add.i.i.i = add i64 %now_or.i.i.i, 200000000
  %now_lshr.i.i.i = lshr i64 %now_add.i.i.i, 32
  %now_trunc.i.i.i = trunc i64 %now_lshr.i.i.i to i32
  %now_trunc1.i.i.i = trunc i64 %now_add.i.i.i to i32
  store atomic i32 %now_trunc.i.i.i, i32* bitcast (i64* @now to i32*) seq_cst, align 4
  store atomic i32 %now_trunc1.i.i.i, i32* bitcast (i64* getelementptr inbounds (i64, i64* @now, i64 1) to i32*) seq_cst, align 4
  tail call void @rtio_output(i32 4608, i32 0)
  ret void
}

Note that the variable test is a float in the first case, and int32 in the second case. The compilation output is correct (see the line %now_add.i.i.i = add i64 %now_or.i.i.i, )

Supports #91. This way of handling is actually quite efficient as we keep the parsed AST. We have to perform type inference again as python variables can change between kernel invocations, and their type can change. Example: ```python from min_artiq import * test = 100.0 @nac3 class Demo: core: KernelInvariant[Core] led0: KernelInvariant[TTLOut] def __init__(self): self.core = Core() self.led0 = TTLOut(self.core, 18) @kernel def run(self): self.core.reset() self.led0.pulse(float(test)*ms) if __name__ == "__main__": Demo().run() test = 200 Demo().run() ``` Output: ``` ; ModuleID = 'main' source_filename = "main" @"139905343409264" = global { double } { double 1.000000e-09 } @"139905343409648" = global { { double }*, i32, i32 } { { double }* @"139905343409264", i32 18, i32 4608 } @"139905343409888" = local_unnamed_addr global { { double }*, { { double }*, i32, i32 }* } { { double }* @"139905343409264", { { double }*, i32, i32 }* @"139905343409648" } @now = external local_unnamed_addr global i64 declare void @rtio_output(i32 %0, i32 %1) local_unnamed_addr define void @__modinit__() local_unnamed_addr { init: tail call void @rtio_output(i32 4608, i32 1) %now_hi.i.i.i = load i32, i32* bitcast (i64* @now to i32*), align 4 %now_lo.i.i.i = load i32, i32* bitcast (i64* getelementptr inbounds (i64, i64* @now, i64 1) to i32*), align 4 %now_zext_hi.i.i.i = zext i32 %now_hi.i.i.i to i64 %now_shifted_zext_hi.i.i.i = shl nuw i64 %now_zext_hi.i.i.i, 32 %now_zext_lo.i.i.i = zext i32 %now_lo.i.i.i to i64 %now_or.i.i.i = or i64 %now_shifted_zext_hi.i.i.i, %now_zext_lo.i.i.i %now_add.i.i.i = add i64 %now_or.i.i.i, 100000000 %now_lshr.i.i.i = lshr i64 %now_add.i.i.i, 32 %now_trunc.i.i.i = trunc i64 %now_lshr.i.i.i to i32 %now_trunc1.i.i.i = trunc i64 %now_add.i.i.i to i32 store atomic i32 %now_trunc.i.i.i, i32* bitcast (i64* @now to i32*) seq_cst, align 4 store atomic i32 %now_trunc1.i.i.i, i32* bitcast (i64* getelementptr inbounds (i64, i64* @now, i64 1) to i32*) seq_cst, align 4 tail call void @rtio_output(i32 4608, i32 0) ret void } ``` ``` ; ModuleID = 'main' source_filename = "main" @"139903062922912" = global { double } { double 1.000000e-09 } @"139903062923056" = global { { double }*, i32, i32 } { { double }* @"139903062922912", i32 18, i32 4608 } @"139903062922480" = local_unnamed_addr global { { double }*, { { double }*, i32, i32 }* } { { double }* @"139903062922912", { { double }*, i32, i32 }* @"139903062923056" } @now = external local_unnamed_addr global i64 declare void @rtio_output(i32 %0, i32 %1) local_unnamed_addr define void @__modinit__() local_unnamed_addr { init: tail call void @rtio_output(i32 4608, i32 1) %now_hi.i.i.i = load i32, i32* bitcast (i64* @now to i32*), align 4 %now_lo.i.i.i = load i32, i32* bitcast (i64* getelementptr inbounds (i64, i64* @now, i64 1) to i32*), align 4 %now_zext_hi.i.i.i = zext i32 %now_hi.i.i.i to i64 %now_shifted_zext_hi.i.i.i = shl nuw i64 %now_zext_hi.i.i.i, 32 %now_zext_lo.i.i.i = zext i32 %now_lo.i.i.i to i64 %now_or.i.i.i = or i64 %now_shifted_zext_hi.i.i.i, %now_zext_lo.i.i.i %now_add.i.i.i = add i64 %now_or.i.i.i, 200000000 %now_lshr.i.i.i = lshr i64 %now_add.i.i.i, 32 %now_trunc.i.i.i = trunc i64 %now_lshr.i.i.i to i32 %now_trunc1.i.i.i = trunc i64 %now_add.i.i.i to i32 store atomic i32 %now_trunc.i.i.i, i32* bitcast (i64* @now to i32*) seq_cst, align 4 store atomic i32 %now_trunc1.i.i.i, i32* bitcast (i64* getelementptr inbounds (i64, i64* @now, i64 1) to i32*) seq_cst, align 4 tail call void @rtio_output(i32 4608, i32 0) ret void } ``` Note that the variable `test` is a float in the first case, and int32 in the second case. The compilation output is correct (see the line `%now_add.i.i.i = add i64 %now_or.i.i.i, `)
pca006132 added 2 commits 2021-12-04 23:01:29 +08:00
sb10q merged commit 65bc1e5fa4 into master 2021-12-05 13:10:55 +08:00
Sign in to join this conversation.
No reviewers
No Milestone
No Assignees
1 Participants
Notifications
Due Date
The due date is invalid or out of range. Please use the format 'yyyy-mm-dd'.

No due date set.

Dependencies

No dependencies set.

Reference: M-Labs/nac3#124
No description provided.