Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

improvement: better literal support #122

Merged
merged 5 commits into from
Apr 19, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 0 additions & 5 deletions crates/mun_codegen/src/db.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ use inkwell::{
types::{AnyTypeEnum, StructType},
OptimizationLevel,
};
use mun_target::spec::Target;
use std::sync::Arc;

/// The `IrDatabase` enables caching of intermediate in the process of LLVM IR generation. It uses
Expand All @@ -25,10 +24,6 @@ pub trait IrDatabase: hir::HirDatabase {
#[salsa::input]
fn optimization_lvl(&self) -> OptimizationLevel;

/// Returns the target for code generation.
#[salsa::input]
fn target(&self) -> Target;

/// Returns the target machine's data layout for code generation.
#[salsa::invoke(crate::code_gen::target_data_query)]
fn target_data(&self) -> Arc<TargetData>;
Expand Down
61 changes: 50 additions & 11 deletions crates/mun_codegen/src/ir/body.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,9 @@ use inkwell::{
values::{BasicValueEnum, CallSiteValue, FloatValue, FunctionValue, IntValue, StructValue},
AddressSpace, FloatPredicate, IntPredicate,
};
use std::{collections::HashMap, mem, sync::Arc};
use std::{collections::HashMap, sync::Arc};

use hir::ResolveBitness;
use inkwell::basic_block::BasicBlock;
use inkwell::values::{AggregateValueEnum, GlobalValue, PointerValue};

Expand Down Expand Up @@ -200,7 +201,7 @@ impl<'a, 'b, D: IrDatabase> BodyIrGenerator<'a, 'b, D> {
let resolver = hir::resolver_for_expr(self.body.clone(), self.db, expr);
Some(self.gen_path_expr(p, expr, &resolver))
}
Expr::Literal(lit) => Some(self.gen_literal(lit)),
Expr::Literal(lit) => Some(self.gen_literal(lit, expr)),
Expr::RecordLit { fields, .. } => Some(self.gen_record_lit(expr, fields)),
Expr::BinaryOp { lhs, rhs, op } => {
self.gen_binary_op(expr, *lhs, *rhs, op.expect("missing op"))
Expand Down Expand Up @@ -259,16 +260,54 @@ impl<'a, 'b, D: IrDatabase> BodyIrGenerator<'a, 'b, D> {
}

/// Generates an IR value that represents the given `Literal`.
fn gen_literal(&mut self, lit: &Literal) -> BasicValueEnum {
fn gen_literal(&mut self, lit: &Literal, expr: ExprId) -> BasicValueEnum {
match lit {
Literal::Int(v) => self
.db
.context()
.i64_type()
.const_int(unsafe { mem::transmute::<i64, u64>(*v) }, true)
.into(),

Literal::Float(v) => self.db.context().f64_type().const_float(*v as f64).into(),
Literal::Int(v) => {
let ty = match &self.infer[expr] {
hir::Ty::Apply(hir::ApplicationTy {
ctor: hir::TypeCtor::Int(int_ty),
..
}) => int_ty,
_ => unreachable!(
"cannot construct an IR value for anything but an integral type"
),
};

let context = self.db.context();
let ir_ty = match ty.resolve(&self.db.target_data_layout()).bitness {
hir::IntBitness::X8 => context.i8_type().const_int(v.value as u64, false),
hir::IntBitness::X16 => context.i16_type().const_int(v.value as u64, false),
hir::IntBitness::X32 => context.i32_type().const_int(v.value as u64, false),
hir::IntBitness::X64 => context.i64_type().const_int(v.value as u64, false),
hir::IntBitness::X128 => {
context.i128_type().const_int_arbitrary_precision(&unsafe {
std::mem::transmute::<u128, [u64; 2]>(v.value)
})
}
_ => unreachable!("unresolved bitness in code generation"),
};

ir_ty.into()
}

Literal::Float(v) => {
let ty = match &self.infer[expr] {
hir::Ty::Apply(hir::ApplicationTy {
ctor: hir::TypeCtor::Float(float_ty),
..
}) => float_ty,
_ => unreachable!("cannot construct an IR value for anything but a float type"),
};

let context = self.db.context();
let ir_ty = match ty.bitness.resolve(&self.db.target_data_layout()) {
hir::FloatBitness::X32 => context.f32_type().const_float(v.value),
hir::FloatBitness::X64 => context.f64_type().const_float(v.value),
_ => unreachable!("unresolved bitness in code generation"),
};

ir_ty.into()
}

Literal::Bool(value) => {
let ty = self.db.context().bool_type();
Expand Down
50 changes: 13 additions & 37 deletions crates/mun_codegen/src/ir/ty.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,17 @@
use super::try_convert_any_to_basic;
use crate::type_info::TypeSize;
use crate::{
type_info::TypeSize,
type_info::{TypeGroup, TypeInfo},
CodeGenParams, IrDatabase,
};
use hir::{ApplicationTy, CallableDef, FloatBitness, FloatTy, IntBitness, IntTy, Ty, TypeCtor};
use inkwell::types::{AnyTypeEnum, BasicType, BasicTypeEnum, FloatType, IntType, StructType};
use inkwell::AddressSpace;
use mun_target::spec::Target;
use hir::{
ApplicationTy, CallableDef, FloatBitness, FloatTy, IntBitness, IntTy, ResolveBitness, Ty,
TypeCtor,
};
use inkwell::{
types::{AnyTypeEnum, BasicType, BasicTypeEnum, FloatType, IntType, StructType},
AddressSpace,
};

/// Given a mun type, construct an LLVM IR type
#[rustfmt::skip]
Expand Down Expand Up @@ -57,7 +61,7 @@ pub(crate) fn ir_query(db: &impl IrDatabase, ty: Ty, params: CodeGenParams) -> A
/// Returns the LLVM IR type of the specified float type
fn float_ty_query(db: &impl IrDatabase, fty: FloatTy) -> FloatType {
let context = db.context();
match fty.resolve(&db.target()).bitness {
match fty.bitness.resolve(&db.target_data_layout()) {
FloatBitness::X64 => context.f64_type(),
FloatBitness::X32 => context.f32_type(),
_ => unreachable!(),
Expand All @@ -67,7 +71,7 @@ fn float_ty_query(db: &impl IrDatabase, fty: FloatTy) -> FloatType {
/// Returns the LLVM IR type of the specified int type
fn int_ty_query(db: &impl IrDatabase, ity: IntTy) -> IntType {
let context = db.context();
match ity.resolve(&db.target()).bitness {
match ity.bitness.resolve(&db.target_data_layout()) {
IntBitness::X128 => context.i128_type(),
IntBitness::X64 => context.i64_type(),
IntBitness::X32 => context.i32_type(),
Expand Down Expand Up @@ -102,7 +106,7 @@ pub fn type_info_query(db: &impl IrDatabase, ty: Ty) -> TypeInfo {
let ir_ty = float_ty_query(db, ty);
let type_size = TypeSize::from_ir_type(&ir_ty, target.as_ref());
TypeInfo::new(
format!("core::{}", ty.resolve(&db.target())),
format!("core::{}", ty.resolve(&db.target_data_layout())),
TypeGroup::FundamentalTypes,
type_size,
)
Expand All @@ -111,7 +115,7 @@ pub fn type_info_query(db: &impl IrDatabase, ty: Ty) -> TypeInfo {
let ir_ty = int_ty_query(db, ty);
let type_size = TypeSize::from_ir_type(&ir_ty, target.as_ref());
TypeInfo::new(
format!("core::{}", ty.resolve(&db.target())),
format!("core::{}", ty.resolve(&db.target_data_layout())),
TypeGroup::FundamentalTypes,
type_size,
)
Expand All @@ -131,31 +135,3 @@ pub fn type_info_query(db: &impl IrDatabase, ty: Ty) -> TypeInfo {
_ => unreachable!("{:?} unhandled", ty),
}
}

trait ResolveBitness {
fn resolve(&self, _target: &Target) -> Self;
}

impl ResolveBitness for FloatTy {
fn resolve(&self, _target: &Target) -> Self {
let bitness = match self.bitness {
FloatBitness::Undefined => FloatBitness::X64,
bitness => bitness,
};
FloatTy { bitness }
}
}

impl ResolveBitness for IntTy {
fn resolve(&self, _target: &Target) -> Self {
let bitness = match self.bitness {
IntBitness::Undefined => IntBitness::X64,
IntBitness::Xsize => IntBitness::X64,
bitness => bitness,
};
IntTy {
bitness,
signedness: self.signedness,
}
}
}
75 changes: 75 additions & 0 deletions crates/mun_codegen/src/snapshots/test__literal_types.snap
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
---
source: crates/mun_codegen/src/test.rs
expression: "pub fn main(){\n let a = 123;\n let a = 123u8;\n let a = 123u16;\n let a = 123u32;\n let a = 123u64;\n let a = 123u128;\n let a = 123uint;\n let a = 1_000_000_u32;\n let a = 123i8;\n let a = 123i16;\n let a = 123i32;\n let a = 123i64;\n let a = 123123123123123123123123123123123i128;\n let a = 123int;\n let a = 1_000_000_i32;\n let a = 1_000_123.0e-2;\n let a = 1_000_123.0e-2f32;\n let a = 1_000_123.0e-2f64;\n let a = 1_000_123.0e-2float;\n}\n\npub fn add(a:u32) -> u32 {\n a + 12u32\n}"
---
; == FILE IR =====================================
; ModuleID = 'main.mun'
source_filename = "main.mun"

%struct.MunTypeInfo = type { [16 x i8], i8 addrspace(4)*, i32, i8, i8 }

@global_type_table = external global [1 x %struct.MunTypeInfo addrspace(4)*]

define void @main() {
body:
%a18 = alloca double
%a17 = alloca double
%a16 = alloca float
%a15 = alloca double
%a14 = alloca i32
%a13 = alloca i64
%a12 = alloca i128
%a11 = alloca i64
%a10 = alloca i32
%a9 = alloca i16
%a8 = alloca i8
%a7 = alloca i32
%a6 = alloca i64
%a5 = alloca i128
%a4 = alloca i64
%a3 = alloca i32
%a2 = alloca i16
%a1 = alloca i8
%a = alloca i64
store i64 123, i64* %a
store i8 123, i8* %a1
store i16 123, i16* %a2
store i32 123, i32* %a3
store i64 123, i64* %a4
store i128 123, i128* %a5
store i64 123, i64* %a6
store i32 1000000, i32* %a7
store i8 123, i8* %a8
store i16 123, i16* %a9
store i32 123, i32* %a10
store i64 123, i64* %a11
store i128 123123123123123123123123123123123, i128* %a12
store i64 123, i64* %a13
store i32 1000000, i32* %a14
store double 0x40C3889D70A3D70A, double* %a15
store float 0x40C3889D80000000, float* %a16
store double 0x40C3889D70A3D70A, double* %a17
store double 0x40C3889D70A3D70A, double* %a18
ret void
}

define i32 @add(i32) {
body:
%a = alloca i32
store i32 %0, i32* %a
%a1 = load i32, i32* %a
%add = add i32 %a1, 12
ret i32 %add
}


; == GROUP IR ====================================
; ModuleID = 'group_name'
source_filename = "group_name"

%struct.MunTypeInfo = type { [16 x i8], i8 addrspace(4)*, i32, i8, i8 }

@"type_info::<core::u32>::name" = private unnamed_addr constant [10 x i8] c"core::u32\00"
@"type_info::<core::u32>" = private unnamed_addr constant %struct.MunTypeInfo { [16 x i8] c"daz5d\A6\BE\88\81=&Y\A1+\C6\1D", [10 x i8]* @"type_info::<core::u32>::name", i32 32, i8 4, i8 0 }
@global_type_table = global [1 x %struct.MunTypeInfo addrspace(4)*] [%struct.MunTypeInfo addrspace(4)* @"type_info::<core::u32>"]

36 changes: 35 additions & 1 deletion crates/mun_codegen/src/test.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
use crate::{mock::MockDatabase, IrDatabase, ModuleBuilder};
use hir::{diagnostics::DiagnosticSink, line_index::LineIndex, Module, SourceDatabase};
use hir::{
diagnostics::DiagnosticSink, line_index::LineIndex, HirDatabase, Module, SourceDatabase,
};
use inkwell::OptimizationLevel;
use mun_target::spec::Target;
use std::cell::RefCell;
Expand Down Expand Up @@ -41,6 +43,38 @@ fn issue_133() {
);
}

#[test]
fn literal_types() {
test_snapshot_unoptimized(
r"
pub fn main(){
let a = 123;
let a = 123u8;
let a = 123u16;
let a = 123u32;
let a = 123u64;
let a = 123u128;
let a = 123uint;
let a = 1_000_000_u32;
let a = 123i8;
let a = 123i16;
let a = 123i32;
let a = 123i64;
let a = 123123123123123123123123123123123i128;
let a = 123int;
let a = 1_000_000_i32;
let a = 1_000_123.0e-2;
let a = 1_000_123.0e-2f32;
let a = 1_000_123.0e-2f64;
let a = 1_000_123.0e-2float;
}

pub fn add(a:u32) -> u32 {
a + 12u32
}",
)
}

#[test]
fn function() {
test_snapshot(
Expand Down
2 changes: 1 addition & 1 deletion crates/mun_compiler/src/driver.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

use crate::{db::CompilerDatabase, diagnostics::diagnostics, PathOrInline};
use mun_codegen::{IrDatabase, ModuleBuilder};
use mun_hir::{FileId, RelativePathBuf, SourceDatabase, SourceRoot, SourceRootId};
use mun_hir::{FileId, HirDatabase, RelativePathBuf, SourceDatabase, SourceRoot, SourceRootId};

use std::{path::PathBuf, sync::Arc};

Expand Down
1 change: 1 addition & 0 deletions crates/mun_hir/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ description = "Provides high-level intermediate representation of Mun code"
salsa="0.12"
superslice = "1.0"
mun_syntax={path="../mun_syntax"}
mun_target={path="../mun_target"}
rustc-hash = "1.1"
once_cell = "0.2"
relative-path = "0.4.0"
Expand Down
3 changes: 3 additions & 0 deletions crates/mun_hir/src/builtin_type.rs
Original file line number Diff line number Diff line change
Expand Up @@ -125,13 +125,15 @@ impl BuiltinInt {

pub fn from_suffix(suffix: &str) -> Option<BuiltinInt> {
let res = match suffix {
"int" => Self::INT,
"isize" => Self::ISIZE,
"i8" => Self::I8,
"i16" => Self::I16,
"i32" => Self::I32,
"i64" => Self::I64,
"i128" => Self::I128,

"uint" => Self::UINT,
"usize" => Self::USIZE,
"u8" => Self::U8,
"u16" => Self::U16,
Expand All @@ -155,6 +157,7 @@ impl BuiltinFloat {
let res = match suffix {
"f32" => BuiltinFloat::F32,
"f64" => BuiltinFloat::F64,
"float" => BuiltinFloat::FLOAT,
_ => return None,
};
Some(res)
Expand Down
6 changes: 4 additions & 2 deletions crates/mun_hir/src/code_model.rs
Original file line number Diff line number Diff line change
Expand Up @@ -349,10 +349,12 @@ impl Function {
}

pub fn diagnostics(self, db: &impl HirDatabase, sink: &mut DiagnosticSink) {
let body = self.body(db);
body.add_diagnostics(db, self.into(), sink);
let infer = self.infer(db);
infer.add_diagnostics(db, self, sink);
let mut validator = ExprValidator::new(self, db, sink);
validator.validate_body();
let validator = ExprValidator::new(self, db);
validator.validate_body(sink);
}
}

Expand Down
Loading