Merge "Fix none.d8.Art370_dex_v37Test test specification:"
diff --git a/src/main/java/com/android/tools/r8/code/MulDouble.java b/src/main/java/com/android/tools/r8/code/MulDouble.java
index 2d63172..039f602 100644
--- a/src/main/java/com/android/tools/r8/code/MulDouble.java
+++ b/src/main/java/com/android/tools/r8/code/MulDouble.java
@@ -18,6 +18,11 @@
 
   public MulDouble(int dest, int left, int right) {
     super(dest, left, right);
+    // The art x86 backend had a bug that made it fail on "mul r0, r1, r0" instructions where
+    // the second src register and the dst register is the same (but the first src register is
+    // different). Therefore, we have to avoid generating that pattern. The bug was fixed for
+    // Android M: https://android-review.googlesource.com/#/c/114932/
+    assert dest != right || dest == left;
   }
 
   public String getName() {
diff --git a/src/main/java/com/android/tools/r8/code/MulFloat.java b/src/main/java/com/android/tools/r8/code/MulFloat.java
index bb10eaf..aa3eaa0 100644
--- a/src/main/java/com/android/tools/r8/code/MulFloat.java
+++ b/src/main/java/com/android/tools/r8/code/MulFloat.java
@@ -18,6 +18,11 @@
 
   public MulFloat(int dest, int left, int right) {
     super(dest, left, right);
+    // The art x86 backend had a bug that made it fail on "mul r0, r1, r0" instructions where
+    // the second src register and the dst register is the same (but the first src register is
+    // different). Therefore, we have to avoid generating that pattern. The bug was fixed for
+    // Android M: https://android-review.googlesource.com/#/c/114932/
+    assert dest != right || dest == left;
   }
 
   public String getName() {
diff --git a/src/main/java/com/android/tools/r8/code/MulInt.java b/src/main/java/com/android/tools/r8/code/MulInt.java
index cb24a89..28b2fb3 100644
--- a/src/main/java/com/android/tools/r8/code/MulInt.java
+++ b/src/main/java/com/android/tools/r8/code/MulInt.java
@@ -17,6 +17,11 @@
 
   public MulInt(int dest, int left, int right) {
     super(dest, left, right);
+    // The art x86 backend had a bug that made it fail on "mul r0, r1, r0" instructions where
+    // the second src register and the dst register is the same (but the first src register is
+    // different). Therefore, we have to avoid generating that pattern. The bug was fixed for
+    // Android M: https://android-review.googlesource.com/#/c/114932/
+    assert dest != right || dest == left;
   }
 
   public String getName() {
diff --git a/src/main/java/com/android/tools/r8/code/MulLong.java b/src/main/java/com/android/tools/r8/code/MulLong.java
index 487f786..d341c3c 100644
--- a/src/main/java/com/android/tools/r8/code/MulLong.java
+++ b/src/main/java/com/android/tools/r8/code/MulLong.java
@@ -18,6 +18,11 @@
 
   public MulLong(int dest, int left, int right) {
     super(dest, left, right);
+    // The art x86 backend had a bug that made it fail on "mul r0, r1, r0" instructions where
+    // the second src register and the dst register is the same (but the first src register is
+    // different). Therefore, we have to avoid generating that pattern. The bug was fixed for
+    // Android M: https://android-review.googlesource.com/#/c/114932/
+    assert dest != right || dest == left;
   }
 
   public String getName() {
diff --git a/src/main/java/com/android/tools/r8/ir/code/Mul.java b/src/main/java/com/android/tools/r8/ir/code/Mul.java
index 19024f5..67aca89 100644
--- a/src/main/java/com/android/tools/r8/ir/code/Mul.java
+++ b/src/main/java/com/android/tools/r8/ir/code/Mul.java
@@ -27,19 +27,31 @@
   }
 
   public com.android.tools.r8.code.Instruction CreateInt(int dest, int left, int right) {
-    return new MulInt(dest, left, right);
+    // Flip arguments if dest and right are the same to work around x86 code generation bug on
+    // Android L. See https://android-review.googlesource.com/#/c/114932/ for the fix for Android
+    // M.
+    return dest == right ? new MulInt(dest, right, left) : new MulInt(dest, left, right);
   }
 
   public com.android.tools.r8.code.Instruction CreateLong(int dest, int left, int right) {
-    return new MulLong(dest, left, right);
+    // Flip arguments if dest and right are the same to work around x86 code generation bug on
+    // Android L. See https://android-review.googlesource.com/#/c/114932/ for the fix for Android
+    // M.
+    return dest == right ? new MulLong(dest, right, left) : new MulLong(dest, left, right);
   }
 
   public com.android.tools.r8.code.Instruction CreateFloat(int dest, int left, int right) {
-    return new MulFloat(dest, left, right);
+    // Flip arguments if dest and right are the same to work around x86 code generation bug on
+    // Android L. See https://android-review.googlesource.com/#/c/114932/ for the fix for Android
+    // M.
+    return dest == right ? new MulFloat(dest, right, left) : new MulFloat(dest, left, right);
   }
 
   public com.android.tools.r8.code.Instruction CreateDouble(int dest, int left, int right) {
-    return new MulDouble(dest, left, right);
+    // Flip arguments if dest and right are the same to work around x86 code generation bug on
+    // Android L. See https://android-review.googlesource.com/#/c/114932/ for the fix for Android
+    // M.
+    return dest == right ? new MulDouble(dest, right, left) : new MulDouble(dest, left, right);
   }
 
   public com.android.tools.r8.code.Instruction CreateInt2Addr(int left, int right) {
diff --git a/src/main/java/com/android/tools/r8/shaking/ProguardConfigurationParser.java b/src/main/java/com/android/tools/r8/shaking/ProguardConfigurationParser.java
index c37948c..860fc45 100644
--- a/src/main/java/com/android/tools/r8/shaking/ProguardConfigurationParser.java
+++ b/src/main/java/com/android/tools/r8/shaking/ProguardConfigurationParser.java
@@ -40,6 +40,8 @@
       .of("protomapping",
           "optimizationpasses",
           "target");
+  private static final List<String> ignoredOptionalSingleArgOptions = ImmutableList
+      .of("keepdirectories");
   private static final List<String> ignoredFlagOptions = ImmutableList
       .of("forceprocessing", "dontusemixedcaseclassnames",
           "dontpreverify", "experimentalshrinkunusedprotofields",
@@ -121,6 +123,7 @@
       expectChar('-');
       String option;
       if (Iterables.any(ignoredSingleArgOptions, this::skipOptionWithSingleArg)
+          || Iterables.any(ignoredOptionalSingleArgOptions, this::skipOptionWithOptionalSingleArg)
           || Iterables.any(ignoredFlagOptions, this::skipFlag)
           || Iterables.any(ignoredClassDescriptorOptions, this::skipOptionWithClassSpec)
           || parseOptimizationOption()) {
@@ -261,6 +264,20 @@
       return false;
     }
 
+    private boolean skipOptionWithOptionalSingleArg(String name) {
+      if (acceptString(name)) {
+        if (Log.ENABLED) {
+          Log.debug(ProguardConfigurationParser.class, "Skipping '-%s` option", name);
+        }
+        skipWhitespace();
+        if (!eof() && peekChar() != '-') {
+          skipSingleArgument();
+        }
+        return true;
+      }
+      return false;
+    }
+
     private boolean skipOptionWithClassSpec(String name) {
       if (acceptString(name)) {
         if (Log.ENABLED) {
diff --git a/src/test/java/com/android/tools/r8/shaking/ProguardConfigurationParserTest.java b/src/test/java/com/android/tools/r8/shaking/ProguardConfigurationParserTest.java
index 727d533..5d5bc17 100644
--- a/src/test/java/com/android/tools/r8/shaking/ProguardConfigurationParserTest.java
+++ b/src/test/java/com/android/tools/r8/shaking/ProguardConfigurationParserTest.java
@@ -51,6 +51,8 @@
       VALID_PROGUARD_DIR + "seeds-2.flags";
   private static final String VERBOSE =
       VALID_PROGUARD_DIR + "verbose.flags";
+  private static final String KEEPDIRECTORIES =
+      VALID_PROGUARD_DIR + "keepdirectories.flags";
   private static final String DONT_OBFUSCATE =
       VALID_PROGUARD_DIR + "dontobfuscate.flags";
   private static final String DONT_SKIP_NON_PUBLIC_LIBRARY_CLASSES =
@@ -310,6 +312,12 @@
   }
 
   @Test
+  public void parseKeepdirectories() throws IOException, ProguardRuleParserException {
+    ProguardConfigurationParser parser = new ProguardConfigurationParser(new DexItemFactory());
+    parser.parse(Paths.get(KEEPDIRECTORIES));
+  }
+
+  @Test
   public void parseDontSkipNonPublicLibraryClasses()
       throws IOException, ProguardRuleParserException {
     ProguardConfigurationParser parser = new ProguardConfigurationParser(new DexItemFactory());
diff --git a/src/test/proguard/valid/keepdirectories.flags b/src/test/proguard/valid/keepdirectories.flags
new file mode 100644
index 0000000..b78e3aa
--- /dev/null
+++ b/src/test/proguard/valid/keepdirectories.flags
@@ -0,0 +1,9 @@
+# Copyright (c) 2017, the R8 project authors. Please see the AUTHORS file
+# for details. All rights reserved. Use of this source code is governed by a
+# BSD-style license that can be found in the LICENSE file.
+-keepdirectories
+
+-keepdirectories toto/titi
+-keepdirectories **
+-keepdirectories
+