diff --git a/artiq/compiler/targets.py b/artiq/compiler/targets.py index 1519a8df9..c5b282c4c 100644 --- a/artiq/compiler/targets.py +++ b/artiq/compiler/targets.py @@ -78,13 +78,15 @@ class Target: :var little_endian: (boolean) Whether the code will be executed on a little-endian machine. This cannot be always determined from data_layout due to JIT. + :var now_pinning: (boolean) + Whether the target implements the now-pinning RTIO optimization. """ triple = "unknown" data_layout = "" features = [] print_function = "printf" little_endian = False - + now_pinning = True def __init__(self): self.llcontext = ll.Context() @@ -254,6 +256,7 @@ class OR1KTarget(Target): features = ["mul", "div", "ffl1", "cmov", "addc"] print_function = "core_log" little_endian = False + now_pinning = True class CortexA9Target(Target): triple = "armv7-unknown-linux-gnueabihf" @@ -261,3 +264,4 @@ class CortexA9Target(Target): features = ["dsp", "fp16", "neon", "vfp3"] print_function = "core_log" little_endian = True + now_pinning = False diff --git a/artiq/compiler/transforms/llvm_ir_generator.py b/artiq/compiler/transforms/llvm_ir_generator.py index ca302412d..b63cb881f 100644 --- a/artiq/compiler/transforms/llvm_ir_generator.py +++ b/artiq/compiler/transforms/llvm_ir_generator.py @@ -380,8 +380,19 @@ class LLVMIRGenerator: llty = ll.FunctionType(llvoid, [lli32, llsliceptr, llptrptr]) elif name == "rpc_recv": llty = ll.FunctionType(lli32, [llptr]) + + # with now-pinning elif name == "now": llty = lli64 + + # without now-pinning + elif name == "now_mu": + llty = ll.FunctionType(lli64, []) + elif name == "at_mu": + llty = ll.FunctionType(llvoid, [lli64]) + elif name == "delay_mu": + llty = ll.FunctionType(llvoid, [lli64]) + elif name == "watchdog_set": llty = ll.FunctionType(lli32, [lli64]) elif name == "watchdog_clear": @@ -1174,35 +1185,43 @@ class LLVMIRGenerator: # This is an identity cast at LLVM IR level. return self.map(insn.operands[0]) elif insn.op == "now_mu": - llnow = self.llbuilder.load(self.llbuiltin("now"), name=insn.name) - return llnow + if self.target.now_pinning: + return self.llbuilder.load(self.llbuiltin("now"), name=insn.name) + else: + return self.llbuilder.call(self.llbuiltin("now_mu"), []) elif insn.op == "at_mu": time, = insn.operands lltime = self.map(time) - lltime_hi = self.llbuilder.trunc(self.llbuilder.lshr(lltime, ll.Constant(lli64, 32)), lli32) - lltime_lo = self.llbuilder.trunc(lltime, lli32) - llnow_hiptr = self.llbuilder.bitcast(self.llbuiltin("now"), lli32.as_pointer()) - llnow_loptr = self.llbuilder.gep(llnow_hiptr, [self.llindex(1)]) - if self.target.little_endian: - lltime_hi, lltime_lo = lltime_lo, lltime_hi - llstore_hi = self.llbuilder.store_atomic(lltime_hi, llnow_hiptr, ordering="seq_cst", align=4) - llstore_lo = self.llbuilder.store_atomic(lltime_lo, llnow_loptr, ordering="seq_cst", align=4) - return llstore_lo + if self.target.now_pinning: + lltime_hi = self.llbuilder.trunc(self.llbuilder.lshr(lltime, ll.Constant(lli64, 32)), lli32) + lltime_lo = self.llbuilder.trunc(lltime, lli32) + llnow_hiptr = self.llbuilder.bitcast(self.llbuiltin("now"), lli32.as_pointer()) + llnow_loptr = self.llbuilder.gep(llnow_hiptr, [self.llindex(1)]) + if self.target.little_endian: + lltime_hi, lltime_lo = lltime_lo, lltime_hi + llstore_hi = self.llbuilder.store_atomic(lltime_hi, llnow_hiptr, ordering="seq_cst", align=4) + llstore_lo = self.llbuilder.store_atomic(lltime_lo, llnow_loptr, ordering="seq_cst", align=4) + return llstore_lo + else: + return self.llbuilder.call(self.llbuiltin("at_mu"), [lltime]) elif insn.op == "delay_mu": interval, = insn.operands - llnowptr = self.llbuiltin("now") - llnow = self.llbuilder.load(llnowptr, name="now.old") - lladjusted = self.llbuilder.add(llnow, self.map(interval), name="now.new") - - lladjusted_hi = self.llbuilder.trunc(self.llbuilder.lshr(lladjusted, ll.Constant(lli64, 32)), lli32) - lladjusted_lo = self.llbuilder.trunc(lladjusted, lli32) - llnow_hiptr = self.llbuilder.bitcast(llnowptr, lli32.as_pointer()) - llnow_loptr = self.llbuilder.gep(llnow_hiptr, [self.llindex(1)]) - if self.target.little_endian: - lladjusted_hi, lladjusted_lo = lladjusted_lo, lladjusted_hi - llstore_hi = self.llbuilder.store_atomic(lladjusted_hi, llnow_hiptr, ordering="seq_cst", align=4) - llstore_lo = self.llbuilder.store_atomic(lladjusted_lo, llnow_loptr, ordering="seq_cst", align=4) - return llstore_lo + llinterval = self.map(interval) + if self.target.now_pinning: + llnowptr = self.llbuiltin("now") + llnow = self.llbuilder.load(llnowptr, name="now.old") + lladjusted = self.llbuilder.add(llnow, llinterval, name="now.new") + lladjusted_hi = self.llbuilder.trunc(self.llbuilder.lshr(lladjusted, ll.Constant(lli64, 32)), lli32) + lladjusted_lo = self.llbuilder.trunc(lladjusted, lli32) + llnow_hiptr = self.llbuilder.bitcast(llnowptr, lli32.as_pointer()) + llnow_loptr = self.llbuilder.gep(llnow_hiptr, [self.llindex(1)]) + if self.target.little_endian: + lladjusted_hi, lladjusted_lo = lladjusted_lo, lladjusted_hi + llstore_hi = self.llbuilder.store_atomic(lladjusted_hi, llnow_hiptr, ordering="seq_cst", align=4) + llstore_lo = self.llbuilder.store_atomic(lladjusted_lo, llnow_loptr, ordering="seq_cst", align=4) + return llstore_lo + else: + return self.llbuilder.call(self.llbuiltin("delay_mu"), [llinterval]) elif insn.op == "watchdog_set": interval, = insn.operands return self.llbuilder.call(self.llbuiltin("watchdog_set"), [self.map(interval)])