Skip to content

Commit

Permalink
Fix the bugs brought by opaque-pointers in LLVM.
Browse files Browse the repository at this point in the history
  • Loading branch information
XChy committed Aug 3, 2023
1 parent 41ac28a commit 90b2c4e
Show file tree
Hide file tree
Showing 11 changed files with 382 additions and 47 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/c-cpp.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ jobs:
steps:
- uses: actions/checkout@v3
- name: Install LLVM
run: sudo apt install llvm-dev
run: sudo apt install llvm-15
- name: CMake Configure
run: cmake .
- name: Build
Expand Down
28 changes: 15 additions & 13 deletions LLVMIR/ClassProxy/IndexProxy.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
#include "IndexProxy.h"
#include <llvm/IR/Constants.h>
#include <llvm/IR/Value.h>
#include "LLVMIR/CodeGenHelper.h"
#include "LLVMIR/LLVMTypes.h"
Expand All @@ -11,40 +12,41 @@ using namespace XSharp::LLVMCodeGen;
using namespace XSharp;

ValueAndType CodeGenProxy<IndexNode>::codeGen(IndexNode *ast,
CodeGenContext *helper,
CodeGenContext *ctx,
const Generator &generator)
{
using llvm::ConstantInt;
auto [index, index_type] = generator(ast->index());

auto [indexed, indexed_type] =
deReference(generator(ast->operand()), helper);
deReference(generator(ast->operand()), ctx);

if (!indexed_type->isArray()) {
helper->error("Cannot get the element of non-array");
ctx->error("Cannot get the element of non-array");
return {nullptr, nullptr};
}

index = TypeAdapter::llvmConvert(index_type, Types::get("i64"), index);

if (!index) {
helper->error("Cannot convert '{}' to '{}'", index_type->typeName(),
ctx->error("Cannot convert '{}' to '{}'", index_type->typeName(),
Types::get("i64")->typeName());

helper->error("Index must be an integer");
ctx->error("Index must be an integer");
return {nullptr, nullptr};
}

auto array_struct_type = indexed->getType()->getContainedType(0);
auto PtrTy = indexed->getType();

llvm::Value *element_ptr_ptr =
helper->llvm_builder.CreateStructGEP(array_struct_type, indexed, 1);
llvm::Value *element_ptr_ptr = ctx->llvm_builder.CreateStructGEP(
structForArray(ctx->llvm_ctx), indexed, 1);

llvm::Value *element_ptr_head = helper->llvm_builder.CreateLoad(
element_ptr_ptr->getType()->getContainedType(0), element_ptr_ptr);
llvm::Value *element_ptr_head =
ctx->llvm_builder.CreateLoad(PtrTy, element_ptr_ptr);

llvm::Value *element = helper->llvm_builder.CreateInBoundsGEP(
element_ptr_head->getType()->getContainedType(0), element_ptr_head,
index, ast->dump().toStdString());
llvm::Value *element = ctx->llvm_builder.CreateGEP(
castToLLVM(indexed_type->elementType(), ctx->llvm_ctx),
element_ptr_head, index, ast->dump().toStdString());

return {element, getReferenceType(indexed_type->elementType())};
}
4 changes: 2 additions & 2 deletions LLVMIR/ClassProxy/MemberExprProxy.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,10 +36,10 @@ ValueAndType CodeGenProxy<MemberExprNode>::codeGen(MemberExprNode *ast,
} else if (obj_type->isArray()) {
if (ast->memberName() == "length") {
llvm::Value *length_ptr = helper->llvm_builder.CreateStructGEP(
obj->getType()->getContainedType(0), obj, 0);
structForArray(helper->llvm_ctx), obj, 0);

llvm::Value *length = helper->llvm_builder.CreateLoad(
length_ptr->getType()->getContainedType(0), length_ptr);
castToLLVM(getI64Type(), helper->llvm_ctx), length_ptr);
return {deReference({length, XSharp::getI32Type()}, helper)};
}
}
Expand Down
29 changes: 11 additions & 18 deletions LLVMIR/CodeGenProxy.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -66,40 +66,33 @@ ValueAndType CodeGenProxy<CharNode>::codeGen(CharNode* ast,
}

