ART: Move exception clearing into own instruction

Runtime delivers exceptions only to catch blocks which begin with a
MOVE_EXCEPTION instruction (in DEX). In that case, the catch block is
expected to clear the thread-local exception storage after having
read the exception reference.

This patch changes Optimizing to represent MOVE_EXCEPTION with two
instructions - HLoadException and HClearException - instead of one.
If the exception reference is not used, HLoadException can be safely
removed, saving a memory load without breaking the runtime behaviour.

Change-Id: Idad8a714467bf9d9d5fccefbc43c0bd8ae13ddba
diff --git a/compiler/optimizing/code_generator_arm64.cc b/compiler/optimizing/code_generator_arm64.cc
index 11de4ee..bbde7e8 100644
--- a/compiler/optimizing/code_generator_arm64.cc
+++ b/compiler/optimizing/code_generator_arm64.cc
@@ -2496,6 +2496,10 @@
   }
 }
 
+static MemOperand GetExceptionTlsAddress() {
+  return MemOperand(tr, Thread::ExceptionOffset<kArm64WordSize>().Int32Value());
+}
+
 void LocationsBuilderARM64::VisitLoadException(HLoadException* load) {
   LocationSummary* locations =
       new (GetGraph()->GetArena()) LocationSummary(load, LocationSummary::kNoCall);
@@ -2503,9 +2507,15 @@
 }
 
 void InstructionCodeGeneratorARM64::VisitLoadException(HLoadException* instruction) {
-  MemOperand exception = MemOperand(tr, Thread::ExceptionOffset<kArm64WordSize>().Int32Value());
-  __ Ldr(OutputRegister(instruction), exception);
-  __ Str(wzr, exception);
+  __ Ldr(OutputRegister(instruction), GetExceptionTlsAddress());
+}
+
+void LocationsBuilderARM64::VisitClearException(HClearException* clear) {
+  new (GetGraph()->GetArena()) LocationSummary(clear, LocationSummary::kNoCall);
+}
+
+void InstructionCodeGeneratorARM64::VisitClearException(HClearException* clear ATTRIBUTE_UNUSED) {
+  __ Str(wzr, GetExceptionTlsAddress());
 }
 
 void LocationsBuilderARM64::VisitLoadLocal(HLoadLocal* load) {