Skip to content

Commit 2b46409

Browse files
Update llvm backends to use llvm 15 (ballerina-platform#1146)
* patch llvm to use opaque pointers fix jni.llvm code cleanup fix unit tests Fix native image code cleanup * update workflows * Refactor jni.llvm * Code cleanup * update readme * Address review comments
1 parent 22cacc1 commit 2b46409

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

77 files changed

+589
-529
lines changed

.github/workflows/make-test.yml

+9-2
Original file line numberDiff line numberDiff line change
@@ -28,9 +28,16 @@ jobs:
2828
- name: Install LLVM (macOS)
2929
if: runner.os == 'macOS'
3030
run: |
31-
brew install llvm@13
32-
echo "/usr/local/opt/llvm@13/bin" >> $GITHUB_PATH
31+
brew install llvm@15
32+
echo "/usr/local/opt/llvm@15/bin" >> $GITHUB_PATH
3333
echo "LLVM_SUFFIX=" >> $GITHUB_ENV
34+
- name: Install LLVM (linux)
35+
if: runner.os == 'Linux'
36+
run: |
37+
wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key|sudo apt-key add -
38+
sudo add-apt-repository deb http://apt.llvm.org/jammy/ llvm-toolchain-jammy-15 main
39+
sudo apt-get update
40+
sudo apt-get install -y clang-15 llvm-15
3441
- name: Cache jBallerina
3542
id: cache-jbal
3643
uses: actions/cache@v2

Makefile

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
BAL?=bal
2-
LLVM_SUFFIX?=-13
2+
LLVM_SUFFIX?=-15
33
CLANG?=clang$(LLVM_SUFFIX)
44
CFLAGS=-O2
55
JAVA?=$(shell test/findJava.sh)

README.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ The compiler has not yet got to a stage where it is useful. But if you want to p
7979
2. [Download](https://ballerina.io/downloads/) and [install](https://ballerina.io/learn/user-guide/getting-started/installation-options/) the latest Ballerina distribution (Swan Lake not 1.2.x)
8080
3. You can build the compiler by using the command `bal build` in the `compiler` directory; this will generate a file `target/bin/nballerina.jar`. This should work on any system that Ballerina works on.
8181
4. You can use `java -jar nballerina.jar example.bal` to compile a Ballerina module into an LLVM assembly file `example.ll` (note that only a tiny subset of the language is currently implemented, as described in the Status section).
82-
5. If you want to be able to turn the LLVM assembly file into something you can execute, there are additional requirements: Linux or OS X, LLVM 13 and GNU make. With these, you can build the runtime and run the tests by running `make test` in the top-level directory. This compiles and executes all the test cases and checks that they produce the right outputs. You can use e.g. `make -j8` to make it run tests in parallel.
82+
5. If you want to be able to turn the LLVM assembly file into something you can execute, there are additional requirements: Linux or OS X, LLVM 15 and GNU make. With these, you can build the runtime and run the tests by running `make test` in the top-level directory. This compiles and executes all the test cases and checks that they produce the right outputs. You can use e.g. `make -j8` to make it run tests in parallel.
8383

8484
If you want to turn the LLVM assembly into an executable, you can use the [test/run.sh](test/run.sh) command.
8585

compiler/modules/print.llvm/common.bal

100644100755
+24-1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import wso2/nballerina.comm.err;
12
// This contains the common definitions for both print.llvm and jni.llvm
23

34
// "i64" corresponds to LLVMInt64Type
@@ -67,7 +68,7 @@ public function functionType(RetType returnType, Type[] paramTypes) returns Func
6768
// Corresponds to LLVMLinkage enum
6869
public type Linkage "internal"|"external";
6970

70-
public type FunctionEnumAttribute "nofree"|"nosync"|"readnone"|"noreturn"|"cold"|"nounwind"|"readnone"|"readonly"|"speculatable"|"willreturn";
71+
public type FunctionEnumAttribute "nocallback"|"nofree"|"nosync"|"readnone"|"noreturn"|"cold"|"nounwind"|"readnone"|"readonly"|"speculatable"|"willreturn";
7172
public type ParamEnumAttribute "signext"|"zeroext";
7273
public type ReturnEnumAttribute "signext"|"zeroext"|"noalias";
7374
public type EnumAttribute FunctionEnumAttribute | (readonly & [int, ParamEnumAttribute]) | (readonly & ["return", ReturnEnumAttribute]);
@@ -187,3 +188,25 @@ public type PointerTypeMetdataProperties record {|
187188
int addressSpace = 0;
188189
string? name = ();
189190
|};
191+
192+
function getTypeAtIndex(StructType ty, int index, Context context) returns Type {
193+
boolean isNamed = ty.name != ();
194+
Type[] elementTypes = ty.elementTypes;
195+
if isNamed {
196+
elementTypes = context.getNamedStructBody(ty);
197+
}
198+
return elementTypes[index];
199+
}
200+
201+
function sameNumberType(Value v1, Value v2) returns IntType|FloatType {
202+
Type ty1 = v1.ty;
203+
Type ty2 = v2.ty;
204+
if ty1 != ty2 {
205+
panic err:illegalArgument("expected same types");
206+
}
207+
else if ty1 is IntType || ty1 is FloatType {
208+
return ty1;
209+
}
210+
panic err:illegalArgument("expected a number type");
211+
}
212+

compiler/modules/print.llvm/llvm.bal

+31-27
Original file line numberDiff line numberDiff line change
@@ -327,22 +327,21 @@ public class Module {
327327
if name is IntegerArithmeticIntrinsicName {
328328
return self.addIntrinsic(name,
329329
{ returnType: structType(["i64", "i1"]), paramTypes: ["i64", "i64"] },
330-
["nofree", "nosync", "nounwind", "readnone", "speculatable", "willreturn"]);
330+
["nocallback", "nofree", "nosync", "nounwind", "readnone", "speculatable", "willreturn"]);
331331

332332
}
333333
else {
334-
GeneralIntrinsicName _ = name;
335334
return self.addIntrinsic(name,
336335
{ returnType: pointerType("i8", 1), paramTypes: [pointerType("i8", 1), "i64"] },
337-
["nofree", "nosync", "nounwind", "readnone", "speculatable", "willreturn"]);
336+
["nocallback", "nofree", "nosync", "nounwind", "readnone", "speculatable", "willreturn"]);
338337
}
339338
}
340339

