compiler/transforms/llvm_ir_generator: changed list representation

The representation of TList(T) is changed from `{T*, u32}` to
`{T*, u32}*`. The old representation forbids changing the length of a
list when the list is passed as a parameter into functions, as the
length is passed by value. The representation now matches with nac3.
This commit is contained in:
pca006132 2022-03-10 16:05:18 +08:00 committed by Sébastien Bourdeauducq
parent 8415151866
commit eb6817c8f1
1 changed files with 52 additions and 9 deletions

View File

@ -253,7 +253,10 @@ class LLVMIRGenerator:
return ll.LiteralStructType([llbufferty, llshapety]) return ll.LiteralStructType([llbufferty, llshapety])
elif builtins.is_listish(typ): elif builtins.is_listish(typ):
lleltty = self.llty_of_type(builtins.get_iterable_elt(typ)) lleltty = self.llty_of_type(builtins.get_iterable_elt(typ))
return ll.LiteralStructType([lleltty.as_pointer(), lli32]) lltyp = ll.LiteralStructType([lleltty.as_pointer(), lli32])
if builtins.is_list(typ):
lltyp = lltyp.as_pointer()
return lltyp
elif builtins.is_range(typ): elif builtins.is_range(typ):
lleltty = self.llty_of_type(builtins.get_iterable_elt(typ)) lleltty = self.llty_of_type(builtins.get_iterable_elt(typ))
return ll.LiteralStructType([lleltty, lleltty, lleltty]) return ll.LiteralStructType([lleltty, lleltty, lleltty])
@ -782,8 +785,19 @@ class LLVMIRGenerator:
llalloc = self.llbuilder.alloca(lleltty, size=llsize) llalloc = self.llbuilder.alloca(lleltty, size=llsize)
if types._is_pointer(insn.type): if types._is_pointer(insn.type):
return llalloc return llalloc
if builtins.is_list(insn.type):
llvalue = self.llbuilder.alloca(self.llty_of_type(insn.type).pointee, size=1)
self.llbuilder.store(llalloc, self.llbuilder.gep(llvalue,
[self.llindex(0),
self.llindex(0)],
inbounds=True))
self.llbuilder.store(llsize, self.llbuilder.gep(llvalue,
[self.llindex(0),
self.llindex(1)],
inbounds=True))
else:
llvalue = ll.Constant(self.llty_of_type(insn.type), ll.Undefined) llvalue = ll.Constant(self.llty_of_type(insn.type), ll.Undefined)
llvalue = self.llbuilder.insert_value(llvalue, llalloc, 0, name=insn.name) llvalue = self.llbuilder.insert_value(llvalue, llalloc, 0)
llvalue = self.llbuilder.insert_value(llvalue, llsize, 1) llvalue = self.llbuilder.insert_value(llvalue, llsize, 1)
return llvalue return llvalue
elif (not builtins.is_allocated(insn.type) or ir.is_keyword(insn.type) elif (not builtins.is_allocated(insn.type) or ir.is_keyword(insn.type)
@ -988,8 +1002,14 @@ class LLVMIRGenerator:
def process_Offset(self, insn): def process_Offset(self, insn):
base, idx = insn.base(), insn.index() base, idx = insn.base(), insn.index()
llelts, llidx = map(self.map, (base, idx)) llelts, llidx = map(self.map, (base, idx))
if not types._is_pointer(base.type): if builtins.is_listish(base.type):
# This is list-ish. # This is list-ish.
if builtins.is_list(base.type):
llelts = self.llbuilder.load(self.llbuilder.gep(llelts,
[self.llindex(0),
self.llindex(0)],
inbounds=True))
else:
llelts = self.llbuilder.extract_value(llelts, 0) llelts = self.llbuilder.extract_value(llelts, 0)
llelt = self.llbuilder.gep(llelts, [llidx], inbounds=True) llelt = self.llbuilder.gep(llelts, [llidx], inbounds=True)
return llelt return llelt
@ -1004,8 +1024,14 @@ class LLVMIRGenerator:
def process_SetElem(self, insn): def process_SetElem(self, insn):
base, idx = insn.base(), insn.index() base, idx = insn.base(), insn.index()
llelts, llidx = map(self.map, (base, idx)) llelts, llidx = map(self.map, (base, idx))
if not types._is_pointer(base.type): if builtins.is_listish(base.type):
# This is list-ish. # This is list-ish.
if builtins.is_list(base.type):
llelts = self.llbuilder.load(self.llbuilder.gep(llelts,
[self.llindex(0),
self.llindex(0)],
inbounds=True))
else:
llelts = self.llbuilder.extract_value(llelts, 0) llelts = self.llbuilder.extract_value(llelts, 0)
llelt = self.llbuilder.gep(llelts, [llidx], inbounds=True) llelt = self.llbuilder.gep(llelts, [llidx], inbounds=True)
return self.llbuilder.store(self.map(insn.value()), llelt) return self.llbuilder.store(self.map(insn.value()), llelt)
@ -1152,6 +1178,11 @@ class LLVMIRGenerator:
lllhs, llrhs = map(self.map, (insn.lhs(), insn.rhs())) lllhs, llrhs = map(self.map, (insn.lhs(), insn.rhs()))
assert lllhs.type == llrhs.type assert lllhs.type == llrhs.type
if isinstance(lllhs.type, ll.PointerType) and \
isinstance(lllhs.type.pointee, ll.LiteralStructType):
lllhs = self.llbuilder.load(lllhs)
llrhs = self.llbuilder.load(llrhs)
if isinstance(lllhs.type, ll.IntType): if isinstance(lllhs.type, ll.IntType):
return self.llbuilder.icmp_signed(op, lllhs, llrhs, return self.llbuilder.icmp_signed(op, lllhs, llrhs,
name=insn.name) name=insn.name)
@ -1222,6 +1253,11 @@ class LLVMIRGenerator:
shape = self.llbuilder.extract_value(self.map(collection), shape = self.llbuilder.extract_value(self.map(collection),
self.attr_index(collection.type, "shape")) self.attr_index(collection.type, "shape"))
return self.llbuilder.extract_value(shape, 0) return self.llbuilder.extract_value(shape, 0)
elif builtins.is_list(collection.type):
return self.llbuilder.load(self.llbuilder.gep(self.map(collection),
[self.llindex(0),
self.llindex(1)]))
else:
return self.llbuilder.extract_value(self.map(collection), 1) return self.llbuilder.extract_value(self.map(collection), 1)
elif insn.op in ("printf", "rtio_log"): elif insn.op in ("printf", "rtio_log"):
# We only get integers, floats, pointers and strings here. # We only get integers, floats, pointers and strings here.
@ -1677,6 +1713,13 @@ class LLVMIRGenerator:
assert isinstance(value, (list, numpy.ndarray)), fail_msg assert isinstance(value, (list, numpy.ndarray)), fail_msg
elt_type = builtins.get_iterable_elt(typ) elt_type = builtins.get_iterable_elt(typ)
lleltsptr = self._quote_listish_to_llglobal(value, elt_type, path, typ.find().name) lleltsptr = self._quote_listish_to_llglobal(value, elt_type, path, typ.find().name)
if builtins.is_list(typ):
llconst = ll.Constant(llty.pointee, [lleltsptr, ll.Constant(lli32, len(value))])
name = self.llmodule.scope.deduplicate("quoted.{}".format(typ.find().name))
llglobal = ll.GlobalVariable(self.llmodule, llconst.type, name)
llglobal.initializer = llconst
llglobal.linkage = "private"
return llglobal
llconst = ll.Constant(llty, [lleltsptr, ll.Constant(lli32, len(value))]) llconst = ll.Constant(llty, [lleltsptr, ll.Constant(lli32, len(value))])
return llconst return llconst
elif types.is_tuple(typ): elif types.is_tuple(typ):