diff --git a/artiq/compiler/transforms/llvm_ir_generator.py b/artiq/compiler/transforms/llvm_ir_generator.py index 61f66599c..084e5ae09 100644 --- a/artiq/compiler/transforms/llvm_ir_generator.py +++ b/artiq/compiler/transforms/llvm_ir_generator.py @@ -10,6 +10,7 @@ from llvmlite import ir as ll, binding as llvm from ...language import core as language_core from .. import types, builtins, ir from ..embedding import SpecializedFunction +from artiq.compiler.targets import RV32GTarget llvoid = ll.VoidType() @@ -1097,20 +1098,28 @@ class LLVMIRGenerator: if self.target.now_pinning: # Word swap now.old as CPU is little endian # Most significant word is stored in lower address (see generated csr.rs) - llnow_raw = self.llbuilder.load(self.llbuiltin("now"), name=insn.name) - llnow_lo = self.llbuilder.shl(llnow_raw, ll.Constant(lli64, 32)) - llnow_hi = self.llbuilder.lshr(llnow_raw, ll.Constant(lli64, 32)) - return self.llbuilder.or_(llnow_lo, llnow_hi) + csr_offset = 2 if isinstance(self.target, RV32GTarget) else 1 + + llnow_hiptr = self.llbuilder.bitcast(self.llbuiltin("now"), lli32.as_pointer()) + llnow_loptr = self.llbuilder.gep(llnow_hiptr, [self.llindex(csr_offset)]) + llnow_hi = self.llbuilder.load(llnow_hiptr, name="now.hi") + llnow_lo = self.llbuilder.load(llnow_loptr, name="now.lo") + llzext_hi = self.llbuilder.zext(llnow_hi, lli64) + llshifted_hi = self.llbuilder.shl(llzext_hi, ll.Constant(lli64, 32)) + llzext_lo = self.llbuilder.zext(llnow_lo, lli64) + return self.llbuilder.or_(llshifted_hi, llzext_lo) else: return self.llbuilder.call(self.llbuiltin("now_mu"), []) elif insn.op == "at_mu": time, = insn.operands lltime = self.map(time) if self.target.now_pinning: + csr_offset = 2 if isinstance(self.target, RV32GTarget) else 1 + 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)]) + llnow_loptr = self.llbuilder.gep(llnow_hiptr, [self.llindex(csr_offset)]) 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 @@ -1120,20 +1129,22 @@ class LLVMIRGenerator: interval, = insn.operands llinterval = self.map(interval) if self.target.now_pinning: - llnowptr = self.llbuiltin("now") - llnow = self.llbuilder.load(llnowptr, name="now.old") - # Word swap now.old as CPU is little endian # Most significant word is stored in lower address (see generated csr.rs) - llnow_lo = self.llbuilder.shl(llnow, ll.Constant(lli64, 32)) - llnow_hi = self.llbuilder.lshr(llnow, ll.Constant(lli64, 32)) - llnow = self.llbuilder.or_(llnow_lo, llnow_hi) + csr_offset = 2 if isinstance(self.target, RV32GTarget) else 1 + + llnow_hiptr = self.llbuilder.bitcast(self.llbuiltin("now"), lli32.as_pointer()) + llnow_loptr = self.llbuilder.gep(llnow_hiptr, [self.llindex(csr_offset)]) + llnow_hi = self.llbuilder.load(llnow_hiptr, name="now.hi") + llnow_lo = self.llbuilder.load(llnow_loptr, name="now.lo") + llzext_hi = self.llbuilder.zext(llnow_hi, lli64) + llshifted_hi = self.llbuilder.shl(llzext_hi, ll.Constant(lli64, 32)) + llzext_lo = self.llbuilder.zext(llnow_lo, lli64) + llnow = self.llbuilder.or_(llshifted_hi, llzext_lo) 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)]) 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