Skip to content

Commit

Permalink
Implement Instruction display and tests
Browse files Browse the repository at this point in the history
  • Loading branch information
Willyboar committed May 26, 2023
1 parent 9a39b93 commit 8e4f04f
Show file tree
Hide file tree
Showing 4 changed files with 230 additions and 25 deletions.
2 changes: 1 addition & 1 deletion gleam.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ description = "Gleam QBE IR Generator"
licences = ["MIT"]

[dependencies]
gleam_stdlib = "~> 0.28"
gleam_stdlib = "~> 0.29"

[dev-dependencies]
gleeunit = "~> 0.10"
4 changes: 2 additions & 2 deletions manifest.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@
# You typically do not need to edit this file

packages = [
{ name = "gleam_stdlib", version = "0.28.2", build_tools = ["gleam"], requirements = [], otp_app = "gleam_stdlib", source = "hex", outer_checksum = "088E334A00C9530D4B194F31406E51B6E4E4697C6A380D11591E60CC2F239724" },
{ name = "gleam_stdlib", version = "0.29.0", build_tools = ["gleam"], requirements = [], otp_app = "gleam_stdlib", source = "hex", outer_checksum = "DB981FB670AAC6392C0694AF639C49ADF1C2E42664D5F90BBF573102667B8E53" },
{ name = "gleeunit", version = "0.10.1", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleeunit", source = "hex", outer_checksum = "ECEA2DE4BE6528D36AFE74F42A21CDF99966EC36D7F25DEB34D47DD0F7977BAF" },
]

[requirements]
gleam_stdlib = "~> 0.28"
gleam_stdlib = "~> 0.29"
gleeunit = "~> 0.10"
53 changes: 32 additions & 21 deletions src/glove.gleam
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ pub type Inst {
/// Unconditionally jumps to a label
Jmp(String)
/// Calls a function
Call(Value, #(Type, Value))
Call(Value, List(#(Type, Value)))
/// Allocates a 4-byte aligned area on the stack
Alloc4(Int)
/// Allocates a 8-byte aligned area on the stack
Expand Down Expand Up @@ -74,37 +74,37 @@ pub type Inst {
pub fn display_inst(inst: Inst) -> String {
case inst {
Add(a, b) -> "add " <> display_value(a) <> ", " <> display_value(b)
Sub(a, b) -> "sub" <> display_value(a) <> ", " <> display_value(b)
Mul(a, b) -> "mul" <> display_value(a) <> ", " <> display_value(b)
Div(a, b) -> "div" <> display_value(a) <> ", " <> display_value(b)
Rem(a, b) -> "rem" <> display_value(a) <> ", " <> display_value(b)
Sub(a, b) -> "sub " <> display_value(a) <> ", " <> display_value(b)
Mul(a, b) -> "mul " <> display_value(a) <> ", " <> display_value(b)
Div(a, b) -> "div " <> display_value(a) <> ", " <> display_value(b)
Rem(a, b) -> "rem " <> display_value(a) <> ", " <> display_value(b)
Comp(ty, cmp, a, b) -> {
case ty {
Agreegate(_) -> "Cannot Compare aggregate types"
Aggregate(_) -> "Cannot Compare aggregate types"
_ ->
case cmp {
Slt ->
"c" <> "slt" <> display_type(ty) <> " " <> display_value(a) <> " " <> display_value(
"c" <> "slt" <> " " <> display_type(ty) <> " " <> display_value(a) <> " " <> display_value(
b,
)
Sle ->
"c" <> "sle" <> display_type(ty) <> " " <> display_value(a) <> " " <> display_value(
"c" <> "sle" <> " " <> display_type(ty) <> " " <> display_value(a) <> " " <> display_value(
b,
)
Sgt ->
"c" <> "sgt" <> display_type(ty) <> " " <> display_value(a) <> " " <> display_value(
"c" <> "sgt" <> " " <> display_type(ty) <> " " <> display_value(a) <> " " <> display_value(
b,
)
Sge ->
"c" <> "sge" <> display_type(ty) <> " " <> display_value(a) <> " " <> display_value(
"c" <> "sge" <> " " <> display_type(ty) <> " " <> display_value(a) <> " " <> display_value(
b,
)
Eq ->
"c" <> "eq" <> display_type(ty) <> " " <> display_value(a) <> " " <> display_value(
"c" <> "eq" <> " " <> display_type(ty) <> " " <> display_value(a) <> " " <> display_value(
b,
)
Ne ->
"c" <> "ne" <> display_type(ty) <> " " <> display_value(a) <> " " <> display_value(
"c" <> "ne" <> " " <> display_type(ty) <> " " <> display_value(a) <> " " <> display_value(
b,
)
}
Expand All @@ -122,13 +122,25 @@ pub fn display_inst(inst: Inst) -> String {
Jnz(val, if_nonzero, if_zero) ->
"jnz " <> display_value(val) <> ", @" <> if_nonzero <> ", @" <> if_zero
Jmp(str) -> "jmp @" <> str
Call(name, #(typ, arg)) -> "call"
Call(name, args) -> {
let arg_str =
args
|> list.index_map(fn(_, arg) {
case arg {
#(ty, val) -> display_type(ty) <> " " <> display_value(val)
}
})
|> string.join(", ")

"call " <> display_value(name) <> "(" <> arg_str <> ")"
}

Alloc4(int) -> "alloc4 " <> int.to_string(int)
Alloc8(int) -> "alloc8 " <> int.to_string(int)
Alloc16(int) -> "alloc16 " <> int.to_string(int)
Store(typ, value, dest) ->
case typ {
Agreegate(_) -> "Store to an aggregate type"
Aggregate(_) -> "Store to an aggregate type"
_ ->
"store" <> display_type(typ) <> " " <> display_value(value) <> " " <> display_value(
dest,
Expand All @@ -137,7 +149,7 @@ pub fn display_inst(inst: Inst) -> String {

Load(typ, val) ->
case typ {
Agreegate(_) -> "Load aggregate type"
Aggregate(_) -> "Load aggregate type"
_ -> "load" <> display_type(typ) <> " " <> display_value(val)
}
Blit(src, dest, n) ->
Expand Down Expand Up @@ -176,7 +188,7 @@ pub type Type {
/// Extended Types
Byte
Halfword
Agreegate(TypeDef)
Aggregate(TypeDef)
}

/// Display Type function
Expand All @@ -188,7 +200,7 @@ pub fn display_type(ty: Type) -> String {
Long -> "l"
Single -> "s"
Double -> "d"
Agreegate(ty) -> display_type_def(ty)
Aggregate(ty) -> display_type_def(ty)
}
}

Expand Down Expand Up @@ -245,10 +257,9 @@ pub fn display_type_def(def: TypeDef) -> String {
|> list.index_map(fn(_, item) {
case item {
#(ty, count) ->
case count {
0 -> display_type(ty)
1 -> display_type(ty)
_ -> display_type(ty) <> " " <> int.to_string(count)
case count > 1 {
False -> display_type(ty)
True -> display_type(ty) <> " " <> int.to_string(count)
}
}
})
Expand Down
196 changes: 195 additions & 1 deletion test/glove_test.gleam
Original file line number Diff line number Diff line change
Expand Up @@ -201,8 +201,202 @@ pub fn display_type_test() {

// Test case 2: Extended types
let def1 = glove.TypeDef("myType", None, [#(glove.Word, 1)])
let result5 = glove.Agreegate(def1)
let result5 = glove.Aggregate(def1)
result5
|> glove.display_type
|> should.equal("type :myType = { w }")
}

// Tests for QBE.Instructions
pub fn display_inst_test() {
// Test case for Call with 2 args
let call1 =
glove.Call(
glove.Global("vadd"),
[
#(glove.Single, glove.Temporary("a")),
#(glove.Long, glove.Temporary("ap")),
],
)
call1
|> glove.display_inst
|> should.equal("call $vadd(s %a, l %ap)")

//Test case for empty call
let call2 = glove.Call(glove.Global("vsub"), [])
call2
|> glove.display_inst
|> should.equal("call $vsub()")

// Test case for call with single arg
let call3 =
glove.Call(glove.Global("div"), [#(glove.Single, glove.Temporary("b"))])
call3
|> glove.display_inst
|> should.equal("call $div(s %b)")

// Test case for add instruction
let add = glove.Add(glove.Temporary("a"), glove.Temporary("b"))
add
|> glove.display_inst
|> should.equal("add %a, %b")

// Test case for sub instruction
let sub = glove.Sub(glove.Temporary("a"), glove.Temporary("b"))
sub
|> glove.display_inst
|> should.equal("sub %a, %b")

// Test case for mul instruction
let mul = glove.Mul(glove.Temporary("a"), glove.Temporary("b"))
mul
|> glove.display_inst
|> should.equal("mul %a, %b")

// Test case for div instruction
let div = glove.Div(glove.Temporary("a"), glove.Temporary("b"))
div
|> glove.display_inst
|> should.equal("div %a, %b")

// Test case for rem instruction
let rem = glove.Rem(glove.Temporary("a"), glove.Temporary("b"))
rem
|> glove.display_inst
|> should.equal("rem %a, %b")

// Test case for comparing integer values
let comp1 =
glove.Comp(
glove.Word,
glove.Slt,
glove.Temporary("a"),
glove.Temporary("b"),
)
comp1
|> glove.display_inst
|> should.equal("cslt w %a %b")

// Test case for comparing aggregate types
let comp2 =
glove.Comp(
glove.Aggregate(glove.TypeDef(
"struct",
Some(4),
[#(glove.Word, 2), #(glove.Word, 1), #(glove.Word, 3)],
)),
glove.Eq,
glove.Temporary("a"),
glove.Temporary("b"),
)
comp2
|> glove.display_inst
|> should.equal("Cannot Compare aggregate types")

// Test case for logical AND
let and = glove.And(glove.Temporary("a"), glove.Temporary("b"))
and
|> glove.display_inst
|> should.equal("and %a, %b")

// Test case for logical OR
let or = glove.Or(glove.Temporary("a"), glove.Temporary("b"))
or
|> glove.display_inst
|> should.equal("or %a, %b")

// Test case for copying a value
let copy = glove.Copy(glove.Temporary("a"))
copy
|> glove.display_inst
|> should.equal("copy %a")

// Test case for returning a value
let ret1 = glove.Ret(Some(glove.Const(10)))
ret1
|> glove.display_inst
|> should.equal("ret 10")

// Test case for returning without a value
let ret2 = glove.Ret(None)
ret2
|> glove.display_inst
|> should.equal("ret")

// Test case for conditional jump if nonzero
let jnz = glove.Jnz(glove.Const(1), "label1", "label2")
jnz
|> glove.display_inst
|> should.equal("jnz 1, @label1, @label2")

// Test case for unconditional jump
let jmp = glove.Jmp("label")
jmp
|> glove.display_inst
|> should.equal("jmp @label")

// Test case for allocating 4 bytes
let alloc4 = glove.Alloc4(16)
alloc4
|> glove.display_inst
|> should.equal("alloc4 16")

// Test case for allocating 8 bytes
let alloc8 = glove.Alloc8(32)
alloc8
|> glove.display_inst
|> should.equal("alloc8 32")

// Test case for allocating 16 bytes
let alloc16 = glove.Alloc16(64)
alloc16
|> glove.display_inst
|> should.equal("alloc16 64")

// Test case for storing a value
let store = glove.Store(glove.Word, glove.Const(42), glove.Temporary("r1"))
store
|> glove.display_inst
|> should.equal("storew 42 %r1")

// Test case for loading a value
let load = glove.Load(glove.Word, glove.Temporary("r2"))
load
|> glove.display_inst
|> should.equal("loadw %r2")

// Test case for storing an aggregate value
let store2 =
glove.Store(
glove.Aggregate(glove.TypeDef(
"struct",
Some(4),
[#(glove.Word, 2), #(glove.Word, 1), #(glove.Word, 3)],
)),
glove.Const(42),
glove.Temporary("%r5"),
)
store2
|> glove.display_inst
|> should.equal("Store to an aggregate type")

// Test case for loading an aggregate value
let load2 =
glove.Load(
glove.Aggregate(glove.TypeDef(
"struct",
Some(4),
[#(glove.Word, 2), #(glove.Word, 1), #(glove.Word, 3)],
)),
glove.Temporary("%r6"),
)
load2
|> glove.display_inst
|> should.equal("Load aggregate type")

// Test case for blitting values
let blit = glove.Blit(glove.Temporary("r3"), glove.Temporary("r4"), 8)
blit
|> glove.display_inst
|> should.equal("blit %r3, %r4, 8")
}

0 comments on commit 8e4f04f

Please sign in to comment.