Skip to content

Commit 2e9e5db

Browse files
authored
feat: extract simple array literals as static initializers (#12724)
This PR implements support for extracting simple ground array literals into statically initialized data.
1 parent 81a5eb5 commit 2e9e5db

File tree

3 files changed

+364
-0
lines changed

3 files changed

+364
-0
lines changed

src/Lean/Compiler/IR/EmitC.lean

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -176,6 +176,23 @@ where
176176
| .nameMkStr args =>
177177
let obj ← groundNameMkStrToCLit args
178178
mkValueCLit "lean_ctor_object" obj
179+
| .array elems =>
180+
let leanArrayTag := 246
181+
let header := mkHeader s!"sizeof(lean_array_object) + sizeof(void*)*{elems.size}" 0 leanArrayTag
182+
let elemLits ← elems.mapM groundArgToCLit
183+
let dataArray := String.intercalate "," elemLits.toList
184+
mkValueCLit
185+
"lean_array_object"
186+
s!"\{.m_header = {header}, .m_size = {elems.size}, .m_capacity = {elems.size}, .m_data = \{{dataArray}}}"
187+
| .byteArray data =>
188+
let leanScalarArrayTag := 248
189+
let elemSize : Nat := 1
190+
let header := mkHeader s!"sizeof(lean_sarray_object) + {data.size}" elemSize leanScalarArrayTag
191+
let dataLits := data.map toString
192+
let dataArray := String.intercalate "," dataLits.toList
193+
mkValueCLit
194+
"lean_sarray_object"
195+
s!"\{.m_header = {header}, .m_size = {data.size}, .m_capacity = {data.size}, .m_data = \{{dataArray}}}"
179196
| .reference refDecl => findValueDecl refDecl
180197

181198
mkValueName (name : String) : String :=

src/Lean/Compiler/LCNF/SimpleGroundExpr.lean

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,14 @@ public inductive SimpleGroundExpr where
7171
compiled to a reference to the mangled version of the name.
7272
-/
7373
| reference (n : Name)
74+
/--
75+
An array of `lean_object*` elements, represented by a `lean_array_object`.
76+
-/
77+
| array (elems : Array SimpleGroundArg)
78+
/--
79+
A byte array (scalar array with elem_size=1), represented by a `lean_sarray_object`.
80+
-/
81+
| byteArray (data : Array UInt8)
7482
deriving Inhabited
7583

7684
public structure SimpleGroundExtState where
@@ -141,6 +149,11 @@ inductive SimpleGroundValue where
141149
| uint32 (val : UInt32)
142150
| uint64 (val : UInt64)
143151
| usize (val : UInt64)
152+
/--
153+
Contains the elements of the array in a list in reverse order to enable sharing as we traverse the
154+
expression instead.
155+
-/
156+
| arrayBuilder (elems : List SimpleGroundArg) (remainingCapacity : Nat)
144157
deriving Inhabited
145158

146159
structure DetectState where
@@ -157,6 +170,8 @@ The compiler currently supports the following patterns:
157170
- Constructor calls with other simple expressions
158171
- `Name.mkStrX`, `Name.str._override`, and `Name.num._override`
159172
- references to other declarations marked as simple ground expressions
173+
- Array literals (`Array.mkEmpty` + `Array.push` chains)
174+
- ByteArray literals (`Array.mkEmpty` + `Array.push` chains + `ByteArray.mk`)
160175
-/
161176
partial def compileToSimpleGroundExpr (code : Code .impure) : CompilerM (Option SimpleGroundExpr) :=
162177
go code |>.run' {} |>.run
@@ -217,6 +232,16 @@ where
217232
go k
218233
-- boxed uint32/uint64 get extracted into separate closed terms automatically
219234
| _ => failure
235+
| .fap ``Array.mkEmpty #[.erased, .fvar sizeId]
236+
| .fap ``Array.emptyWithCapacity #[.erased, .fvar sizeId] =>
237+
let .arg (.tagged size) := (← get).groundMap[sizeId]! | failure
238+
record decl.fvarId (.arrayBuilder [] size)
239+
go k
240+
| .fap ``Array.push #[.erased, .fvar arrId, .fvar elemId] =>
241+
let .arrayBuilder elems remainingCapacity := (← get).groundMap[arrId]! | failure
242+
let .arg elemArg := (← get).groundMap[elemId]! | failure
243+
record decl.fvarId (.arrayBuilder (elemArg :: elems) (remainingCapacity - 1))
244+
go k
220245
| _ => failure
221246

222247
compileSetChain (id : FVarId) (info : CtorInfo) (objArgs : Array SimpleGroundArg)
@@ -301,6 +326,29 @@ where
301326
nameAcc := .str nameAcc str
302327
processedArgs := processedArgs.push (ref, nameAcc.hash)
303328
return .nameMkStr processedArgs
329+
| .fap ``Array.mkEmpty #[.erased, .fvar sizeId]
330+
| .fap ``Array.emptyWithCapacity #[.erased, .fvar sizeId] =>
331+
let .arg (.tagged 0) := (← get).groundMap[sizeId]! | failure
332+
return .array #[]
333+
| .fap ``ByteArray.mk #[.fvar argId] =>
334+
match (← get).groundMap[argId]! with
335+
| .arrayBuilder elems 0 =>
336+
let bytes ← elems.mapM fun elem => do
337+
let .tagged v := elem | failure
338+
return v.toUInt8
339+
return .byteArray bytes.toArray.reverse
340+
| .arg (.reference ref) =>
341+
let some (.array elems) := getSimpleGroundExprWithResolvedRefs (← getEnv) ref | failure
342+
let bytes ← elems.mapM fun elem => do
343+
let .tagged v := elem | failure
344+
return v.toUInt8
345+
return .byteArray bytes
346+
| _ => failure
347+
| .fap ``Array.push #[.erased, .fvar arrId, .fvar elemId] =>
348+
let .arrayBuilder elems remainingCapacity := (← get).groundMap[arrId]! | failure
349+
if remainingCapacity > 1 then failure
350+
let .arg elemArg := (← get).groundMap[elemId]! | failure
351+
return .array (elemArg :: elems).toArray.reverse
304352
| .fap c #[] =>
305353
guard <| isSimpleGroundDecl (← getEnv) c
306354
return .reference c

0 commit comments

Comments
 (0)