-
Notifications
You must be signed in to change notification settings - Fork 1
Tea BC 规范
TeaBC(Tea byte code) 是一个类似汇编的底层编程语言。它具有以下特性:
- 可以转换为 LLVM(Low level virtual machine) 字节码,并继续转为原生的汇编指令。
- 支持面向对象,相比 LLVM,更接近高级语言。
- 语法简单,比 LLVM 更容易上手。但是功能不如 LLVM 完整。
field const int8* val { "hello world" }
method extern void printf(int8*, ...)
method void main() {
ld.fld val // 载入全局 val 到栈顶
call printf(char32*, ...) // 调用函数
}
class public A
extends Object {
method public void fn(int32 a)
local int32 b // 局部变量 b
local int8 c {
ld.arg a // 载入参数 a 到栈顶
ld.const int32 1 // 载入常数 1 到栈顶
add // 计算 a + 1
st.loc b // 存入 a + 1 到 b
ld.arg a
br.true if.end // 如果栈顶是 true,则跳转 if.end
st.loc c int8 "g"
:if.end
ret
}
}
一个 TeaBC 是由多个成员定义组成的。每个成员定义都由一个成员标记开始。下文具体列出有哪些成员标记。
module <模块修饰符> <模块名> <属性列表>
支持的属性:
- src <字符串> 模块的源码
- time <字符串> 模块生成的时间
- target <字符串> 模块对应的平台
如: module Hi src "hi.src" time "2014-12-12"
class <类修饰符> <类名> <属性列表>
支持的属性:
- extends <类型> 指示类型继承类。
struct <结构修饰符> <结构名> <属性列表> { <结构主体> }
interface <接口修饰符> <接口名> <属性列表> { <结构主体> }
method <函数修饰符> <函数返回类型> <函数名> ( <类型> [<参数名>], ... ) <属性列表> { <函数主体> }
field <字段修饰符> <字段类型> <字段名> [ { <默认值> } ]
property <属性修饰符> <属性类型> <属性名> { get <属性修饰符> <属性列表> { <函数主体> } set <属性修饰符> <属性列表> { <函数主体> } }
从当前方法返回,并将返回值(如果存在)从调用方的计算堆栈推送到被调用方的计算堆栈上。
ret
> ret void
> ret i32 1
无条件地将控制转移到目标指令。
br label
:label
>br label %label
如果值为真、非空或非零,则将控制转移到目标指令。
br.true label
>br i1 %cond label %label
如果值为假、空或零,则将控制转移到目标指令。
实现跳转表。
switch switch.end
switch.case int32 1 switch.case1
switch case int32 2 switch.case2
:switch.case1
:switch.case2
:switch.end
>switch i32 %val, label %otherwise [ i32 0, label %onzero i32 1, label %onone i32 2, label %ontwo ]
实现跳转表的一项。
调用由传递的方法说明符指示的方法。
ld.const int32 1
call system.Console.writeLine(int32)
对对象调用后期绑定方法,并且将返回值推送到计算堆栈上。
表示进入一个需要检测异常语句块。
try
// try 语句
br.catch try.end
// catch 语句
:try.end
表示检测到任何异常时执行的语句块。
引发当前位于计算堆栈上的异常对象。
再次引发当前异常。
将两个值相加并将结果推送到计算堆栈上。
ld.const int32 1
ld.const int32 1
add
>int32 + int32 -> add nsw i32 %0 %1
>uint32 + uint32 -> add i32 %0 %1
>uint32 + int32 -> add i32 %0 %1
>long + long -> add nsw i64 %0 %1
>ulong + ulong -> add i64 %0 %1
>float + float -> fadd i32 %0 %1
>double + double -> fadd i64 %0 %1
将两个整数相加,执行溢出检查,并且将结果推送到计算堆栈上。
ld.const int32 1
ld.const int32 1
add.ovf
int32 + int32 -> call {i32, i1} @llvm.sadd.with.overflow.i32(i32 %0, i32 %1)
uint32 + uint32 -> call {i32, i1} @llvm.uadd.with.overflow.i32(i32 %0, i32 %1)
uint32 + int32 -> call {i32, i1} @llvm.uadd.with.overflow.i32(i32 %0, i32 %1)
long + long -> call {i64, i1} @llvm.sadd.with.overflow.i64(i64 %0, i64 %1)
ulong + ulong -> call {i64, i1} @llvm.uadd.with.overflow.i64(i64 %0, i64 %1)
http://llvm.org/docs/LangRef.html#llvm-sadd-with-overflow-intrinsics
declare {i32, i1} @llvm.sadd.with.overflow.i32(i32 %a, i32 %b)
declare {i32, i1} @llvm.sadd.with.overflow.i32(i32 %a, i32 %b)
%res = call {i32, i1} @llvm.sadd.with.overflow.i32(i32 2147483647, i32 2147483647)
%obit = extractvalue {i32, i1} %res, 1
br i1 %obit, label %overflow, label %hidden
从其他值中减去一个值并将结果推送到计算堆栈上。
从另一值中减去一个整数值,执行溢出检查,并且将结果推送到计算堆栈上。
将两个值相乘并将结果推送到计算堆栈上。
将两个整数值相乘,执行溢出检查,并将结果推送到计算堆栈上。
将两个值相除并将结果作为浮点(F 类型)或商(int32 类型)推送到计算堆栈上。
将两个值相除并将余数推送到计算堆栈上。
对一个值执行求反并将结果推送到计算堆栈上。
将整数值左移(用零填充)指定的位数,并将结果推送到计算堆栈上。
将整数值右移(保留符号)指定的位数,并将结果推送到计算堆栈上。
计算两个值的按位“与”并将结果推送到计算堆栈上。
>and i32 %0 %1
>and i64 %0 %1
计算位于堆栈顶部的两个整数值的按位求补并将结果推送到计算堆栈上。
计算位于计算堆栈顶部的两个值的按位异或,并且将结果推送到计算堆栈上。
计算堆栈顶部整数值的按位求补并将结果作为相同的类型推送到计算堆栈上。
比较两个值。如果这两个值相等,则将整数值 1 (int32) 推送到计算堆栈上;否则,将 0 (int32) 推送到计算堆栈上。
比较两个值。如果第一个值大于第二个值,则将整数值 1 (int32) 推送到计算堆栈上;反之,将 0 (int32) 推送到计算堆栈上。
比较两个值。如果第一个值小于第二个值,则将整数值 1 (int32) 推送到计算堆栈上;反之,将 0 (int32) 推送到计算堆栈上。
将位于计算堆栈顶部的值转换为 natural int。
尝试将引用传递的对象转换为指定的类。
将参数(由指定索引值引用)加载到堆栈上。
将所提供的 int32 类型的值作为 int32 推送到计算堆栈上。
查找对象中其引用当前位于计算堆栈的字段的值。
查找对象中其引用当前位于计算堆栈的字段的地址。
将指向实现特定方法的本机代码的非托管指针(natural int 类型)推送到计算堆栈上。
将指向实现与指定对象关联的特定虚方法的本机代码的非托管指针(natural int 类型)推送到计算堆栈上。
将指定索引处的局部变量加载到计算堆栈上。
将地址指向的值类型对象复制到计算堆栈的顶部。
将位于计算堆栈顶部的值存储到位于指定索引的参数槽中。
用新值替换在对象引用或指针的字段中存储的值。
从计算堆栈的顶部弹出当前值并将其存储到指定索引处的局部变量列表中。
将指定类型的值从计算堆栈复制到所提供的内存地址中。
复制计算堆栈上当前最顶端的值,然后将副本推送到计算堆栈上。
将提供的值类型的大小(以字节为单位)推送到计算堆栈上。
发出信号以通知调试器已撞上了一个断点。
如果修补操作码,则填充空间。尽管可能消耗处理周期,但未执行任何有意义的操作。
创建一个值类型的新对象或新实例,并将对象引用(O 类型)推送到计算堆栈上。
将位于指定地址的对象的所有字段初始化为空引用或适当的基元类型的 0。
移除当前位于计算堆栈顶部的值。
返回指向当前方法的参数列表的指针。
>declare void @llvm.va_start(i8*)
>%ap = alloca i8*
>%ap2 = bitcast i8** %ap to i8*
>call void @llvm.va_start(i8* %ap2)
返回当前参数指针对应的值,并放入栈顶。
>%tmp = va_arg i8** %ap, i32
复制当前参数列表到指定的指针,并放入栈顶。
>declare void @llvm.va_copy(i8*, i8*)
>%aq = alloca i8*
>%aq2 = bitcast i8** %aq to i8*
>call void @llvm.va_copy(i8* %aq2, i8* %ap2)
关闭读取参数列表的指针。
>declare void @llvm.va_end(i8*)
>call void @llvm.va_end(i8* %aq2)