Skip to content

Commit

Permalink
Lower global variables
Browse files Browse the repository at this point in the history
  • Loading branch information
hamphet committed Aug 19, 2024
1 parent 657eda9 commit fd45fee
Show file tree
Hide file tree
Showing 9 changed files with 188 additions and 3 deletions.
1 change: 1 addition & 0 deletions toolchain/lower/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -53,5 +53,6 @@ cc_library(
"//toolchain/sem_ir:inst_namer",
"@llvm-project//llvm:Core",
"@llvm-project//llvm:Support",
"@llvm-project//llvm:TransformUtils",
],
)
34 changes: 31 additions & 3 deletions toolchain/lower/file_context.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
#include "common/vlog.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/Sequence.h"
#include "llvm/Transforms/Utils/ModuleUtils.h"
#include "toolchain/base/kind_switch.h"
#include "toolchain/lower/constant.h"
#include "toolchain/lower/function_context.h"
Expand Down Expand Up @@ -50,7 +51,17 @@ auto FileContext::Run() -> std::unique_ptr<llvm::Module> {
functions_[i] = BuildFunctionDecl(SemIR::FunctionId(i));
}

// TODO: Lower global variable declarations.
// Lower global variable declarations
for (auto inst_id :
sem_ir().inst_blocks().Get(sem_ir().top_inst_block_id())) {
// Only `VarStorage` indicates global variable declaration in the
// top instruction block.
if (auto inst = sem_ir().insts().Get(inst_id);
inst.kind() != SemIR::InstKind::VarStorage) {
continue;
}
global_variables_.Insert(inst_id, BuildGlobalVariableDecl(inst_id));
}

// Lower constants.
constants_.resize(sem_ir_->insts().size());
Expand All @@ -61,8 +72,6 @@ auto FileContext::Run() -> std::unique_ptr<llvm::Module> {
BuildFunctionDefinition(SemIR::FunctionId(i));
}

// TODO: Lower global variable initializers.

return std::move(llvm_module_);
}

Expand Down Expand Up @@ -216,6 +225,12 @@ auto FileContext::BuildFunctionDecl(SemIR::FunctionId function_id)
llvm::Function::Create(function_type, llvm::Function::ExternalLinkage,
mangled_name, llvm_module());

// Append `__global_init` to llvm::global_ctors to initialize global
// variables.
if (mangled_name == "__global_init") {
llvm::appendToGlobalCtors(llvm_module(), llvm_function, /*Priority=*/0);
}

// Set up parameters and the return slot.
for (auto [inst_id, arg] :
llvm::zip_equal(param_inst_ids, llvm_function->args())) {
Expand Down Expand Up @@ -463,4 +478,17 @@ auto FileContext::BuildType(SemIR::InstId inst_id) -> llvm::Type* {
}
}

