diff options
author | Eric Holk <eholk@google.com> | 2018-11-01 15:50:24 -0700 |
---|---|---|
committer | Eric Holk <eholk@google.com> | 2018-11-10 00:46:07 +0000 |
commit | d62c5aa954dd6c995f24353dbfd13c2b0bfb112a (patch) | |
tree | 494c9b360001b979dbc88e89f7d88beba7383bff /startop/view_compiler/dex_testcase_generator.cc | |
parent | b8740842e0da907c208ae3f1a1281c8985fcbcb9 (diff) |
[view compiler] Add conditional branch instruction
This CL adds support for the if-eqz instruction. It should be easy to add
additional comparisons as needed.
This also introduces a new kind of Value called a Label. Labels may be created
any time and then must be bound to a location in code at some point. References
to labels are tracked, and when a label is bound all references are patched to
refer to the concrete address.
Bug: 111895153
Change-Id: I15424aec75425004f0f1f4bbc6e760bac3a6c7de
Diffstat (limited to 'startop/view_compiler/dex_testcase_generator.cc')
-rw-r--r-- | startop/view_compiler/dex_testcase_generator.cc | 82 |
1 files changed, 75 insertions, 7 deletions
diff --git a/startop/view_compiler/dex_testcase_generator.cc b/startop/view_compiler/dex_testcase_generator.cc index 898817b4768c..c521bf2b8ccf 100644 --- a/startop/view_compiler/dex_testcase_generator.cc +++ b/startop/view_compiler/dex_testcase_generator.cc @@ -46,9 +46,11 @@ void GenerateSimpleTestCases(const string& outdir) { // int return5() { return 5; } auto return5{cbuilder.CreateMethod("return5", Prototype{TypeDescriptor::Int()})}; - Value r{return5.MakeRegister()}; - return5.BuildConst4(r, 5); - return5.BuildReturn(r); + { + Value r{return5.MakeRegister()}; + return5.BuildConst4(r, 5); + return5.BuildReturn(r); + } return5.Encode(); // // int returnParam(int x) { return x; } @@ -64,12 +66,78 @@ void GenerateSimpleTestCases(const string& outdir) { auto returnStringLength{ cbuilder.CreateMethod("returnStringLength", Prototype{TypeDescriptor::Int(), string_type})}; - Value result = returnStringLength.MakeRegister(); - returnStringLength.AddInstruction( - Instruction::InvokeVirtual(string_length.id, result, Value::Parameter(0))); - returnStringLength.BuildReturn(result); + { + Value result = returnStringLength.MakeRegister(); + returnStringLength.AddInstruction( + Instruction::InvokeVirtual(string_length.id, result, Value::Parameter(0))); + returnStringLength.BuildReturn(result); + } returnStringLength.Encode(); + // int returnIfZero(int x) { if (x == 0) { return 5; } else { return 3; } } + MethodBuilder returnIfZero{cbuilder.CreateMethod( + "returnIfZero", Prototype{TypeDescriptor::Int(), TypeDescriptor::Int()})}; + { + Value resultIfZero{returnIfZero.MakeRegister()}; + Value else_target{returnIfZero.MakeLabel()}; + returnIfZero.AddInstruction(Instruction::OpWithArgs( + Instruction::Op::kBranchEqz, /*dest=*/{}, Value::Parameter(0), else_target)); + // else branch + returnIfZero.BuildConst4(resultIfZero, 3); + returnIfZero.AddInstruction( + Instruction::OpWithArgs(Instruction::Op::kReturn, /*dest=*/{}, resultIfZero)); + // then branch + returnIfZero.AddInstruction( + Instruction::OpWithArgs(Instruction::Op::kBindLabel, /*dest=*/{}, else_target)); + returnIfZero.BuildConst4(resultIfZero, 5); + returnIfZero.AddInstruction( + Instruction::OpWithArgs(Instruction::Op::kReturn, /*dest=*/{}, resultIfZero)); + } + returnIfZero.Encode(); + + // Make sure backwards branches work too. + // + // Pseudo code for test: + // { + // zero = 0; + // result = 1; + // if (zero == 0) goto B; + // A: + // return result; + // B: + // result = 2; + // if (zero == 0) goto A; + // result = 3; + // return result; + // } + // If it runs correctly, this test should return 2. + MethodBuilder backwardsBranch{ + cbuilder.CreateMethod("backwardsBranch", Prototype{TypeDescriptor::Int()})}; + [](MethodBuilder& method) { + Value zero = method.MakeRegister(); + Value result = method.MakeRegister(); + Value labelA = method.MakeLabel(); + Value labelB = method.MakeLabel(); + method.BuildConst4(zero, 0); + method.BuildConst4(result, 1); + method.AddInstruction( + Instruction::OpWithArgs(Instruction::Op::kBranchEqz, /*dest=*/{}, zero, labelB)); + + method.AddInstruction( + Instruction::OpWithArgs(Instruction::Op::kBindLabel, /*dest=*/{}, labelA)); + method.BuildReturn(result); + + method.AddInstruction( + Instruction::OpWithArgs(Instruction::Op::kBindLabel, /*dest=*/{}, labelB)); + method.BuildConst4(result, 2); + method.AddInstruction( + Instruction::OpWithArgs(Instruction::Op::kBranchEqz, /*dest=*/{}, zero, labelA)); + + method.BuildConst4(result, 3); + method.BuildReturn(result); + }(backwardsBranch); + backwardsBranch.Encode(); + slicer::MemView image{dex_file.CreateImage()}; std::ofstream out_file(outdir + "/simple.dex"); out_file.write(image.ptr<const char>(), image.size()); |