-
Notifications
You must be signed in to change notification settings - Fork 3
Lydia
- I finished the translation of logic AND and logic OR.
- I went through the implementation ForIn Loop in swift and tried to translate reading and writing of array.
- I don’t know what the right CAST should be, especially the construction of array.
- There are 4 different types of CAstNode ARRAY_LITERAL ARRAY_REF OBJECT_LITERAL OBJECT_REF I don’t know which one should I use.
- I understand the distinction between "let" and "var". Using "let" means the declared object is a constant so it can not be modified afterwords.
var names = [“Anna”, “Alex”, “Brian”, “Jack”]
for name in names {
// We can't change the value of name!
print(name)
}
However, if we declare the iterator in ForIn Loop as a variable, we are able to modify it in the loop.
var names = ["Anna", "Alex", "Brian", "Jack"]
for var name in names {
name = "a "+name
}
- I find that for the code:
var names = [“Anna”, “Alex”, “Brian”, “Jack”]
swift firstly allocate uninitialized array and assign string to corresponding address, the it initialized this array and assign this array to variable “names”.
- I tried to implement translation of logic AND and logic OR.
- In my opinion, "TryApplyInst" corresponds to "try" and "catch" structure in c language. However, in this case, there is no "catchInst" but only ""TryApplyInst", so I have no idea about how to translate this instruction into two part.
- TryApplyInst calls Swift.Bool.&& infix() in this case, and its arguments are the first bool literal and a function reference which creates the second bool. This function is created while compiling swift code, so I am not very clear what the final CAST should be look like.
- For those functions created during compilation, we can find their definition code through the address of SILFunction.
- TryApplyInst will has two destination Basic Block. When the funciton returns, control resumes in either the normal destination (if it returns with "return") or the error destination (if it returns with "throw").
- I will finish the translation of logic AND and logic OR.
- I supplemented some functions for the handler of "BranchInst" so that it will create an ASSIGN node while binding given values to arguments for destination basic block.
- I implemented the expression of "ReturnInst" in CAST.
- The difficulty I met this week has been resolved with the help of Julian and Chen.
- I test a special case in which return instructions are in if-else statements. By carefully reading the SIL file generated by it, I found that "branchInst" will bind given values to arguments of destination basic block and the return instruction in destination block will regard its argument as return value.
func use_ints(num1: Int, num2: Int, num3: Int) -> Int{
var num4 = num1 + num2
if (num1 < 5 ) {
return (num4 - num3)
} else {
return (num4 * num3)
}
}
var t = use_ints(num1: 1, num2: 2, num3: 3);
The CAST is like below:
FOO: 1836019240:BLOCK
LABEL_STMT
"BLOCK #0"
ASSIGN
VAR
"num4"
BINARY_EXPR
"+"
VAR
"num1"
VAR
"num2"
IF_STMT
CALL
FUNCTION_EXPR
"Swift.Bool._getBuiltinLogicValue() -> Builtin.Int1"
BINARY_EXPR
"<"
VAR
"num1"
CALL
FUNCTION_EXPR
"Swift.Int.init(_builtinIntegerLiteral: Builtin.Int2048) -> Swift.Int"
"5"
GOTO
"BLOCK #1"
GOTO
"BLOCK #2"
FOO: 325040804:BLOCK
LABEL_STMT
"BLOCK #1"
ASSIGN
VAR
"argument0"
BINARY_EXPR
"-"
VAR
"num4"
VAR
"num3"
GOTO
"BLOCK #3"
FOO: 1173230247:BLOCK
LABEL_STMT
"BLOCK #2"
ASSIGN
VAR
"argument0"
BINARY_EXPR
"*"
VAR
"num4"
VAR
"num3"
GOTO
"BLOCK #3"
FOO: 856419764:BLOCK
LABEL_STMT
"BLOCK #3"
RETURN
VAR
"argument0"
- I plan to help Chen to deal with the implicit closure.
- I finished the work of expressing arguments normally in user-defined functions.
- I implemented the expression of local variables in user-defined functions.
- When I declare a local variable in the function with a value assigned to it, I found that there is no SILInstrunction "ASSIGN", but "StoreInst" instead. However, this instruction can be used as many situations such as storing stack pointer while allocating new space. I modify the handler of "StoreInst" so that it will create a "ASSIGN" node if the destination is variable. Till now, all test cases can work well but I ma not sure whether this measure is appropriate enough.
- I learned how the swift compiler works to deal with the passing of parameters and allocating for local variables.
- I will implement the return instruction in CAST.
- I plan to go through expression of enumeration and loop of swift in CAST.
- I modified the switch statement in WALAWalker so that some previously unhandled cases are now being processed. (CopyValueInst, DestroyValueInst, BeginBorrowInst, DebugValueInst)
- I tried to resolve the problem that expression of function's arguments in CAST but I have not finished yet.
When an used-defined function is called, its arguments can't be presented well as below:
func add_str(op1:String,op2:String) -> String{
return (op1+op2)
}
its CAST tree is like this:
LABEL_STMT
"BLOCK #0"
BINARY_EXPR
"+"
(null)
(null)
When I checked its arguments' address in <> and I found that there is no instructions to create CAST nodes for them. So I wonder how to express arguments of a function no matter whether it is called.
- I learned that debug_value in SIL is to indicates that the value of a declaration with loadable type has changed value to the specified operand. *I learned that load_borrow instruction in SIL creates a borrowed scope in which a read-only borrow value %1 can be used to read the value stored in %0.
- I will continue working on expressing arguments of user-defined functions in CAST.
- I worked on a part of if statement.
- I finished the implementation of reading and writing variables.
- I tested some cases and found that I might mix up the difference between expression and statement. In somehow the tree-like output looks very strange and I tried to figure out the problem.
The problem is that if I set FUNCTION_EXPR as a child of block statement, when I test the below code:
var a = ""
if (true) {
a = a + "x"
} else {
a = a + "y"
}
a = a + "z"
The tree structure returned will present FUNCTION_EXPR twice, such as below:
FOO: 1836019240:BLOCK
LABEL_STMT
"BLOCK #1"
FUNCTION_EXPR
"static Swift.String.+ infix(Swift.String, Swift.String) -> Swift.String"
FUNCTION_EXPR
"Swift.String.init(_builtinStringLiteral: Builtin.RawPointer, utf8CodeUnitCount: Builtin.Word, isASCII: Builtin.Int1) -> Swift.String"
BINARY_EXPR
"+"
VAR
"_T08nodetest1aSSvp"
CALL
FUNCTION_EXPR
"Swift.String.init(_builtinStringLiteral: Builtin.RawPointer, utf8CodeUnitCount: Builtin.Word, isASCII: Builtin.Int1) -> Swift.String"
"x"
"1"
"-1"
ASSIGN
VAR
"_T08nodetest1aSSvp"
BINARY_EXPR
"+"
VAR
"_T08nodetest1aSSvp"
CALL
FUNCTION_EXPR
"Swift.String.init(_builtinStringLiteral: Builtin.RawPointer, utf8CodeUnitCount: Builtin.Word, isASCII: Builtin.Int1) -> Swift.String"
"x"
"1"
"-1"
GOTO
"BLOCK #3"
But if I remove FUNCTION_EXPR from block statement's children, when I test the below code:
func add_str(op1:String,op2:String) -> String{
return (op1+op2)
}
var c = add_str(op1:"qwe",op2:"weq")
it only returns
FOO: 2133927002:BLOCK
LABEL_STMT
"BLOCK #0"
"0"
That's what I am confused about.
- Global variables are declared and definied using 3 instructions: AllocGlobalInst, GlobalAddrInst, StoreInst. They are read through instructions "Begin Access" "Load Inst" and "End Access", they are written through "Begin Access", "Assign Inst' and "End Access".
- The AST structure of reading variables is Node(var) with variable's name as child node, and the ASTs structure of writing values into variables is Node(Assign) with Node(Var)and Node(expression) as children.
- I found that a SILBasicBlock is a container of SILInstructions because I'm able to retrieve all instructions in a block from a SILBasicBlock.
- I'm going to finish work on variables and distinct clear between expression and statement.
- I'm going to help Chen's work on separating built-in binary/unary operators with regular function calls.
- I made some tests on makeNode() functions and found the relationship between constant numbers such as "1" and their AST means. For example, if I want to create an CAST node whose syntax is "LOOP", I can call makeNode(3). But obviously speaking, it is not practical to use simple constants because there are too many operators and node types.
- At the beginning, I insisted that using SILValue as the key for hash map which stores CAST nodes. So I spent a lot of time detecting the relationship between SILInstruction, SILValue and Valuebase and trying to find out a method which can fetch SILValue from SILInstruction. What made me raise the idea that we can use SILValue as the key is that: firstly, through getArgument() I can get SILValue of all arguments of a function call; secondly, for each CAST node created, there must be an SILInstruction corresponding to it. However, after exploring and analyzing, I found using SILValue may not be a good idea. Thanks to the help of Jeff, I found that the address of SILInstruction is as same as that of ValueBase stored in SILValue. Consequently, a hash map using the address of SILInstruction is much more practical.
- Based on what I have done above, I implemented a simple CAST tree with "FUNC_STMT" as root node and its arguments as children. What's more, there are many different makeNode() functions which connect different number of children to their parent node. Therefore, I store fetched argument node in a vector so for a specific number of arguments, I can call the corresponding function.
- In order to build simple CAST tree, I need integer node as child node. Since the other group has not been done on their work, I just write a little code on integer literal so that I can continue my test.
- It is impractical to use constants as the parameters for makeNode() function, but I can't find a valid way to use macro instead. It seems that macros of all operators and node types have been written well but when the program is ran, it returns "unknown" instead of right type of the node.
- By printing all arguments of a function call, I found there are more arguments than what I imagine before, such as metatype argument which is the last argument for all function calls. Therefore, I am not sure which and what arguments should be connected to the function node.
- Based on the output, I found that the function name is pretty long. Since I need to create different function nodes according to the type of function, it will be a matter to extract useful function name from those long strings.
- It is very important to select an appropriate key for hash map, so I think the huge time Chen and I spent on discussing and testing different key candidates is worthy. Moreover, during exploring this great amount of code, I know much better about the relation between SILInstruction, SILValue, SILType and Valuebase. SILValue is a wrapper around a ValueBase pointer. The underlying ValueBase pointer can be gotten through: SILValue::getOpaqueValue(). The class SILInstruction is inherited from the calss ValueBase. Beacuse of that, getting value of SILInstruction is practical.
- Chen and I have decided to set Tuesday afternoon and Saturday afternoon as our regular programming day. So I maintain that our efficiency will be boost up.
- I will solve the problem of nonavailability in macro use for function makeNode().
- I will start on distinguishing different function call based on their names.
####Past week: Since I got a Mac, I tried to install swift and WALA on my own machine. Although there were several difficulties, fortunately I built them successfully with the help of Julian and Jeff. According to my well configured environment, it is much easier for me to modify code and run test. Based on what I have done last week, I tried more tests on operations of string such as string equality and self-defined string concatenation. These tests told me that operations of string in swift are all function calls and they have quite complex structure, so it might not be very east to translate string operation in swift into expression node in WALA AST. As I have known from our meetings, I was aware that, for example, we should create an OP_ADD node and two constant nodes for string concatenation for WALA. Consequently, I attempted to detect the add operation in swift text and call makeNode function based on that. But it doesn't success until now.
The problem is that I can't find a method to detect there is a string operation in swift code. In the file WALAWalker, we have a switch branch whose name is "ApplyInst", all expressions and function calls are dealt with this branch, so a effective way to distinct string operation from other instructions is needed in translating them into WALA node. However, there is no direct way to print out the name of the callee or what the function does. Too many wraps are there that I have no idea about what some data structures, such as SILValue, SILFunction and SILType really are. so it is difficult to confirm whether this instruction is string operation or not.
when I ran test on string equality, I found that we can see some interesting results. What I run is the following code:
let spain = "España"
let tilde = "\u{303}"
let country = "Espan" + "\(tilde)" + "a"
if country == spain {
print("Matched!") // "Matched!\n"
}
Since I print all standard output I can get, I found that the name of function can be printed out, some function names are listed as following:
[OPER]: // function_ref String.init(_builtinStringLiteral:utf8CodeUnitCount:isASCII:)
%30 = function_ref @_T0S2SBp21_builtinStringLiteral_Bw17utf8CodeUnitCountBi1_7isASCIItcfC : $@convention(method) (Builtin.RawPointer, Builtin.Word, Builtin.Int1, @thin String.Type) -> @owned String // user: %31
[OPER]: // function_ref _allocateUninitializedArray<A>(_:)
%35 = function_ref @_T0s27_allocateUninitializedArraySayxG_BptBwlF : $@convention(thin) <τ_0_0> (Builtin.Word) -> (@owned Array<τ_0_0>, Builtin.RawPointer) // user: %36
[OPER]: // function_ref static String.+ infix(_:_:)
%24 = function_ref @_T0SS1poiS2S_SStFZ : $@convention(method) (@owned String, @owned String, @thin String.Type) -> @owned String // user: %83
[OPER]: // function_ref static String.== infix(_:_:)
%93 = function_ref @_T0SS2eeoiSbSS_SStFZ : $@convention(method) (@owned String, @owned String, @thin String.Type) -> Bool // user: %97
As we can see from the function reference, String.init is the function used to assign value to a string variable, String.+ represents string concatenation, and String.== represents string comparison. Consequently, what I need to do is find the member function which can give me the reference name of function. With those names, I can deal with different string operations.
I will continue my work on translating function call in swift to expression node in WALA and find an effective way to detect the details of instruction.
Firstly, since I can't build swift and WALA on my own machine and there is some problems with my private key for server, testing my code is impossible for me. Based on this situation, I didn't do much coding in the past week. Instead, I watched some videos about SIL and WALA offered in the reference link. Secondly, Chen and I spent a lot of time on transforming binary addition of swift from method call into expression in WALA, but we didn't make a big progress on it. Currently, we only get aware of the sequence of method calls when we use binary addition in swift and the difference between calling a self-defined function and calling binary addition directly.
In the beginning, I have a misunderstanding about the requirement of the transformation on binary addition. It cost me some time on detecting the structure of "SILFunction" and the definition of "ValueType". I made some attempts on printing the type of arguments but I failed. After discussion with Chen, we found the critical problem is to understand the expression structure of WALA and to transform method call in swift to expression in WALA. Consequently, I think what I need to do next week is understanding the expression in WALA and implementing the transformation.
During the test, I found that three functions will be called while calling binary addition of two strings. For example "a"+"b": [1] Assign "a" to a temporary variable; [2] Assign "b" to a temporary variable; [3] Concatenate "a" and "b", and assign the value to a variable; I have learned a compiler course in school but this process is different from what I learned in the class. In my opinion, the third step is to store concatenating result into a temporary variable and there should be the forth step assigning the value of temporary variable to the variable we declared. However, the program only prints the above three steps and this makes me very curious.
As I have mentioned above, I can't do any attempts on my own because I can't get access to the server. I believe it will be more convenient after the problem with the public key of server is fixed. Therefore, I plan to learn expression in WALA and implement the transformation between swift's method call and WALA's expression.