341340
function addDebugIntrinsic(DebugIntrinsicName name) {
342341
boolean fnExisting = self.globals[name] != ();
343342
if !fnExisting {
344343
_ = self.addIntrinsic(name, { returnType: "void", paramTypes: ["metadata", "metadata", "metadata"]},
345-
["nofree", "nosync", "nounwind", "readnone", "speculatable", "willreturn"]);
344+
["nocallback","nofree", "nosync", "nounwind", "readnone", "speculatable", "willreturn"]);
346345
}
347346
}
348347

@@ -1535,24 +1534,13 @@ function sameIntegralType(Value v1, Value v2) returns IntegralType {
15351534
panic err:illegalArgument("expected an integral type");
15361535
}
15371536

1538-
function sameNumberType(Value v1, Value v2) returns IntType|FloatType {
1539-
Type ty1 = v1.ty;
1540-
Type ty2 = v2.ty;
1541-
if ty1 != ty2 {
1542-
panic err:illegalArgument("expected same types");
1543-
}
1544-
else if ty1 is IntType || ty1 is FloatType {
1545-
return ty1;
1546-
}
1547-
panic err:illegalArgument("expected a number type");
1548-
}
1549-
15501537
function typeToString(RetType ty, Context context, boolean forceInline=false) returns string {
15511538
if ty is PointerType {
1539+
includeNamedType(ty, context);
15521540
if ty.addressSpace == 0 {
1553-
return typeToString(ty.pointsTo, context) + "*";
1541+
return forceInline ? typeToString(ty.pointsTo, context) : "ptr";
15541542
} else {
1555-
return createLine([typeToString(ty.pointsTo, context), "addrspace", "(", ty.addressSpace.toString(), ")", "*"]);
1543+
return createLine([forceInline ? typeToString(ty.pointsTo, context) : "ptr", "addrspace", "(", ty.addressSpace.toString(), ")"]);
15561544
}
15571545
}
15581546
else if ty is StructType {
@@ -1610,6 +1598,31 @@ function typeToString(RetType ty, Context context, boolean forceInline=false) re
16101598
}
16111599
}
16121600