ValueAndType CodeGenProxy<StringNode>::codeGen(StringNode* ast,
CodeGenContext* helper,
CodeGenContext* ctx,
const Generator& generator)
{
auto x_array_type = XSharp::getArrayType(Types::get("char"), 1);
auto llvm_array_type = castToLLVM(x_array_type, helper->llvm_ctx);

llvm::StructType* array_struct_type =
(llvm::StructType*)llvm_array_type->getContainedType(0);

llvm::ArrayType* array_data_type = llvm::ArrayType::get(
castToLLVM(x_array_type->elementType(), helper->llvm_ctx),
ast->value().size());
auto eltTy = castToLLVM(x_array_type->elementType(), ctx->llvm_ctx);

std::vector<llvm::Constant*> chars;

for (int i = 0; i < ast->value().size(); ++i) {
chars.push_back(helper->llvm_builder.getInt(
llvm::APInt(16, ast->value()[i].value())));
chars.push_back(
ctx->llvm_builder.getInt(llvm::APInt(16, ast->value()[i].value())));
}

llvm::ConstantInt* length_data = llvm::ConstantInt::get(
helper->llvm_ctx, llvm::APInt(64, ast->value().size()));
ctx->llvm_ctx, llvm::APInt(64, ast->value().size()));

llvm::Constant* chars_data =
llvm::ConstantArray::get(array_data_type, chars);
llvm::Constant* chars_data = llvm::ConstantArray::get(
llvm::ArrayType::get(eltTy, chars.size()), chars);
llvm::GlobalVariable* glob_chars = new llvm::GlobalVariable(
helper->module, chars_data->getType(), true,
ctx->module, chars_data->getType(), true,
llvm::GlobalValue::ExternalLinkage, chars_data);

llvm::Constant* array_data =
llvm::ConstantStruct::get(array_struct_type, {length_data, glob_chars});
llvm::Constant* array_data = llvm::ConstantStruct::get(
structForArray(ctx->llvm_ctx), {length_data, glob_chars});

llvm::GlobalVariable* glob = new llvm::GlobalVariable(
helper->module, array_data->getType(), true,
ctx->module, array_data->getType(), true,
llvm::GlobalValue::ExternalLinkage, array_data);

return {glob, XSharp::getArrayType(Types::get("char"), 1)};
Expand Down
22 changes: 10 additions & 12 deletions LLVMIR/LLVMTypes.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -59,14 +59,7 @@ llvm::Type* castToLLVM(XSharp::Type* type, llvm::LLVMContext& context)
case Type::Array: {
// Allocate XSharp's array on heap
// So the type of array is the pointer type of its element
auto pointerToElements = llvm::PointerType::get(
castToLLVM(type->elementType(), context), 0);

auto structType = llvm::StructType::get(
context,
std::vector<llvm::Type*>{castToLLVM(getI64Type(), context),
pointerToElements});
return structType->getPointerTo();
return llvm::PointerType::get(context, 0);
}

case Type::Class: {
Expand All @@ -76,24 +69,29 @@ llvm::Type* castToLLVM(XSharp::Type* type, llvm::LLVMContext& context)
llvmTypes.push_back(
llvm::Type::getIntNTy(context, sizeof(uintptr_t) * 8));

for (auto fieid : type->getClassDecl()->dataFields) {
for (auto fieid : type->getClassDecl()->dataFields)
llvmTypes.push_back(castToLLVM(fieid.type, context));
}

auto structType = llvm::StructType::get(context, llvmTypes);
return structType;
}

case Type::Closure:
break;

case Type::Reference:
return castToLLVM(type->derefType(), context)->getPointerTo();
return llvm::PointerType::get(context, 0);
default:
return nullptr;
}

return nullptr;
}

