[LIR] Add support for new unboxed enum instance.

Also migrates legacy example tests stringbuilders, switches and switchmaps.

Bug: b/225838009
Bug: b/167145686
Change-Id: I0b2ce5d7fe80012716cd25036715fc284307399b
diff --git a/src/main/java/com/android/tools/r8/ir/code/NewUnboxedEnumInstance.java b/src/main/java/com/android/tools/r8/ir/code/NewUnboxedEnumInstance.java
index 123b988..d47c812 100644
--- a/src/main/java/com/android/tools/r8/ir/code/NewUnboxedEnumInstance.java
+++ b/src/main/java/com/android/tools/r8/ir/code/NewUnboxedEnumInstance.java
@@ -22,6 +22,7 @@
 import com.android.tools.r8.ir.optimize.InliningConstraints;
 import com.android.tools.r8.ir.optimize.enums.EnumUnboxer;
 import com.android.tools.r8.ir.optimize.enums.EnumUnboxerImpl;
+import com.android.tools.r8.lightir.LirBuilder;
 
 /**
  * Special instruction used by {@link EnumUnboxerImpl}.
@@ -166,4 +167,9 @@
   void internalRegisterUse(UseRegistry<?> registry, DexClassAndMethod context) {
     registry.registerNewUnboxedEnumInstance(clazz);
   }
+
+  @Override
+  public void buildLir(LirBuilder<Value, ?> builder) {
+    builder.addNewUnboxedEnumInstance(clazz, ordinal);
+  }
 }
diff --git a/src/main/java/com/android/tools/r8/lightir/Lir2IRConverter.java b/src/main/java/com/android/tools/r8/lightir/Lir2IRConverter.java
index abccb80..b02f968 100644
--- a/src/main/java/com/android/tools/r8/lightir/Lir2IRConverter.java
+++ b/src/main/java/com/android/tools/r8/lightir/Lir2IRConverter.java
@@ -56,6 +56,7 @@
 import com.android.tools.r8.ir.code.NewArrayEmpty;
 import com.android.tools.r8.ir.code.NewArrayFilledData;
 import com.android.tools.r8.ir.code.NewInstance;
+import com.android.tools.r8.ir.code.NewUnboxedEnumInstance;
 import com.android.tools.r8.ir.code.NumberConversion;
 import com.android.tools.r8.ir.code.NumberGenerator;
 import com.android.tools.r8.ir.code.NumericType;
@@ -763,5 +764,12 @@
           ArrayPut.createWithoutVerification(
               type, getValue(array), getValue(index), getValue(value)));
     }
+
+    @Override
+    public void onNewUnboxedEnumInstance(DexType clazz, int ordinal) {
+      TypeElement type = TypeElement.fromDexType(clazz, Nullability.definitelyNotNull(), appView);
+      Value dest = getOutValueForNextInstruction(type);
+      addInstruction(new NewUnboxedEnumInstance(clazz, ordinal, dest));
+    }
   }
 }
diff --git a/src/main/java/com/android/tools/r8/lightir/LirBuilder.java b/src/main/java/com/android/tools/r8/lightir/LirBuilder.java
index b0334c9..c19b47c 100644
--- a/src/main/java/com/android/tools/r8/lightir/LirBuilder.java
+++ b/src/main/java/com/android/tools/r8/lightir/LirBuilder.java
@@ -789,4 +789,13 @@
     return addInstructionTemplate(
         LirOpcodes.ITEMBASEDCONSTSTRING, ImmutableList.of(item, payload), Collections.emptyList());
   }
+
+  public LirBuilder<V, EV> addNewUnboxedEnumInstance(DexType clazz, int ordinal) {
+    advanceInstructionState();
+    int operandSize = constantIndexSize(clazz) + ByteUtils.intEncodingSize(ordinal);
+    writer.writeInstruction(LirOpcodes.NEWUNBOXEDENUMINSTANCE, operandSize);
+    writeConstantIndex(clazz);
+    ByteUtils.writeEncodedInt(ordinal, writer::writeOperand);
+    return this;
+  }
 }
diff --git a/src/main/java/com/android/tools/r8/lightir/LirOpcodes.java b/src/main/java/com/android/tools/r8/lightir/LirOpcodes.java
index e4111ff..19179aa 100644
--- a/src/main/java/com/android/tools/r8/lightir/LirOpcodes.java
+++ b/src/main/java/com/android/tools/r8/lightir/LirOpcodes.java
@@ -197,6 +197,7 @@
   int INVOKENEWARRAY = 214;
   int NEWARRAYFILLEDDATA = 215;
   int ITEMBASEDCONSTSTRING = 216;
+  int NEWUNBOXEDENUMINSTANCE = 217;
 
   static String toString(int opcode) {
     switch (opcode) {
@@ -515,6 +516,8 @@
         return "NEWARRAYFILLEDDATA";
       case ITEMBASEDCONSTSTRING:
         return "ITEMBASEDCONSTSTRING";
+      case NEWUNBOXEDENUMINSTANCE:
+        return "NEWUNBOXEDENUMINSTANCE";
 
       default:
         throw new Unreachable("Unexpected LIR opcode: " + opcode);
diff --git a/src/main/java/com/android/tools/r8/lightir/LirParsedInstructionCallback.java b/src/main/java/com/android/tools/r8/lightir/LirParsedInstructionCallback.java
index 8277988..3354fba 100644
--- a/src/main/java/com/android/tools/r8/lightir/LirParsedInstructionCallback.java
+++ b/src/main/java/com/android/tools/r8/lightir/LirParsedInstructionCallback.java
@@ -410,6 +410,10 @@
 
   public abstract void onMonitorExit(EV value);
 
+  public void onNewUnboxedEnumInstance(DexType type, int ordinal) {
+    onInstruction();
+  }
+
   private DexItem getConstantItem(int index) {
     return code.getConstantItem(index);
   }
@@ -1059,6 +1063,13 @@
           onDexItemBasedConstString(item, payload.nameComputationInfo);
           return;
         }
+      case LirOpcodes.NEWUNBOXEDENUMINSTANCE:
+        {
+          DexType type = getNextDexTypeOperand(view);
+          int ordinal = view.getNextIntegerOperand();
+          onNewUnboxedEnumInstance(type, ordinal);
+          return;
+        }
       default:
         throw new Unimplemented("No dispatch for opcode " + LirOpcodes.toString(opcode));
     }
diff --git a/src/main/java/com/android/tools/r8/lightir/LirPrinter.java b/src/main/java/com/android/tools/r8/lightir/LirPrinter.java
index 7aaf668..26a4694 100644
--- a/src/main/java/com/android/tools/r8/lightir/LirPrinter.java
+++ b/src/main/java/com/android/tools/r8/lightir/LirPrinter.java
@@ -379,4 +379,9 @@
   public void onMonitorExit(EV value) {
     appendValueArguments(value);
   }
+
+  @Override
+  public void onNewUnboxedEnumInstance(DexType type, int ordinal) {
+    appendOutValue().append("type(").append(type).append(") ordinal(").append(ordinal).append(")");
+  }
 }
diff --git a/src/test/java/com/android/tools/r8/R8RunExamplesTest.java b/src/test/java/com/android/tools/r8/R8RunExamplesTest.java
index a303b8c..c359fd9 100644
--- a/src/test/java/com/android/tools/r8/R8RunExamplesTest.java
+++ b/src/test/java/com/android/tools/r8/R8RunExamplesTest.java
@@ -27,8 +27,6 @@
     String[] tests = {
       "arithmetic.Arithmetic",
       "inlining.Inlining",
-      "stringbuilding.StringBuilding",
-      "switches.Switches",
       "sync.Sync",
       "throwing.Throwing",
       "trivial.Trivial",
@@ -51,7 +49,6 @@
       "minification.Minification",
       "enclosingmethod.Main",
       "enclosingmethod_proguarded.Main",
-      "switchmaps.Switches",
       "uninitializedfinal.UninitializedFinalFieldLeak",
     };
 
diff --git a/src/test/java/com/android/tools/r8/debug/ExamplesDebugTest.java b/src/test/java/com/android/tools/r8/debug/ExamplesDebugTest.java
index c870a8e..c1bf716 100644
--- a/src/test/java/com/android/tools/r8/debug/ExamplesDebugTest.java
+++ b/src/test/java/com/android/tools/r8/debug/ExamplesDebugTest.java
@@ -60,16 +60,6 @@
   }
 
   @Test
-  public void testStringBuilding() throws Exception {
-    testDebugging("stringbuilding", "StringBuilding");
-  }
-
-  @Test
-  public void testSwitches() throws Exception {
-    testDebugging("switches", "Switches");
-  }
-
-  @Test
   public void testSync() throws Exception {
     // TODO(b/79671093): Line number mismatch in D8.
     testDebuggingJvmOnly("sync", "Sync");
@@ -179,12 +169,6 @@
     testDebuggingJvmOutputOnly("enclosingmethod_proguarded", "Main");
   }
 
-  @Test
-  public void testSwitchmaps() throws Exception {
-    // TODO(b/79671093): D8 has different line number info during stepping.
-    testDebuggingJvmOnly("switchmaps", "Switches");
-  }
-
   private void testDebugging(String pkg, String clazz) throws Exception {
     init(pkg, clazz)
         .add("Input", input())
diff --git a/src/test/java/com/android/tools/r8/examples/returns/StaticFieldTestRunner.java b/src/test/java/com/android/tools/r8/examples/staticfield/StaticFieldTestRunner.java
similarity index 92%
rename from src/test/java/com/android/tools/r8/examples/returns/StaticFieldTestRunner.java
rename to src/test/java/com/android/tools/r8/examples/staticfield/StaticFieldTestRunner.java
index 81ca334..3cb14eb 100644
--- a/src/test/java/com/android/tools/r8/examples/returns/StaticFieldTestRunner.java
+++ b/src/test/java/com/android/tools/r8/examples/staticfield/StaticFieldTestRunner.java
@@ -1,12 +1,11 @@
 // Copyright (c) 2023, 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.
-package com.android.tools.r8.examples.returns;
+package com.android.tools.r8.examples.staticfield;
 
 import com.android.tools.r8.TestParameters;
 import com.android.tools.r8.TestParametersCollection;
 import com.android.tools.r8.examples.ExamplesTestBase;
-import com.android.tools.r8.examples.staticfield.StaticField;
 import com.android.tools.r8.utils.StringUtils;
 import org.junit.Assume;
 import org.junit.Test;
diff --git a/src/test/examples/stringbuilding/StringBuilding.java b/src/test/java/com/android/tools/r8/examples/stringbuilding/StringBuilding.java
similarity index 96%
rename from src/test/examples/stringbuilding/StringBuilding.java
rename to src/test/java/com/android/tools/r8/examples/stringbuilding/StringBuilding.java
index 18152fb..0805f37 100644
--- a/src/test/examples/stringbuilding/StringBuilding.java
+++ b/src/test/java/com/android/tools/r8/examples/stringbuilding/StringBuilding.java
@@ -5,7 +5,7 @@
 // This code is not run directly. It needs to be compiled to dex code.
 // 'stringbuilding.dex' is what is run.
 
-package stringbuilding;
+package com.android.tools.r8.examples.stringbuilding;
 
 class StringBuilding {
 
diff --git a/src/test/java/com/android/tools/r8/examples/returns/StaticFieldTestRunner.java b/src/test/java/com/android/tools/r8/examples/stringbuilding/StringBuildingTestRunner.java
similarity index 67%
copy from src/test/java/com/android/tools/r8/examples/returns/StaticFieldTestRunner.java
copy to src/test/java/com/android/tools/r8/examples/stringbuilding/StringBuildingTestRunner.java
index 81ca334..db98076 100644
--- a/src/test/java/com/android/tools/r8/examples/returns/StaticFieldTestRunner.java
+++ b/src/test/java/com/android/tools/r8/examples/stringbuilding/StringBuildingTestRunner.java
@@ -1,38 +1,43 @@
 // Copyright (c) 2023, 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.
-package com.android.tools.r8.examples.returns;
+package com.android.tools.r8.examples.stringbuilding;
 
 import com.android.tools.r8.TestParameters;
 import com.android.tools.r8.TestParametersCollection;
 import com.android.tools.r8.examples.ExamplesTestBase;
-import com.android.tools.r8.examples.staticfield.StaticField;
 import com.android.tools.r8.utils.StringUtils;
-import org.junit.Assume;
+import com.google.common.collect.ImmutableList;
+import java.util.List;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
 
 @RunWith(Parameterized.class)
-public class StaticFieldTestRunner extends ExamplesTestBase {
+public class StringBuildingTestRunner extends ExamplesTestBase {
 
   @Parameterized.Parameters(name = "{0}")
   public static TestParametersCollection data() {
     return getTestParameters().withAllRuntimesAndApiLevels().enableApiLevelsForCf().build();
   }
 
-  public StaticFieldTestRunner(TestParameters parameters) {
+  public StringBuildingTestRunner(TestParameters parameters) {
     super(parameters);
   }
 
   @Override
   public Class<?> getMainClass() {
-    return StaticField.class;
+    return StringBuilding.class;
+  }
+
+  @Override
+  public List<Class<?>> getTestClasses() throws Exception {
+    return ImmutableList.of(getMainClass(), StringBuilding.X.class);
   }
 
   @Override
   public String getExpected() {
-    return StringUtils.lines("101010", "101010", "ABC", "ABC");
+    return StringUtils.joinLines("a2c-xyz-abc7xyz", "trueABCDE1234232.21.101an Xstringbuilder");
   }
 
   @Test
@@ -47,8 +52,6 @@
 
   @Test
   public void testDebug() throws Exception {
-    // TODO(b/79671093): DEX has different line number info during stepping.
-    Assume.assumeTrue(parameters.isCfRuntime());
     runTestDebugComparator();
   }
 }
diff --git a/src/test/examples/switches/Switches.java b/src/test/java/com/android/tools/r8/examples/switches/Switches.java
similarity index 97%
rename from src/test/examples/switches/Switches.java
rename to src/test/java/com/android/tools/r8/examples/switches/Switches.java
index 588e541..a51e94b 100644
--- a/src/test/examples/switches/Switches.java
+++ b/src/test/java/com/android/tools/r8/examples/switches/Switches.java
@@ -5,7 +5,7 @@
 // This code is not run directly. It needs to be compiled to dex code.
 // 'switches.dex' is what is run.
 
-package switches;
+package com.android.tools.r8.examples.switches;
 
 class Switches {
 
diff --git a/src/test/java/com/android/tools/r8/examples/switches/SwitchesTestRunner.java b/src/test/java/com/android/tools/r8/examples/switches/SwitchesTestRunner.java
new file mode 100644
index 0000000..5bcd322
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/examples/switches/SwitchesTestRunner.java
@@ -0,0 +1,68 @@
+// Copyright (c) 2023, 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.
+package com.android.tools.r8.examples.switches;
+
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
+import com.android.tools.r8.examples.ExamplesTestBase;
+import com.android.tools.r8.utils.StringUtils;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+@RunWith(Parameterized.class)
+public class SwitchesTestRunner extends ExamplesTestBase {
+
+  @Parameterized.Parameters(name = "{0}")
+  public static TestParametersCollection data() {
+    return getTestParameters().withAllRuntimesAndApiLevels().enableApiLevelsForCf().build();
+  }
+
+  public SwitchesTestRunner(TestParameters parameters) {
+    super(parameters);
+  }
+
+  @Override
+  public Class<?> getMainClass() {
+    return Switches.class;
+  }
+
+  @Override
+  public String getExpected() {
+    return StringUtils.lines(
+        "packedSwitch cases: 0 1 2 after switch 0",
+        "packedSwitch cases: 1 2 after switch 1",
+        "packedSwitch cases: 1 2 after switch 2",
+        "packedSwitch cases: after switch -1",
+        "0 ",
+        "100 ",
+        "after switch 0",
+        "100 ",
+        "after switch 100",
+        "200 ",
+        "after switch 200",
+        "after switch -1",
+        " 420",
+        " 1.02",
+        "0-21 after switch 1",
+        "0-21 after switch 10",
+        "after switch 40",
+        "60 after switch 60");
+  }
+
+  @Test
+  public void testDesugaring() throws Exception {
+    runTestDesugaring();
+  }
+
+  @Test
+  public void testR8() throws Exception {
+    runTestR8();
+  }
+
+  @Test
+  public void testDebug() throws Exception {
+    runTestDebugComparator();
+  }
+}
diff --git a/src/test/examples/switchmaps/Colors.java b/src/test/java/com/android/tools/r8/examples/switchmaps/Colors.java
similarity index 89%
rename from src/test/examples/switchmaps/Colors.java
rename to src/test/java/com/android/tools/r8/examples/switchmaps/Colors.java
index b2c8dc1..15b4ad6 100644
--- a/src/test/examples/switchmaps/Colors.java
+++ b/src/test/java/com/android/tools/r8/examples/switchmaps/Colors.java
@@ -1,7 +1,7 @@
 // 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.
-package switchmaps;
+package com.android.tools.r8.examples.switchmaps;
 
 public enum Colors {
   RED("rar"), BLUE("blew"), GREEN("soylent"), GRAY("fifty");
diff --git a/src/test/examples/switchmaps/Days.java b/src/test/java/com/android/tools/r8/examples/switchmaps/Days.java
similarity index 85%
rename from src/test/examples/switchmaps/Days.java
rename to src/test/java/com/android/tools/r8/examples/switchmaps/Days.java
index b484bb5..710edfa 100644
--- a/src/test/examples/switchmaps/Days.java
+++ b/src/test/java/com/android/tools/r8/examples/switchmaps/Days.java
@@ -1,7 +1,7 @@
 // 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.
-package switchmaps;
+package com.android.tools.r8.examples.switchmaps;
 
 public enum Days {
   MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY;
diff --git a/src/test/java/com/android/tools/r8/examples/switchmaps/SwitchMapsTestRunner.java b/src/test/java/com/android/tools/r8/examples/switchmaps/SwitchMapsTestRunner.java
new file mode 100644
index 0000000..1fb0770
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/examples/switchmaps/SwitchMapsTestRunner.java
@@ -0,0 +1,89 @@
+// Copyright (c) 2023, 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.
+package com.android.tools.r8.examples.switchmaps;
+
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
+import com.android.tools.r8.examples.ExamplesTestBase;
+import com.android.tools.r8.utils.StringUtils;
+import com.google.common.collect.ImmutableList;
+import java.util.List;
+import org.junit.Assume;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+@RunWith(Parameterized.class)
+public class SwitchMapsTestRunner extends ExamplesTestBase {
+
+  @Parameterized.Parameters(name = "{0}")
+  public static TestParametersCollection data() {
+    return getTestParameters().withAllRuntimesAndApiLevels().enableApiLevelsForCf().build();
+  }
+
+  public SwitchMapsTestRunner(TestParameters parameters) {
+    super(parameters);
+  }
+
+  @Override
+  public Class<?> getMainClass() {
+    return Switches.class;
+  }
+
+  @Override
+  public List<Class<?>> getTestClasses() throws Exception {
+    return ImmutableList.of(
+        getMainClass(),
+        Class.forName(getMainClass().getTypeName() + "$1"),
+        Days.class,
+        Colors.class);
+  }
+
+  @Override
+  public String getExpected() {
+    return StringUtils.lines(
+        "other",
+        "1, 3 or 4",
+        "2 or 5",
+        "other",
+        "2 or 5",
+        "3 or 5",
+        "1, 3 or 4",
+        "2 or 5",
+        "other",
+        "1, 3 or 4",
+        "2 or 5",
+        "3 or 5",
+        "2 or 5",
+        "other",
+        "6",
+        "7",
+        "7",
+        "rar",
+        "colorful",
+        "blew",
+        "colorful",
+        "soylent",
+        "sooo green",
+        "fifty",
+        "not really");
+  }
+
+  @Test
+  public void testDesugaring() throws Exception {
+    runTestDesugaring();
+  }
+
+  @Test
+  public void testR8() throws Exception {
+    runTestR8();
+  }
+
+  @Test
+  public void testDebug() throws Exception {
+    // TODO(b/79671093): DEX has different line number info during stepping.
+    Assume.assumeTrue(parameters.isCfRuntime());
+    runTestDebugComparator();
+  }
+}
diff --git a/src/test/examples/switchmaps/Switches.java b/src/test/java/com/android/tools/r8/examples/switchmaps/Switches.java
similarity index 96%
rename from src/test/examples/switchmaps/Switches.java
rename to src/test/java/com/android/tools/r8/examples/switchmaps/Switches.java
index bf16856..4b5cb54 100644
--- a/src/test/examples/switchmaps/Switches.java
+++ b/src/test/java/com/android/tools/r8/examples/switchmaps/Switches.java
@@ -1,7 +1,7 @@
 // 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.
-package switchmaps;
+package com.android.tools.r8.examples.switchmaps;
 
 public class Switches {