1601+
// use to mark a named struct type as used (so we include that type in output) when it is referenced via a pointer
1602+
function includeNamedType(RetType ty, Context context) {
1603+
if ty is PointerType {
1604+
includeNamedType(ty.pointsTo, context);
1605+
}
1606+
else if ty is StructType {
1607+
Type[] elementTypes = ty.name == () ? ty.elementTypes : context.getNamedStructBody(ty);
1608+
if ty.name != () {
1609+
return;
1610+
}
1611+
foreach Type element in elementTypes {
1612+
includeNamedType(element, context);
1613+
}
1614+
}
1615+
else if ty is ArrayType {
1616+
includeNamedType(ty.elementType, context);
1617+
}
1618+
else if ty is FunctionType {
1619+
foreach Type paramType in ty.paramTypes {
1620+
includeNamedType(paramType, context);
1621+
}
1622+
includeNamedType(ty.returnType, context);
1623+
}
1624+
}
1625+
16131626
class Output {
16141627
final string[] lines = [];
16151628

@@ -1780,15 +1793,6 @@ function gepArgs((string|Unnamed)[] words, Value ptr, Value[] indices, "inbounds
17801793
return pointerType(resultType, resultAddressSpace);
17811794
}
17821795

1783-
function getTypeAtIndex(StructType ty, int index, Context context) returns Type {
1784-
boolean isNamed = ty.name != ();
1785-
Type[] elementTypes = ty.elementTypes;
1786-
if isNamed {
1787-
elementTypes = context.getNamedStructBody(ty);
1788-
}
1789-
return elementTypes[index];
1790-
}
1791-
17921796
function bitCastArgs((string|Unnamed)[] words, Value val, PointerType destTy, Context context) {
17931797
words.push(typeToString(val.ty, context), val.operand, "to", typeToString(destTy, context));
17941798
}
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
declare i64 addrspace(3)* @genFn()
2-
define i64* @main() {
3-
%1 = call i64 addrspace(3)* @genFn()
4-
%2 = addrspacecast i64 addrspace(3)* %1 to i64*
5-
ret i64* %2
1+
declare ptr addrspace(3) @genFn()
2+
define ptr @main() {
3+
%1 = call ptr addrspace(3) @genFn()
4+
%2 = addrspacecast ptr addrspace(3) %1 to ptr
5+
ret ptr %2
66
}
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
@g = internal addrspace(1) global i64 5
2-
@a = alias i64, i64 addrspace(1)* @g
3-
@b = internal alias i64, i64 addrspace(1)* @g
4-
@c = internal unnamed_addr alias i64, i64 addrspace(1)* @g
5-
@d = unnamed_addr alias i64, i64 addrspace(1)* @g
2+
@a = alias i64, ptr addrspace(1) @g
3+
@b = internal alias i64, ptr addrspace(1) @g
4+
@c = internal unnamed_addr alias i64, ptr addrspace(1) @g
5+
@d = unnamed_addr alias i64, ptr addrspace(1) @g
66
define i64 @main() {
7-
%1 = load i64, i64 addrspace(1)* @a
7+
%1 = load i64, ptr addrspace(1) @a
88
ret i64 %1
99
}
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
define i64* @foo(i8* %0) {
2-
%2 = bitcast i8* %0 to i64*
3-
ret i64* %2
1+
define ptr @foo(ptr %0) {
2+
%2 = bitcast ptr %0 to ptr
3+
ret ptr %2
44
}
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
@g1 = external constant {i64, i32, i8}
2-
@g2 = global i64* getelementptr inbounds({i64, i32, i8}, {i64, i32, i8}* @g1, i32 0, i32 0)
3-
@g3 = global i32* bitcast(i64** @g2 to i32*)
4-
@g4 = external constant i32*
5-
@g5 = global i32 addrspace(1)* addrspacecast(i32** @g4 to i32 addrspace(1)*)
2+
@g2 = global ptr getelementptr inbounds({i64, i32, i8}, ptr @g1, i32 0, i32 0)
3+
@g3 = global ptr bitcast(ptr @g2 to ptr)
4+
@g4 = external constant ptr
5+
@g5 = global ptr addrspace(1) addrspacecast(ptr @g4 to ptr addrspace(1))

compiler/modules/print.llvm/tests/testOutputs/const_ptr_to_int.ll

+2-2
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@
22
@g1 = external global i64
33
@g2 = external global %st
44
define i32 @main() {
5-
ret i32 ptrtoint(i64* @g1 to i32)
5+
ret i32 ptrtoint(ptr @g1 to i32)
66
}
77
define i32 @test() {
8-
ret i32 ptrtoint(%st* @g2 to i32)
8+
ret i32 ptrtoint(ptr @g2 to i32)
99
}

compiler/modules/print.llvm/tests/testOutputs/debug_val.ll

+9-9
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,18 @@
1-
declare void @llvm.dbg.declare(metadata, metadata, metadata) nofree nosync nounwind readnone speculatable willreturn
2-
declare void @llvm.dbg.value(metadata, metadata, metadata) nofree nosync nounwind readnone speculatable willreturn
1+
declare void @llvm.dbg.declare(metadata, metadata, metadata) nocallback nofree nosync nounwind readnone speculatable willreturn
2+
declare void @llvm.dbg.value(metadata, metadata, metadata) nocallback nofree nosync nounwind readnone speculatable willreturn
33
define i64 @main() !dbg !6 {
44
%1 = alloca i64, !dbg !18
55
%2 = alloca i64, !dbg !18
6-
%3 = alloca i8 addrspace(1)*, !dbg !18
7-
call void @llvm.dbg.declare(metadata i64* %2, metadata !11, metadata !16), !dbg !18
8-
call void @llvm.dbg.declare(metadata i8 addrspace(1)** %3, metadata !15, metadata !16), !dbg !18
9-
store i64 10, i64* %1, !dbg !18
10-
store i64 15, i64* %2, !dbg !18
6+
%3 = alloca ptr addrspace(1), !dbg !18
7+
call void @llvm.dbg.declare(metadata ptr %2, metadata !11, metadata !16), !dbg !18
8+
call void @llvm.dbg.declare(metadata ptr %3, metadata !15, metadata !16), !dbg !18
9+
store i64 10, ptr %1, !dbg !18
10+
store i64 15, ptr %2, !dbg !18
1111
call void @llvm.dbg.value(metadata i64 10, metadata !9, metadata !16), !dbg !18
12-
%4 = load i64, i64* %1, !dbg !19
12+
%4 = load i64, ptr %1, !dbg !19
1313
%5 = add i64 %4, 1, !dbg !19
1414
call void @llvm.dbg.value(metadata i64 %5, metadata !9, metadata !16), !dbg !19
15-
store i64 20, i64* %2, !dbg !19
15+
store i64 20, ptr %2, !dbg !19
1616
ret i64 %5, !dbg !20
1717
}
1818
!llvm.dbg.cu = !{!1}

compiler/modules/print.llvm/tests/testOutputs/expr_binary_add.ll

+5-5
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
1-
declare {i64, i1} @llvm.sadd.with.overflow.i64.i64(i64, i64) nofree nosync nounwind readnone speculatable willreturn
1+
declare {i64, i1} @llvm.sadd.with.overflow.i64.i64(i64, i64) nocallback nofree nosync nounwind readnone speculatable willreturn
22
define void @abort() {
33
}
44
define i64 @foo(i64 %0, i64 %1) {
55
%3 = alloca i64
66
%4 = alloca i64
7-
store i64 %0, i64* %3
8-
store i64 %1, i64* %4
9-
%5 = load i64, i64* %3
10-
%6 = load i64, i64* %4
7+
store i64 %0, ptr %3
8+
store i64 %1, ptr %4
9+
%5 = load i64, ptr %3
10+
%6 = load i64, ptr %4
1111
%7 = call {i64, i1} @llvm.sadd.with.overflow.i64.i64(i64 %5, i64 %6)
1212
%8 = extractvalue {i64, i1} %7, 0
1313
%9 = extractvalue {i64, i1} %7, 1

compiler/modules/print.llvm/tests/testOutputs/expr_binary_div.ll

+7-7
Original file line numberDiff line numberDiff line change
@@ -3,24 +3,24 @@ define void @abort() {
33
define i64 @foo(i64 %0, i64 %1) {
44
%3 = alloca i64
55
%4 = alloca i64
6-
store i64 %0, i64* %3
7-
store i64 %1, i64* %4
8-
%5 = load i64, i64* %4
6+
store i64 %0, ptr %3
7+
store i64 %1, ptr %4
8+
%5 = load i64, ptr %4
99
%6 = icmp eq i64 %5, 0
1010
br i1 %6, label %13, label %7
1111
7:
12-
%8 = load i64, i64* %3
12+
%8 = load i64, ptr %3
1313
%9 = icmp eq i64 %8, -9223372036854775808
1414
br i1 %9, label %10, label %14
1515
10:
16-
%11 = load i64, i64* %4
16+
%11 = load i64, ptr %4
1717
%12 = icmp eq i64 %11, -1
1818
br i1 %12, label %13, label %14
1919
13:
2020
call void @abort()
2121
14:
22-
%15 = load i64, i64* %3
23-
%16 = load i64, i64* %4
22+
%15 = load i64, ptr %3
23+
%16 = load i64, ptr %4
2424
%17 = sdiv i64 %15, %16
2525
ret i64 %17
2626
}

compiler/modules/print.llvm/tests/testOutputs/expr_binary_mul.ll

+5-5
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
1-
declare {i64, i1} @llvm.smul.with.overflow.i64.i64(i64, i64) nofree nosync nounwind readnone speculatable willreturn
1+
declare {i64, i1} @llvm.smul.with.overflow.i64.i64(i64, i64) nocallback nofree nosync nounwind readnone speculatable willreturn
22
define void @abort() {
33
}
44
define i64 @foo(i64 %0, i64 %1) {
55
%3 = alloca i64
66
%4 = alloca i64
7-
store i64 %0, i64* %3
8-
store i64 %1, i64* %4
9-
%5 = load i64, i64* %3
10-
%6 = load i64, i64* %4
7+
store i64 %0, ptr %3
8+
store i64 %1, ptr %4
9+
%5 = load i64, ptr %3
10+
%6 = load i64, ptr %4
1111
%7 = call {i64, i1} @llvm.smul.with.overflow.i64.i64(i64 %5, i64 %6)
1212
%8 = extractvalue {i64, i1} %7, 0
1313
%9 = extractvalue {i64, i1} %7, 1

compiler/modules/print.llvm/tests/testOutputs/expr_binary_remainder.ll

+10-10
Original file line numberDiff line numberDiff line change
@@ -4,31 +4,31 @@ define i64 @foo(i64 %0, i64 %1) {
44
%3 = alloca i64
55
%4 = alloca i64
66
%5 = alloca i64
7-
store i64 %0, i64* %4
8-
store i64 %1, i64* %5
9-
%6 = load i64, i64* %5
7+
store i64 %0, ptr %4
8+
store i64 %1, ptr %5
9+
%6 = load i64, ptr %5
1010
%7 = icmp eq i64 %6, 0
1111
br i1 %7, label %8, label %9
1212
8:
1313
call void @abort()
1414
9:
15-
%10 = load i64, i64* %4
15+
%10 = load i64, ptr %4
1616
%11 = icmp eq i64 %10, -9223372036854775808
1717
br i1 %11, label %16, label %12
1818
12:
19-
%13 = load i64, i64* %4
20-
%14 = load i64, i64* %5
19+
%13 = load i64, ptr %4
20+
%14 = load i64, ptr %5
2121
%15 = srem i64 %13, %14
22-
store i64 %15, i64* %3
22+
store i64 %15, ptr %3
2323
br label %20
2424
16:
25-
%17 = load i64, i64* %5
25+
%17 = load i64, ptr %5
2626
%18 = icmp eq i64 %17, -1
2727
br i1 %18, label %19, label %12
2828
19:
29-
store i64 0, i64* %3
29+
store i64 0, ptr %3
3030
br label %20
3131
20:
32-
%21 = load i64, i64* %3
32+
%21 = load i64, ptr %3
3333
ret i64 %21
3434
}

compiler/modules/print.llvm/tests/testOutputs/expr_binary_sub.ll

+5-5
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
1-
declare {i64, i1} @llvm.ssub.with.overflow.i64.i64(i64, i64) nofree nosync nounwind readnone speculatable willreturn
1+
declare {i64, i1} @llvm.ssub.with.overflow.i64.i64(i64, i64) nocallback nofree nosync nounwind readnone speculatable willreturn
22
define void @abort() {
33
}
44
define i64 @foo(i64 %0, i64 %1) {
55
%3 = alloca i64
66
%4 = alloca i64
7-
store i64 %0, i64* %3
8-
store i64 %1, i64* %4
9-
%5 = load i64, i64* %3
10-
%6 = load i64, i64* %4
7+
store i64 %0, ptr %3
8+
store i64 %1, ptr %4
9+
%5 = load i64, ptr %3
10+
%6 = load i64, ptr %4
1111
%7 = call {i64, i1} @llvm.ssub.with.overflow.i64.i64(i64 %5, i64 %6)
1212
%8 = extractvalue {i64, i1} %7, 0
1313
%9 = extractvalue {i64, i1} %7, 1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
@g1 = external global {i32, i64(i8, i64)*}
2-
@g2 = external global i64(i8, i64)*
3-
@g3 = global i8(i64)* @otherFn
1+
@g1 = external global {i32, ptr}
2+
@g2 = external global ptr
3+
@g3 = global ptr @otherFn
44
declare i8 @otherFn(i64)

0 commit comments

Comments
 (0)