auto FileContext::BuildGlobalVariableDecl(SemIR::InstId inst_id)
-> llvm::GlobalVariable* {
auto var_storage = sem_ir().insts().Get(inst_id).As<SemIR::VarStorage>();
auto mangled_name =
*sem_ir().names().GetAsStringIfIdentifier(var_storage.name_id);
auto* type =
var_storage.type_id.is_valid() ? GetType(var_storage.type_id) : nullptr;
return new llvm::GlobalVariable(llvm_module(), type,
/*isConstant=*/false,
llvm::GlobalVariable::InternalLinkage,
/*Initializer=*/nullptr, mangled_name);
}

} // namespace Carbon::Lower
8 changes: 8 additions & 0 deletions toolchain/lower/file_context.h
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,9 @@ class FileContext {
auto llvm_module() -> llvm::Module& { return *llvm_module_; }
auto sem_ir() -> const SemIR::File& { return *sem_ir_; }
auto inst_namer() -> const SemIR::InstNamer* { return inst_namer_; }
auto global_variables() -> const Map<SemIR::InstId, llvm::GlobalVariable*>& {
return global_variables_;
}

private:
// Builds the declaration for the given function, which should then be cached
Expand All @@ -73,6 +76,8 @@ class FileContext {
// the caller.
auto BuildType(SemIR::InstId inst_id) -> llvm::Type*;

auto BuildGlobalVariableDecl(SemIR::InstId inst_id) -> llvm::GlobalVariable*;

// State for building the LLVM IR.
llvm::LLVMContext* llvm_context_;
std::unique_ptr<llvm::Module> llvm_module_;
Expand Down Expand Up @@ -101,6 +106,9 @@ class FileContext {
// Maps constants to their lowered values.
// We resize this directly to the (often large) correct size.
llvm::SmallVector<llvm::Constant*, 0> constants_;

// Maps global variables to their lowered variant.
Map<SemIR::InstId, llvm::GlobalVariable*> global_variables_;
};

} // namespace Carbon::Lower
Expand Down
4 changes: 4 additions & 0 deletions toolchain/lower/function_context.h
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,10 @@ class FunctionContext {
if (auto result = locals_.Lookup(inst_id)) {
return result.value();
}

if (auto result = file_context_->global_variables().Lookup(inst_id)) {
return result.value();
}
return file_context_->GetGlobal(inst_id);
}

Expand Down
30 changes: 30 additions & 0 deletions toolchain/lower/testdata/global/class_obj.carbon
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
// Part of the Carbon Language project, under the Apache License v2.0 with LLVM
// Exceptions. See /LICENSE for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
// AUTOUPDATE
// TIP: To test this file alone, run:
// TIP: bazel test //toolchain/testing:file_test --test_arg=--file_tests=toolchain/lower/testdata/global/class_obj.carbon
// TIP: To dump output, run:
// TIP: bazel run //toolchain/testing:file_test -- --dump_output --file_tests=toolchain/lower/testdata/global/class_obj.carbon
class A {}

var a: A = {};

// CHECK:STDOUT: ; ModuleID = 'class_obj.carbon'
// CHECK:STDOUT: source_filename = "class_obj.carbon"
// CHECK:STDOUT:
// CHECK:STDOUT: @llvm.global_ctors = appending global [1 x { i32, ptr, ptr }] [{ i32, ptr, ptr } { i32 0, ptr @__global_init, ptr null }]
// CHECK:STDOUT: @a = internal global {}
// CHECK:STDOUT: @struct.loc12_14 = internal constant {} zeroinitializer
// CHECK:STDOUT:
// CHECK:STDOUT: define void @__global_init() {
// CHECK:STDOUT: entry:
// CHECK:STDOUT: call void @llvm.memcpy.p0.p0.i64(ptr align 1 @a, ptr align 1 @struct.loc12_14, i64 0, i1 false)
// CHECK:STDOUT: ret void
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: ; Function Attrs: nocallback nofree nounwind willreturn memory(argmem: readwrite)
// CHECK:STDOUT: declare void @llvm.memcpy.p0.p0.i64(ptr noalias nocapture writeonly, ptr noalias nocapture readonly, i64, i1 immarg) #0
// CHECK:STDOUT:
// CHECK:STDOUT: attributes #0 = { nocallback nofree nounwind willreturn memory(argmem: readwrite) }
44 changes: 44 additions & 0 deletions toolchain/lower/testdata/global/class_with_fun.carbon
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
// Part of the Carbon Language project, under the Apache License v2.0 with LLVM
// Exceptions. See /LICENSE for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
// AUTOUPDATE
// TIP: To test this file alone, run:
// TIP: bazel test //toolchain/testing:file_test --test_arg=--file_tests=toolchain/lower/testdata/global/class_with_fun.carbon
// TIP: To dump output, run:
// TIP: bazel run //toolchain/testing:file_test -- --dump_output --file_tests=toolchain/lower/testdata/global/class_with_fun.carbon
class A {}

fn ret_a() -> A {
return {};
}

var a: A = {};

// CHECK:STDOUT: ; ModuleID = 'class_with_fun.carbon'
// CHECK:STDOUT: source_filename = "class_with_fun.carbon"
// CHECK:STDOUT:
// CHECK:STDOUT: @llvm.global_ctors = appending global [1 x { i32, ptr, ptr }] [{ i32, ptr, ptr } { i32 0, ptr @__global_init, ptr null }]
// CHECK:STDOUT: @a = internal global {}
// CHECK:STDOUT: @struct.loc13_12 = internal constant {} zeroinitializer
// CHECK:STDOUT: @struct.loc16_14 = internal constant {} zeroinitializer
// CHECK:STDOUT:
// CHECK:STDOUT: define void @ret_a(ptr sret({}) %return) {
// CHECK:STDOUT: entry:
// CHECK:STDOUT: call void @llvm.memcpy.p0.p0.i64(ptr align 1 %return, ptr align 1 @struct.loc13_12, i64 0, i1 false)
// CHECK:STDOUT: ret void
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: define void @__global_init() {
// CHECK:STDOUT: entry:
// CHECK:STDOUT: call void @llvm.memcpy.p0.p0.i64(ptr align 1 @a, ptr align 1 @struct.loc16_14, i64 0, i1 false)
// CHECK:STDOUT: ret void
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: ; Function Attrs: nocallback nofree nounwind willreturn memory(argmem: readwrite)
// CHECK:STDOUT: declare void @llvm.memcpy.p0.p0.i64(ptr noalias nocapture writeonly, ptr noalias nocapture readonly, i64, i1 immarg) #0
// CHECK:STDOUT:
// CHECK:STDOUT: ; uselistorder directives
// CHECK:STDOUT: uselistorder ptr @llvm.memcpy.p0.p0.i64, { 1, 0 }
// CHECK:STDOUT:
// CHECK:STDOUT: attributes #0 = { nocallback nofree nounwind willreturn memory(argmem: readwrite) }
15 changes: 15 additions & 0 deletions toolchain/lower/testdata/global/decl.carbon
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
// Part of the Carbon Language project, under the Apache License v2.0 with LLVM
// Exceptions. See /LICENSE for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
// AUTOUPDATE
// TIP: To test this file alone, run:
// TIP: bazel test //toolchain/testing:file_test --test_arg=--file_tests=toolchain/lower/testdata/global/decl.carbon
// TIP: To dump output, run:
// TIP: bazel run //toolchain/testing:file_test -- --dump_output --file_tests=toolchain/lower/testdata/global/decl.carbon
var a: i32;

// CHECK:STDOUT: ; ModuleID = 'decl.carbon'
// CHECK:STDOUT: source_filename = "decl.carbon"
// CHECK:STDOUT:
// CHECK:STDOUT: @a = internal global i32
22 changes: 22 additions & 0 deletions toolchain/lower/testdata/global/simple_init.carbon
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// Part of the Carbon Language project, under the Apache License v2.0 with LLVM
// Exceptions. See /LICENSE for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
// AUTOUPDATE
// TIP: To test this file alone, run:
// TIP: bazel test //toolchain/testing:file_test --test_arg=--file_tests=toolchain/lower/testdata/global/simple_init.carbon
// TIP: To dump output, run:
// TIP: bazel run //toolchain/testing:file_test -- --dump_output --file_tests=toolchain/lower/testdata/global/simple_init.carbon
var a: i32 = 0;

// CHECK:STDOUT: ; ModuleID = 'simple_init.carbon'
// CHECK:STDOUT: source_filename = "simple_init.carbon"
// CHECK:STDOUT:
// CHECK:STDOUT: @llvm.global_ctors = appending global [1 x { i32, ptr, ptr }] [{ i32, ptr, ptr } { i32 0, ptr @__global_init, ptr null }]
// CHECK:STDOUT: @a = internal global i32
// CHECK:STDOUT:
// CHECK:STDOUT: define void @__global_init() {
// CHECK:STDOUT: entry:
// CHECK:STDOUT: store i32 0, ptr @a, align 4
// CHECK:STDOUT: ret void
// CHECK:STDOUT: }
33 changes: 33 additions & 0 deletions toolchain/lower/testdata/global/simple_with_fun.carbon
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
// Part of the Carbon Language project, under the Apache License v2.0 with LLVM
// Exceptions. See /LICENSE for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
// AUTOUPDATE
// TIP: To test this file alone, run:
// TIP: bazel test //toolchain/testing:file_test --test_arg=--file_tests=toolchain/lower/testdata/global/simple_with_fun.carbon
// TIP: To dump output, run:
// TIP: bazel run //toolchain/testing:file_test -- --dump_output --file_tests=toolchain/lower/testdata/global/simple_with_fun.carbon

fn test_a() -> i32 {
return 0;
}

var a: i32 = test_a();

// CHECK:STDOUT: ; ModuleID = 'simple_with_fun.carbon'
// CHECK:STDOUT: source_filename = "simple_with_fun.carbon"
// CHECK:STDOUT:
// CHECK:STDOUT: @llvm.global_ctors = appending global [1 x { i32, ptr, ptr }] [{ i32, ptr, ptr } { i32 0, ptr @__global_init, ptr null }]
// CHECK:STDOUT: @a = internal global i32
// CHECK:STDOUT:
// CHECK:STDOUT: define i32 @test_a() {
// CHECK:STDOUT: entry:
// CHECK:STDOUT: ret i32 0
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: define void @__global_init() {
// CHECK:STDOUT: entry:
// CHECK:STDOUT: %test_a.call = call i32 @test_a()
// CHECK:STDOUT: store i32 %test_a.call, ptr @a, align 4
// CHECK:STDOUT: ret void
// CHECK:STDOUT: }

0 comments on commit fd45fee

Please sign in to comment.