llvm::StructType* structForArray(llvm::LLVMContext& context)
{
return llvm::StructType::get(context,
{castToLLVM(getArrayLenType(), context),
llvm::PointerType::get(context, 0)});
}
} // namespace LLVMCodeGen
} // namespace XSharp
3 changes: 3 additions & 0 deletions LLVMIR/LLVMTypes.h
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
#pragma once
#include <llvm/IR/DerivedTypes.h>
#include <llvm/IR/Type.h>
#include <llvm/IR/LLVMContext.h>
#include <llvm/IR/Function.h>
Expand All @@ -12,5 +13,7 @@ namespace LLVMCodeGen {

llvm::Type* castToLLVM(XSharp::Type* type, llvm::LLVMContext& context);

llvm::StructType* structForArray(llvm::LLVMContext& context);

}
} // namespace XSharp
2 changes: 1 addition & 1 deletion LLVMIR/Utils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ llvm::Value* genArrayMalloc(CodeGenContext* helper, XSharp::Type* type,
castToLLVM(type->elementType(), context)->getPointerTo(),
{llvm::Type::getInt64Ty(context)}, false));

auto array_struct_type = castToLLVM(type, context)->getContainedType(0);
auto array_struct_type = structForArray(helper->llvm_ctx);

if (type->isArray()) {
llvm::Value* sizeofElement = llvm::ConstantInt::get(
Expand Down
145 changes: 145 additions & 0 deletions LLVMIR/test/class.xsharp.ll
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
; ModuleID = 'XSharp'
source_filename = "XSharp"
target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
target triple = "x86_64-pc-linux-gnu"

@0 = constant [15 x i16] [i16 65, i16 118, i16 101, i16 114, i16 97, i16 103, i16 101, i16 32, i16 97, i16 103, i16 101, i16 32, i16 105, i16 115, i16 58]
@1 = constant { i64, ptr } { i64 15, ptr @0 }

declare i8 @printI32(i32)

declare i8 @printI64(i64)

declare i8 @printChar(i16)

declare i8 @printStr(ptr)

declare i8 @printBoolean(i1)

declare i8 @printDouble(double)

declare i32 @inputI32()

define void @setAge(ptr %self, i32 %age) {
entry:
%self.age = getelementptr inbounds { i64, i32 }, ptr %self, i64 0, i32 1
store i32 %age, ptr %self.age, align 4
ret void
}

define i32 @getAge(ptr %self) {
entry:
%self.age = getelementptr inbounds { i64, i32 }, ptr %self, i64 0, i32 1
%0 = load i32, ptr %self.age, align 4
ret i32 %0
}

define ptr @"Foo:new"() {
entry:
%0 = tail call { i64, i32 } @GC_new_object(i64 12)
%.fca.0.extract = extractvalue { i64, i32 } %0, 0
%1 = inttoptr i64 %.fca.0.extract to ptr
%self.age = getelementptr inbounds { i64, i32 }, ptr %1, i64 0, i32 1
store i32 0, ptr %self.age, align 4
ret ptr %1
}

declare { i64, i32 } @GC_new_object(i64)

define ptr @"Foo:new.1"(i32 %a) {
entry:
%0 = tail call { i64, i32 } @GC_new_object(i64 12)
%.fca.0.extract = extractvalue { i64, i32 } %0, 0
%1 = inttoptr i64 %.fca.0.extract to ptr
%self.age = getelementptr inbounds { i64, i32 }, ptr %1, i64 0, i32 1
store i32 %a, ptr %self.age, align 4
ret ptr %1
}

define i32 @main() {
entry:
%n = alloca i64, align 8
%0 = call i32 @inputI32()
%1 = sext i32 %0 to i64
store i64 %1, ptr %n, align 8
%c = alloca ptr, align 8
%2 = load i64, ptr %n, align 8
%3 = mul i64 %2, 8
%4 = alloca { i64, ptr }, align 8
%5 = call ptr @GC_new_object(i64 %3)
%6 = getelementptr inbounds { i64, ptr }, ptr %4, i32 0, i32 0
%7 = getelementptr inbounds { i64, ptr }, ptr %4, i32 0, i32 1
store i64 %2, ptr %6, align 8
store ptr %5, ptr %7, align 8
store ptr %4, ptr %c, align 8
%i = alloca i64, align 8
%8 = load i64, ptr %n, align 8
store i64 %8, ptr %i, align 8
br label %while.cond

while.cond: ; preds = %while.body, %entry
%9 = load i64, ptr %i, align 8
%10 = sub i64 %9, 1
%11 = icmp sge i64 %10, 0
br i1 %11, label %while.body, label %while.end

while.body: ; preds = %while.cond
%12 = load i64, ptr %i, align 8
%13 = sub i64 %12, 1
%14 = load ptr, ptr %c, align 8
%15 = getelementptr inbounds { i64, ptr }, ptr %14, i32 0, i32 1
%16 = load ptr, ptr %15, align 8
%"[i] - [1] in c" = getelementptr ptr, ptr %16, i64 %13
%17 = call i32 @inputI32()
%18 = call { i64, i32 } @GC_new_object(i64 12)
%.fca.0.extract.i = extractvalue { i64, i32 } %18, 0
%19 = inttoptr i64 %.fca.0.extract.i to ptr
%self.age.i = getelementptr inbounds { i64, i32 }, ptr %19, i64 0, i32 1
store i32 %17, ptr %self.age.i, align 4
store ptr %19, ptr %"[i] - [1] in c", align 8
%20 = load i64, ptr %i, align 8
%21 = sub i64 %20, 1
store i64 %21, ptr %i, align 8
br label %while.cond

while.end: ; preds = %while.cond
%sum = alloca double, align 8
store double 0.000000e+00, ptr %sum, align 8
%22 = load i64, ptr %n, align 8
store i64 %22, ptr %i, align 8
br label %while.cond1

while.cond1: ; preds = %while.body2, %while.end
%23 = load i64, ptr %i, align 8
%24 = sub i64 %23, 1
%25 = icmp sge i64 %24, 0
br i1 %25, label %while.body2, label %while.end4

while.body2: ; preds = %while.cond1
%26 = load double, ptr %sum, align 8
%27 = load i64, ptr %i, align 8
%28 = sub i64 %27, 1
%29 = load ptr, ptr %c, align 8
%30 = getelementptr inbounds { i64, ptr }, ptr %29, i32 0, i32 1
%31 = load ptr, ptr %30, align 8
%"[i] - [1] in c3" = getelementptr ptr, ptr %31, i64 %28
%32 = load ptr, ptr %"[i] - [1] in c3", align 8
%self.age.i5 = getelementptr inbounds { i64, i32 }, ptr %32, i64 0, i32 1
%33 = load i32, ptr %self.age.i5, align 4
%34 = sitofp i32 %33 to double
%35 = fadd double %26, %34
store double %35, ptr %sum, align 8
%36 = load i64, ptr %i, align 8
%37 = sub i64 %36, 1
store i64 %37, ptr %i, align 8
br label %while.cond1

while.end4: ; preds = %while.cond1
%38 = call i8 @printStr(ptr @1)
%39 = load double, ptr %sum, align 8
%40 = load i64, ptr %n, align 8
%41 = sitofp i64 %40 to double
%42 = fdiv double %39, %41
%43 = call i8 @printDouble(double %42)
ret i32 0
}
27 changes: 27 additions & 0 deletions LLVMIR/test/helloworld.xsharp.ll
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
; ModuleID = 'XSharp'
source_filename = "XSharp"
target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
target triple = "x86_64-pc-linux-gnu"

@0 = constant [12 x i16] [i16 72, i16 101, i16 108, i16 108, i16 111, i16 44, i16 87, i16 111, i16 114, i16 108, i16 100, i16 33]
@1 = constant { i64, ptr } { i64 12, ptr @0 }

declare i8 @printI32(i32)

declare i8 @printI64(i64)

declare i8 @printChar(i16)

declare i8 @printStr(ptr)

declare i8 @printBoolean(i1)

declare i8 @printDouble(double)

declare i32 @inputI32()

define void @main() {
entry:
%0 = call i8 @printStr(ptr @1)
ret void
}
Loading

0 comments on commit 90b2c4e

Please sign in to comment.