nac3core: impl call attributes #217

Merged
sb10q merged 1 commits from call-attributes into master 2022-03-09 22:25:29 +08:00
Contributor

Implemented sret for returning large structs, and byval for struct args in extern
function calls.

Closes #151

Tests: I'm not sure what is the best way to write the test for nac3artiq, but here is the test case I've tested with:

from min_artiq import *
from numpy import int32, int64

@extern
def return_tuple(a: tuple[int32, int32]) -> tuple[int32, int32, int32]:
    ...

@nac3
class Demo:
    core: KernelInvariant[Core]
    def __init__(self):
        self.core = Core()

    @kernel
    def run(self):
        return_tuple((1, 2))

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

LLVM IR:

; ModuleID = 'main'
source_filename = "main"

%min_artiq.Core = type { double }
%min_artiq.TTLOut = type { %min_artiq.Core*, i32, i32 }
%__main__.Demo = type { %min_artiq.Core*, %min_artiq.TTLOut*, %min_artiq.TTLOut* }

@"140115763407984" = global %min_artiq.Core { double 1.000000e-09 }
@"140115763408176" = global %min_artiq.TTLOut { %min_artiq.Core* @"140115763407984", i32 18, i32 4608 }
@"140115763407840" = global %min_artiq.TTLOut { %min_artiq.Core* @"140115763407984", i32 19, i32 4864 }
@"140115763408512" = local_unnamed_addr global %__main__.Demo { %min_artiq.Core* @"140115763407984", %min_artiq.TTLOut* @"140115763408176", %min_artiq.TTLOut* @"140115763407840" }

declare i32 @__nac3_personality(...)

declare void @return_tuple({ i32, i32, i32 }* sret({ i32, i32, i32 }) %0, { i32, i32 }* byval({ i32, i32 }) %1) local_unnamed_addr

define void @__modinit__() local_unnamed_addr personality i32 (...)* @__nac3_personality {
init:
  %call.i = alloca { i32, i32, i32 }, align 8
  %call2.i = alloca { i32, i32 }, align 8
  %0 = bitcast { i32, i32, i32 }* %call.i to i8*
  call void @llvm.lifetime.start.p0i8(i64 12, i8* nonnull %0)
  %1 = bitcast { i32, i32 }* %call2.i to i8*
  call void @llvm.lifetime.start.p0i8(i64 8, i8* nonnull %1)
  %tup_val.fca.0.gep.i = getelementptr inbounds { i32, i32 }, { i32, i32 }* %call2.i, i64 0, i32 0
  store i32 1, i32* %tup_val.fca.0.gep.i, align 8
  %tup_val.fca.1.gep.i = getelementptr inbounds { i32, i32 }, { i32, i32 }* %call2.i, i64 0, i32 1
  store i32 2, i32* %tup_val.fca.1.gep.i, align 4
  call void @return_tuple({ i32, i32, i32 }* nonnull sret({ i32, i32, i32 }) %call.i, { i32, i32 }* nonnull byval({ i32, i32 }) %call2.i)
  call void @llvm.lifetime.end.p0i8(i64 12, i8* nonnull %0)
  call void @llvm.lifetime.end.p0i8(i64 8, i8* nonnull %1)
  ret void
}

; Function Attrs: argmemonly nofree nosync nounwind willreturn
declare void @llvm.lifetime.start.p0i8(i64 immarg %0, i8* nocapture %1) #0

; Function Attrs: argmemonly nofree nosync nounwind willreturn
declare void @llvm.lifetime.end.p0i8(i64 immarg %0, i8* nocapture %1) #0

