Browse Source

Added a bunch of files that should have been here already

Neia Finch 1 year ago
parent
commit
157c895cb4
5 changed files with 574 additions and 2 deletions
  1. 12
    2
      .gitignore
  2. 5
    0
      dpetalc/.gitignore
  3. 479
    0
      dpetalc/src/petal/llvm/emit.d
  4. 15
    0
      dpetalc/test/lex/test_class_with_funcs.petal
  5. 63
    0
      genlogo.d

+ 12
- 2
.gitignore View File

@@ -1,3 +1,13 @@
1
-/.metadata/
1
+a.out
2
+*.ll
3
+*.s
4
+*.o
5
+*.a
6
+*.bc
7
+bison.output
8
+test-results
2 9
 *.swp
3
-/.recommenders/
10
+tmp
11
+jpetalc
12
+testrunner
13
+petalc

+ 5
- 0
dpetalc/.gitignore View File

@@ -0,0 +1,5 @@
1
+*.o
2
+petalc
3
+petal-test-binary
4
+a.out
5
+src/petal/frontend/bison.d

+ 479
- 0
dpetalc/src/petal/llvm/emit.d View File

@@ -0,0 +1,479 @@
1
+module petal.llvm.emit;
2
+
3
+import petal.frontend.ast;
4
+import petal.frontend.core;
5
+import petal.frontend.errors;
6
+import petal.frontend.lexer;
7
+import petal.frontend.types;
8
+import petal.semantic.visitor;
9
+import std.experimental.logger;
10
+
11
+import llvm;
12
+import std.string : toStringz, fromStringz;
13
+
14
+enum allTargets = [
15
+    "AArch64",
16
+    "AMDGPU",
17
+    "ARM",
18
+    "BPF",
19
+    "Hexagon",
20
+    "Lanai",
21
+    "Mips",
22
+    "MSP430",
23
+    "NVPTX",
24
+    "PowerPC",
25
+    "Sparc",
26
+    "SystemZ",
27
+    "WebAssembly",
28
+    "X86",
29
+    "XCore",
30
+    "AVR",
31
+];
32
+static foreach (target; allTargets)
33
+{
34
+    mixin("extern(C) void LLVMInitialize", target, "Target();");
35
+}
36
+
37
+struct Targets
38
+{
39
+    string objfile;
40
+    string asmfile;
41
+    string exe;
42
+}
43
+
44
+void emit(ModuleDecl[] modules, string name, Targets targets, ErrorRecorder errors)
45
+{
46
+    static foreach (target; allTargets)
47
+    {
48
+        mixin("LLVMInitialize", target, "Target();");
49
+    }
50
+    LLVMInitializeAllTargetInfos();
51
+    LLVMInitializeAllTargets();
52
+    LLVMInitializeAllTargetMCs();
53
+    LLVMInitializeAllAsmParsers();
54
+    LLVMInitializeAllAsmPrinters();
55
+    auto context = LLVMContextCreate();
56
+    auto lmod = LLVMModuleCreateWithNameInContext(name.toStringz, context);
57
+    auto types = new TypeFinder(context);
58
+    types.initBuiltinTypes;
59
+    auto funcs = new FuncEmitter(context, types, lmod);
60
+    foreach (m; modules)
61
+    {
62
+        tracef("gathering llvm types for " ~ m.name);
63
+        types.visit(m);
64
+    }
65
+    foreach (m; modules)
66
+    {
67
+        tracef("emitting functions for %s with %s children", m.name, m.children.length);
68
+        funcs.visit(cast(SemNode)m);
69
+    }
70
+    if (targets.asmfile != "")
71
+    {
72
+        tracef("emitting llvm ir to %s", targets.asmfile);
73
+        char* err;
74
+        if (LLVMPrintModuleToFile(lmod, targets.asmfile.toMStringz, &err) != 0)
75
+        {
76
+            throw new InternalCompilerError(
77
+                    "failed to write LLVM IR to "
78
+                    ~ targets.asmfile
79
+                    ~ ": "
80
+                    ~ err.fromStringz.idup);
81
+        }
82
+        tracef("done emitting llvm ir");
83
+    }
84
+    if (targets.objfile != "")
85
+    {
86
+        auto triple = LLVMGetDefaultTargetTriple();
87
+        tracef("target triple: %s", triple.fromStringz);
88
+        LLVMTargetRef target;
89
+        char* err;
90
+        if (LLVMGetTargetFromTriple(triple, &target, &err) != 0)
91
+        {
92
+            throw new InternalCompilerError(
93
+                    "failed to initialize target model "
94
+                    ~ triple.fromStringz.idup
95
+                    ~ ": "
96
+                    ~ err.fromStringz.idup);
97
+        }
98
+        auto machine = LLVMCreateTargetMachine(
99
+                target,
100
+                triple,
101
+                "generic", /* cpu */
102
+                "", /* features */
103
+                LLVMCodeGenLevelDefault,
104
+                LLVMRelocDefault,
105
+                LLVMCodeModelDefault);
106
+        LLVMSetTarget(lmod, triple);
107
+        if (LLVMGetTargetFromTriple(triple, &target, &err) != 0)
108
+        {
109
+            throw new InternalCompilerError(
110
+                    "failed to initialize target machine "
111
+                    ~ triple.fromStringz.idup
112
+                    ~ ": "
113
+                    ~ err.fromStringz.idup);
114
+        }
115
+        if (LLVMTargetMachineEmitToFile(
116
+                    machine,
117
+                    lmod,
118
+                    targets.objfile.toMStringz,
119
+                    LLVMObjectFile,
120
+                    &err) != 0)
121
+        {
122
+            throw new InternalCompilerError(
123
+                    "failed to write machine code to "
124
+                    ~ targets.objfile
125
+                    ~ ": "
126
+                    ~ err.fromStringz.idup);
127
+        }
128
+        tracef("done emitting object code");
129
+    }
130
+    if (targets.exe != "")
131
+    {
132
+        assert(targets.objfile != "");
133
+        // Linking is done externally
134
+        import std.process : execute;
135
+        auto result = execute(["gcc", targets.objfile, "-o", targets.exe]);
136
+        if (result.status != 0)
137
+        {
138
+            errors.reportf(
139
+                    modules[0].loc,
140
+                    ErrorType.linkerFailed,
141
+                    "gcc exited with code %s\n%s",
142
+                    result.status,
143
+                    result.output);
144
+        }
145
+    }
146
+}
147
+
148
+char* toMStringz(string s)
149
+{
150
+    return (s ~ "\0").dup.ptr;
151
+}
152
+
153
+class TypeFinder : VisitBase!LLVMTypeRef
154
+{
155
+    alias visit = typeof(super).visit;
156
+
157
+    LLVMContextRef context;
158
+    this(LLVMContextRef context)
159
+    {
160
+        this.context = context;
161
+    }
162
+
163
+    void initBuiltinTypes()
164
+    {
165
+        BuiltinType.unit.llvmType = LLVMVoidTypeInContext(context);
166
+        tracef("unit llvmtype is %x", BuiltinType.unit.llvmType);
167
+        BuiltinType.boolean.llvmType = LLVMInt1TypeInContext(context);
168
+        BuiltinType.uint8.llvmType = LLVMInt8TypeInContext(context);
169
+        BuiltinType.uint16.llvmType = LLVMInt16TypeInContext(context);
170
+        BuiltinType.uint32.llvmType = LLVMInt32TypeInContext(context);
171
+        BuiltinType.uint64.llvmType = LLVMInt64TypeInContext(context);
172
+        BuiltinType.int8.llvmType = LLVMInt8TypeInContext(context);
173
+        BuiltinType.int16.llvmType = LLVMInt16TypeInContext(context);
174
+        BuiltinType.int32.llvmType = LLVMInt32TypeInContext(context);
175
+        BuiltinType.int64.llvmType = LLVMInt64TypeInContext(context);
176
+        BuiltinType.float64.llvmType = LLVMDoubleTypeInContext(context);
177
+        BuiltinType.intLiteral.llvmType = LLVMInt64TypeInContext(context);
178
+        BuiltinType.floatLiteral.llvmType = LLVMDoubleTypeInContext(context);
179
+    }
180
+
181
+    override LLVMTypeRef visit(IntLiteral s)
182
+    {
183
+        tracef("int %s", s);
184
+        if (s.type is BuiltinType.intLiteral)
185
+            s.type = BuiltinType.int64;
186
+        return s.type.llvmType;
187
+    }
188
+
189
+    override LLVMTypeRef visit(FloatLiteral s)
190
+    {
191
+        tracef("float %s", s);
192
+        if (s.type is BuiltinType.floatLiteral)
193
+            s.type = BuiltinType.float64;
194
+        return s.type.llvmType;
195
+    }
196
+
197
+    override LLVMTypeRef visit(TypeDecl s)
198
+    {
199
+        tracef("typedecl %s", s.name);
200
+        if (s.llvmType !is null) return s.llvmType;
201
+        return null;
202
+    }
203
+
204
+    override LLVMTypeRef visit(FuncArg s)
205
+    {
206
+        s.llvmType = visit(s.typeExpr);
207
+        return s.llvmType;
208
+    }
209
+
210
+    override LLVMTypeRef visit(FuncDecl s)
211
+    {
212
+        import std.algorithm : map;
213
+        import std.array : array;
214
+        if (s.llvmType !is null) return s.llvmType;
215
+        auto args = s.args.map!(x => this.visit(x)).array;
216
+        auto ret = s.returnType ? s.returnType.llvmType : BuiltinType.unit.llvmType;
217
+        tracef("building function type with %s args, return type %s, llvm return value %s", ret,
218
+                s.returnType, args.length);
219
+        // No "InContext" version of this?
220
+        s.llvmType = LLVMFunctionType(ret, args.ptr, cast(uint)args.length, false);
221
+        tracef("forged llvm type %s for func %s with %s args",
222
+                LLVMPrintTypeToString(s.llvmType).fromStringz, s.name, s.args.length);
223
+        return s.llvmType;
224
+    }
225
+}
226
+
227
+class FuncEmitter : VisitBase!void
228
+{
229
+    this(LLVMContextRef context, TypeFinder types, LLVMModuleRef mod)
230
+    {
231
+        this.context = context;
232
+        this.types = types;
233
+        this.mod = mod;
234
+    }
235
+
236
+    LLVMContextRef context;
237
+    TypeFinder types;
238
+    LLVMModuleRef mod;
239
+
240
+    alias visit = typeof(super).visit;
241
+
242
+    override bool before(SemNode s)
243
+    {
244
+        tracef("funcemitter: about to visit %s", s);
245
+        return true;
246
+    }
247
+
248
+    override void after(SemNode s)
249
+    {
250
+        tracef("funcemitter: visited %s", s);
251
+    }
252
+
253
+    override void visit(FuncDecl s)
254
+    {
255
+        tracef("FuncEmitter.visit(%s)", s.name);
256
+        // TODO do something reasonable about nested functions
257
+        visitChildren(s);
258
+
259
+        auto type = types.visit(s);
260
+        auto func = LLVMAddFunction(mod, s.mangledName.toStringz, type);
261
+        s.llvmRef = func;
262
+        tracef("defining function %s", s.name);
263
+        new FuncBodyVisitor(context, types).emit(s);
264
+        //LLVMVerifyFunction(func, LLVMPrintMessageAction);
265
+    }
266
+}
267
+
268
+class FuncBodyVisitor : VisitBase!void
269
+{
270
+    this(LLVMContextRef context, TypeFinder types)
271
+    {
272
+        this.context = context;
273
+        this.types = types;
274
+    }
275
+
276
+    LLVMContextRef context;
277
+    TypeFinder types;
278
+    LLVMBuilderRef builder;
279
+    LLVMBuilderRef defbuilder;
280
+
281
+    alias visit = typeof(super).visit;
282
+
283
+    override void visit(FuncDecl s) { /* don't descend into children */ }
284
+
285
+    void emit(FuncDecl s)
286
+    {
287
+        auto defs = LLVMAppendBasicBlockInContext(context, s.llvmRef, "local_decls");
288
+        defbuilder = LLVMCreateBuilderInContext(context);
289
+        LLVMPositionBuilderAtEnd(defbuilder, defs);
290
+        auto start = LLVMAppendBasicBlockInContext(context, s.llvmRef, "start");
291
+        builder = LLVMCreateBuilderInContext(context);
292
+        LLVMPositionBuilderAtEnd(builder, start);
293
+
294
+        tracef(
295
+                "function %s: built start and local decls blocks; body has %s items",
296
+                s.name,
297
+                s.fnBody.statements.length);
298
+        visit(cast(SemNode)s.fnBody);
299
+        visitChildren(s);
300
+        tracef("function %s: finished function body", s.name);
301
+
302
+        LLVMBuildRetVoid(builder);
303
+
304
+        LLVMBuildBr(defbuilder, start);
305
+        LLVMDisposeBuilder(defbuilder);
306
+        LLVMDisposeBuilder(builder);
307
+    }
308
+
309
+    override bool before(SemNode s)
310
+    {
311
+        tracef("fnbody: about to visit %s", s);
312
+        return true;
313
+    }
314
+
315
+    override void after(SemNode s)
316
+    {
317
+        tracef("fnbody: visited %s", s);
318
+    }
319
+
320
+    override void visit(ReturnStatement s)
321
+    {
322
+        tracef("visiting return statement");
323
+        if (s.expr is null || s.expr.type is BuiltinType.unit)
324
+        {
325
+            tracef("return unit");
326
+            LLVMBuildRetVoid(builder);
327
+        }
328
+        else
329
+        {
330
+            tracef("return %s", s.expr);
331
+            visit(s.expr);
332
+            LLVMBuildRet(builder, s.expr.llvmRef);
333
+        }
334
+    }
335
+
336
+    override void visit(IntLiteral s)
337
+    {
338
+        if (s.llvmType is null)
339
+        {
340
+            s.llvmType = s.type.llvmType;
341
+        }
342
+        if (s.llvmType is null)
343
+        {
344
+            s.llvmType = BuiltinType.int64.llvmType;
345
+        }
346
+        s.llvmRef = LLVMConstInt(s.llvmType, s.value, true);
347
+    }
348
+
349
+    override void visit(OperatorExpr s)
350
+    {
351
+        visitChildren(s);
352
+        auto intType = cast(IntType)s.type;
353
+        auto ip = cast(LLVMIntPredicate)0;
354
+        auto up = cast(LLVMIntPredicate)0;
355
+        auto fp = cast(LLVMRealPredicate)0;
356
+        auto isComp = true;
357
+        switch (s.op)
358
+        {
359
+            case Tok.eq:
360
+                fp = LLVMRealOEQ;
361
+                ip = LLVMIntEQ;
362
+                up = LLVMIntEQ;
363
+                break;
364
+            case Tok.notEq:
365
+                fp = LLVMRealONE;
366
+                ip = LLVMIntNE;
367
+                up = LLVMIntNE;
368
+                break;
369
+            case Tok.less:
370
+                fp = LLVMRealOLT;
371
+                ip = LLVMIntSLT;
372
+                up = LLVMIntULT;
373
+                break;
374
+            case Tok.lessEq:
375
+                fp = LLVMRealOLE;
376
+                ip = LLVMIntSLE;
377
+                up = LLVMIntULE;
378
+                break;
379
+            case Tok.greater:
380
+                fp = LLVMRealOGT;
381
+                ip = LLVMIntSGT;
382
+                up = LLVMIntUGT;
383
+                break;
384
+            case Tok.greaterEq:
385
+                fp = LLVMRealOGE;
386
+                ip = LLVMIntSGE;
387
+                up = LLVMIntUGE;
388
+                break;
389
+            default:
390
+                isComp = false;
391
+                break;
392
+        }
393
+        if (isComp)
394
+        {
395
+            if (intType)
396
+            {
397
+                auto op = intType.signed ? ip : up;
398
+                s.llvmRef = LLVMBuildICmp(builder, ip, s.lhs.llvmRef, s.rhs.llvmRef, makeTempName);
399
+            }
400
+            else
401
+            {
402
+                s.llvmRef = LLVMBuildFCmp(builder, fp, s.lhs.llvmRef, s.rhs.llvmRef, makeTempName);
403
+            }
404
+        }
405
+
406
+        switch (s.op)
407
+        {
408
+            case Tok.bitOr:
409
+            case Tok.logicOr:
410
+                s.llvmRef = LLVMBuildOr(builder, s.lhs.llvmRef, s.rhs.llvmRef, makeTempName);
411
+                break;
412
+            case Tok.logicAnd:
413
+            case Tok.bitAnd:
414
+                s.llvmRef = LLVMBuildAnd(builder, s.lhs.llvmRef, s.rhs.llvmRef, makeTempName);
415
+                break;
416
+            case Tok.times:
417
+                if (intType)
418
+                    s.llvmRef = LLVMBuildMul(builder, s.lhs.llvmRef, s.rhs.llvmRef, makeTempName);
419
+                else
420
+                    s.llvmRef = LLVMBuildFMul(builder, s.lhs.llvmRef, s.rhs.llvmRef, makeTempName);
421
+                break;
422
+            case Tok.divide:
423
+                if (intType && intType.signed)
424
+                    s.llvmRef = LLVMBuildSDiv(builder, s.lhs.llvmRef, s.rhs.llvmRef, makeTempName);
425
+                else if (intType)
426
+                    s.llvmRef = LLVMBuildUDiv(builder, s.lhs.llvmRef, s.rhs.llvmRef, makeTempName);
427
+                else
428
+                    s.llvmRef = LLVMBuildFDiv(builder, s.lhs.llvmRef, s.rhs.llvmRef, makeTempName);
429
+                break;
430
+            case Tok.plus:
431
+                if (intType)
432
+                    s.llvmRef = LLVMBuildAdd(builder, s.lhs.llvmRef, s.rhs.llvmRef, makeTempName);
433
+                else
434
+                    s.llvmRef = LLVMBuildFAdd(builder, s.lhs.llvmRef, s.rhs.llvmRef, makeTempName);
435
+                break;
436
+            case Tok.minus:
437
+                if (intType)
438
+                    s.llvmRef = LLVMBuildSub(builder, s.lhs.llvmRef, s.rhs.llvmRef, makeTempName);
439
+                else
440
+                    s.llvmRef = LLVMBuildFSub(builder, s.lhs.llvmRef, s.rhs.llvmRef, makeTempName);
441
+                break;
442
+            default:
443
+                import std.conv : to;
444
+                assert(false, "unhandled binary operator " ~ s.op.to!string);
445
+                break;
446
+        }
447
+    }
448
+
449
+    uint tempCount = 0;
450
+    immutable(char)* makeTempName()
451
+    {
452
+        tempCount++;
453
+        import std.conv : to;
454
+        return ("tmp" ~ tempCount.to!string).toStringz;
455
+    }
456
+
457
+    // TODO either explicitly lower loops or handle loop-bound variables (like foreach)
458
+    override void visit(VarDecl s)
459
+    {
460
+        import petal.frontend.errors;
461
+        auto t = s.type;
462
+        if (t is null || t is BuiltinType.invalid)
463
+            throw new InternalCompilerError(
464
+                    "no type for variable declaration "
465
+                    ~ s.name
466
+                    ~ " at "
467
+                    ~ s.loc.toString);
468
+        if (t.llvmType is null)
469
+            throw new InternalCompilerError(
470
+                    "no LLVM type for variable type "
471
+                    ~ t.name
472
+                    ~ " declaration "
473
+                    ~ s.name
474
+                    ~ " at "
475
+                    ~ s.loc.toString);
476
+        tracef("LLVMBuildAlloca: builder=%x llvmtype=%x name=%s", defbuilder, t.llvmType, s.name);
477
+        s.llvmRef = LLVMBuildAlloca(defbuilder, t.llvmType, ("%" ~ s.name).toStringz);
478
+    }
479
+}