attributes #0 = { argmemonly nofree nosync nounwind willreturn }
Implemented sret for returning large structs, and byval for struct args in extern function calls. Closes #151 Tests: I'm not sure what is the best way to write the test for nac3artiq, but here is the test case I've tested with: ```python from min_artiq import * from numpy import int32, int64 @extern def return_tuple(a: tuple[int32, int32]) -> tuple[int32, int32, int32]: ... @nac3 class Demo: core: KernelInvariant[Core] def __init__(self): self.core = Core() @kernel def run(self): return_tuple((1, 2)) if __name__ == "__main__": Demo().run() ``` LLVM IR: ``` ; ModuleID = 'main' source_filename = "main" %min_artiq.Core = type { double } %min_artiq.TTLOut = type { %min_artiq.Core*, i32, i32 } %__main__.Demo = type { %min_artiq.Core*, %min_artiq.TTLOut*, %min_artiq.TTLOut* } @"140115763407984" = global %min_artiq.Core { double 1.000000e-09 } @"140115763408176" = global %min_artiq.TTLOut { %min_artiq.Core* @"140115763407984", i32 18, i32 4608 } @"140115763407840" = global %min_artiq.TTLOut { %min_artiq.Core* @"140115763407984", i32 19, i32 4864 } @"140115763408512" = local_unnamed_addr global %__main__.Demo { %min_artiq.Core* @"140115763407984", %min_artiq.TTLOut* @"140115763408176", %min_artiq.TTLOut* @"140115763407840" } declare i32 @__nac3_personality(...) declare void @return_tuple({ i32, i32, i32 }* sret({ i32, i32, i32 }) %0, { i32, i32 }* byval({ i32, i32 }) %1) local_unnamed_addr define void @__modinit__() local_unnamed_addr personality i32 (...)* @__nac3_personality { init: %call.i = alloca { i32, i32, i32 }, align 8 %call2.i = alloca { i32, i32 }, align 8 %0 = bitcast { i32, i32, i32 }* %call.i to i8* call void @llvm.lifetime.start.p0i8(i64 12, i8* nonnull %0) %1 = bitcast { i32, i32 }* %call2.i to i8* call void @llvm.lifetime.start.p0i8(i64 8, i8* nonnull %1) %tup_val.fca.0.gep.i = getelementptr inbounds { i32, i32 }, { i32, i32 }* %call2.i, i64 0, i32 0 store i32 1, i32* %tup_val.fca.0.gep.i, align 8 %tup_val.fca.1.gep.i = getelementptr inbounds { i32, i32 }, { i32, i32 }* %call2.i, i64 0, i32 1 store i32 2, i32* %tup_val.fca.1.gep.i, align 4 call void @return_tuple({ i32, i32, i32 }* nonnull sret({ i32, i32, i32 }) %call.i, { i32, i32 }* nonnull byval({ i32, i32 }) %call2.i) call void @llvm.lifetime.end.p0i8(i64 12, i8* nonnull %0) call void @llvm.lifetime.end.p0i8(i64 8, i8* nonnull %1) ret void } ; Function Attrs: argmemonly nofree nosync nounwind willreturn declare void @llvm.lifetime.start.p0i8(i64 immarg %0, i8* nocapture %1) #0 ; Function Attrs: argmemonly nofree nosync nounwind willreturn declare void @llvm.lifetime.end.p0i8(i64 immarg %0, i8* nocapture %1) #0 attributes #0 = { argmemonly nofree nosync nounwind willreturn } ```
pca006132 added 1 commit 2022-03-09 22:13:51 +08:00
sret for returning large structs, and byval for struct args in extern
function calls.
Owner

byval for struct args in extern

This will need updating the artiq firmware, artiq-zynq, and the legacy compiler, correct?

> byval for struct args in extern This will need updating the artiq firmware, artiq-zynq, and the legacy compiler, correct?
Author
Contributor

byval for struct args in extern

This will need updating the artiq firmware, artiq-zynq, and the legacy compiler, correct?

No. The one that needs this update is #187

> > byval for struct args in extern > > This will need updating the artiq firmware, artiq-zynq, and the legacy compiler, correct? No. The one that needs this update is #187
sb10q merged commit 2f85bb3837 into master 2022-03-09 22:25:29 +08:00
sb10q deleted branch call-attributes 2022-03-09 22:25:29 +08:00
Sign in to join this conversation.
No reviewers
No Milestone
No Assignees
2 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#217
No description provided.