+ 15
- 0
dpetalc/test/lex/test_class_with_funcs.petal View File

@@ -0,0 +1,15 @@
1
+namespace test_class_with_funcs.
2
+# Classes can contain functions.
3
+
4
+class A
5
+{
6
+    fn thing1 int i, string f -> string
7
+    {
8
+        return "pistil".
9
+    }
10
+
11
+    fn thing2 int a, int b -> string
12
+    {
13
+        return "anther".
14
+    }
15
+}

+ 63
- 0
genlogo.d View File

@@ -0,0 +1,63 @@
1
+module genlogo;
2
+
3
+import std.experimental.all;
4
+
5
+void main()
6
+{
7
+    foreach (i; 1..20)
8
+    {
9
+        draw(i);
10
+    }
11
+}
12
+
13
+void draw(int numPetals)
14
+{
15
+    enum pi = 3.1415927;
16
+    auto dim = 256;
17
+    auto center = 196;
18
+    auto o = File("petal%s.svg".format(numPetals), "w");
19
+    o.writefln(`<svg width="%s" height="%s">
20
+  <defs>
21
+    <radialGradient id="pinky">
22
+      <stop stop-color="#b3879d" offset="0%%"/>
23
+      <stop stop-color="#d8a4be" offset="50%%"/>
24
+      <stop stop-color="#e2bace" offset="90%%"/>
25
+    </radialGradient>
26
+  </defs>
27
+  <polygon stroke="#3c2631" fill="url(#pinky)" points="%s,%s`, center * 2,  center * 2, center, center);
28
+    // We have five petals. Their points are balanced at the five directions: top, top-right,
29
+    // low-right, low-left, top-left.
30
+    auto radius = (dim / 2) - (dim / 30);
31
+    // 90% of the circle is divided between the petals, and there are five petals.
32
+    auto innerRadius = dim / 9;
33
+    auto midRadius = dim * 0.75;
34
+    auto petalCoverage = 0.95;
35
+    auto margin = (1 - petalCoverage) / numPetals * 2 * pi;
36
+    auto perPetal = petalCoverage / numPetals;
37
+    auto petalWidth = 2 * pi / numPetals;
38
+
39
+    void writePoint(double radians, double radius)
40
+    {
41
+        auto x = sin(radians) * radius;
42
+        auto y = cos(radians) * radius;
43
+        o.writefln(" %s,%s", x + center, y + center);
44
+    }
45
+    foreach (i; 0 .. numPetals)
46
+    {
47
+        auto d1 = petalWidth * i + margin;
48
+        writefln("%s: %s", i, d1);
49
+        auto d2 = d1 + petalWidth - 2 * margin;
50
+        auto d3 = d1 + (d2 - d1) / 2;
51
+        writePoint(d3, innerRadius);
52
+        writePoint(d1, radius);
53
+        writePoint(d3, midRadius);
54
+        writePoint(d2, radius);
55
+        writePoint(d3, innerRadius);
56
+    }
57
+    o.writefln(` %1$s,%1$s" />
58
+  <circle fill="#ac7ba8" stroke="#3c2631" cx="%1$s" cy="%1$s" r="%2$s" />`, center, dim / 6);
59
+    o.writefln(`<circle fill="#665683" cx="%s" cy="%s" r="%s" />
60
+</svg>`, center, center, dim / 10);
61
+    o.flush;
62
+    o.close;
63
+}