OSDN Git Service

Support int-to-long conversions in the optimizing compiler.
authorRoland Levillain <rpl@google.com>
Wed, 5 Nov 2014 14:15:05 +0000 (14:15 +0000)
committerRoland Levillain <rpl@google.com>
Wed, 5 Nov 2014 16:51:59 +0000 (16:51 +0000)
- Add support for the int-to-float Dex instruction in the
  optimizing compiler.
- Add a HTypeConversion node type for control-flow graphs.
- Generate x86, x86-64 and ARM (but not ARM64) code for
  int-to-float HTypeConversion nodes.
- Add a 64-bit "Move doubleword to quadword with
  sign-extension" (MOVSXD) instruction to the x86-64
  assembler.
- Add related tests to test/422-type-conversion.

Change-Id: Ieb8ec5380f9c411857119c79aa8d0728fd10f780

13 files changed:
compiler/optimizing/builder.cc
compiler/optimizing/builder.h
compiler/optimizing/code_generator_arm.cc
compiler/optimizing/code_generator_arm64.cc
compiler/optimizing/code_generator_x86.cc
compiler/optimizing/code_generator_x86_64.cc
compiler/optimizing/nodes.h
compiler/utils/x86_64/assembler_x86_64.cc
compiler/utils/x86_64/assembler_x86_64.h
test/422-type-conversion/expected.txt [new file with mode: 0644]
test/422-type-conversion/info.txt [new file with mode: 0644]
test/422-type-conversion/src/Main.java [new file with mode: 0644]
test/Android.run-test.mk

index d168fc8..4ce23d7 100644 (file)
@@ -273,6 +273,14 @@ void HGraphBuilder::Unop_12x(const Instruction& instruction, Primitive::Type typ
   UpdateLocal(instruction.VRegA(), current_block_->GetLastInstruction());
 }
 
+void HGraphBuilder::Conversion_12x(const Instruction& instruction,
+                                   Primitive::Type input_type,
+                                   Primitive::Type result_type) {
+  HInstruction* first = LoadLocal(instruction.VRegB(), input_type);
+  current_block_->AddInstruction(new (arena_) HTypeConversion(result_type, first));
+  UpdateLocal(instruction.VRegA(), current_block_->GetLastInstruction());
+}
+
 template<typename T>
 void HGraphBuilder::Binop_23x(const Instruction& instruction, Primitive::Type type) {
   HInstruction* first = LoadLocal(instruction.VRegB(), type);
@@ -823,6 +831,11 @@ bool HGraphBuilder::AnalyzeDexInstruction(const Instruction& instruction, uint32
       break;
     }
 
+    case Instruction::INT_TO_LONG: {
+      Conversion_12x(instruction, Primitive::kPrimInt, Primitive::kPrimLong);
+      break;
+    }
+
     case Instruction::ADD_INT: {
       Binop_23x<HAdd>(instruction, Primitive::kPrimInt);
       break;
index eea762f..f25415b 100644 (file)
@@ -116,6 +116,10 @@ class HGraphBuilder : public ValueObject {
   template<typename T> void If_21t(const Instruction& instruction, uint32_t dex_offset);
   template<typename T> void If_22t(const Instruction& instruction, uint32_t dex_offset);
 
+  void Conversion_12x(const Instruction& instruction,
+                      Primitive::Type input_type,
+                      Primitive::Type result_type);
+
   void BuildReturn(const Instruction& instruction, Primitive::Type type);
 
   // Builds an instance field access node and returns whether the instruction is supported.
index 6e6d64c..39e564a 100644 (file)
@@ -1223,6 +1223,94 @@ void InstructionCodeGeneratorARM::VisitNeg(HNeg* neg) {
   }
 }
 
+void LocationsBuilderARM::VisitTypeConversion(HTypeConversion* conversion) {
+  LocationSummary* locations =
+      new (GetGraph()->GetArena()) LocationSummary(conversion, LocationSummary::kNoCall);
+  Primitive::Type result_type = conversion->GetResultType();
+  Primitive::Type input_type = conversion->GetInputType();
+  switch (result_type) {
+    case Primitive::kPrimLong:
+      switch (input_type) {
+        case Primitive::kPrimByte:
+        case Primitive::kPrimShort:
+        case Primitive::kPrimInt:
+          // int-to-long conversion.
+          locations->SetInAt(0, Location::RequiresRegister());
+          locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
+          break;
+
+        case Primitive::kPrimFloat:
+        case Primitive::kPrimDouble:
+          LOG(FATAL) << "Type conversion from " << input_type << " to "
+                     << result_type << " not yet implemented";
+          break;
+
+        default:
+          LOG(FATAL) << "Unexpected type conversion from " << input_type
+                     << " to " << result_type;
+      }
+      break;
+
+    case Primitive::kPrimInt:
+    case Primitive::kPrimFloat:
+    case Primitive::kPrimDouble:
+      LOG(FATAL) << "Type conversion from " << input_type
+                 << " to " << result_type << " not yet implemented";
+      break;
+
+    default:
+      LOG(FATAL) << "Unexpected type conversion from " << input_type
+                 << " to " << result_type;
+  }
+}
+
+void InstructionCodeGeneratorARM::VisitTypeConversion(HTypeConversion* conversion) {
+  LocationSummary* locations = conversion->GetLocations();
+  Location out = locations->Out();
+  Location in = locations->InAt(0);
+  Primitive::Type result_type = conversion->GetResultType();
+  Primitive::Type input_type = conversion->GetInputType();
+  switch (result_type) {
+    case Primitive::kPrimLong:
+      switch (input_type) {
+        case Primitive::kPrimByte:
+        case Primitive::kPrimShort:
+        case Primitive::kPrimInt:
+          // int-to-long conversion.
+          DCHECK(out.IsRegisterPair());
+          DCHECK(in.IsRegister());
+          __ Mov(out.AsRegisterPairLow<Register>(), in.As<Register>());
+          // Sign extension.
+          __ Asr(out.AsRegisterPairHigh<Register>(),
+                 out.AsRegisterPairLow<Register>(),
+                 31);
+          break;
+
+        case Primitive::kPrimFloat:
+        case Primitive::kPrimDouble:
+          LOG(FATAL) << "Type conversion from " << input_type << " to "
+                     << result_type << " not yet implemented";
+          break;
+
+        default:
+          LOG(FATAL) << "Unexpected type conversion from " << input_type
+                     << " to " << result_type;
+      }
+      break;
+
+    case Primitive::kPrimInt:
+    case Primitive::kPrimFloat:
+    case Primitive::kPrimDouble:
+      LOG(FATAL) << "Type conversion from " << input_type
+                 << " to " << result_type << " not yet implemented";
+      break;
+
+    default:
+      LOG(FATAL) << "Unexpected type conversion from " << input_type
+                 << " to " << result_type;
+  }
+}
+
 void LocationsBuilderARM::VisitAdd(HAdd* add) {
   LocationSummary* locations =
       new (GetGraph()->GetArena()) LocationSummary(add, LocationSummary::kNoCall);
index 90d7c35..1c5db9e 100644 (file)
@@ -545,6 +545,7 @@ InstructionCodeGeneratorARM64::InstructionCodeGeneratorARM64(HGraph* graph,
   M(ParallelMove)                                          \
   M(StaticFieldGet)                                        \
   M(StaticFieldSet)                                        \
+  M(TypeConversion)                                        \
 
 #define UNIMPLEMENTED_INSTRUCTION_BREAK_CODE(name) name##UnimplementedInstructionBreakCode
 
index 1e37909..8132e81 100644 (file)
@@ -1126,6 +1126,91 @@ void InstructionCodeGeneratorX86::VisitNeg(HNeg* neg) {
   }
 }
 
+void LocationsBuilderX86::VisitTypeConversion(HTypeConversion* conversion) {
+  LocationSummary* locations =
+      new (GetGraph()->GetArena()) LocationSummary(conversion, LocationSummary::kNoCall);
+  Primitive::Type result_type = conversion->GetResultType();
+  Primitive::Type input_type = conversion->GetInputType();
+  switch (result_type) {
+    case Primitive::kPrimLong:
+      switch (input_type) {
+        case Primitive::kPrimByte:
+        case Primitive::kPrimShort:
+        case Primitive::kPrimInt:
+          // int-to-long conversion.
+          locations->SetInAt(0, Location::RegisterLocation(EAX));
+          locations->SetOut(Location::RegisterPairLocation(EAX, EDX));
+          break;
+
+        case Primitive::kPrimFloat:
+        case Primitive::kPrimDouble:
+          LOG(FATAL) << "Type conversion from " << input_type << " to "
+                     << result_type << " not yet implemented";
+          break;
+
+        default:
+          LOG(FATAL) << "Unexpected type conversion from " << input_type
+                     << " to " << result_type;
+      }
+      break;
+
+    case Primitive::kPrimInt:
+    case Primitive::kPrimFloat:
+    case Primitive::kPrimDouble:
+      LOG(FATAL) << "Type conversion from " << input_type
+                 << " to " << result_type << " not yet implemented";
+      break;
+
+    default:
+      LOG(FATAL) << "Unexpected type conversion from " << input_type
+                 << " to " << result_type;
+  }
+}
+
+void InstructionCodeGeneratorX86::VisitTypeConversion(HTypeConversion* conversion) {
+  LocationSummary* locations = conversion->GetLocations();
+  Location out = locations->Out();
+  Location in = locations->InAt(0);
+  Primitive::Type result_type = conversion->GetResultType();
+  Primitive::Type input_type = conversion->GetInputType();
+  switch (result_type) {
+    case Primitive::kPrimLong:
+      switch (input_type) {
+        case Primitive::kPrimByte:
+        case Primitive::kPrimShort:
+        case Primitive::kPrimInt:
+          // int-to-long conversion.
+          DCHECK_EQ(out.AsRegisterPairLow<Register>(), EAX);
+          DCHECK_EQ(out.AsRegisterPairHigh<Register>(), EDX);
+          DCHECK_EQ(in.As<Register>(), EAX);
+          __ cdq();
+          break;
+
+        case Primitive::kPrimFloat:
+        case Primitive::kPrimDouble:
+          LOG(FATAL) << "Type conversion from " << input_type << " to "
+                     << result_type << " not yet implemented";
+          break;
+
+        default:
+          LOG(FATAL) << "Unexpected type conversion from " << input_type
+                     << " to " << result_type;
+      }
+      break;
+
+    case Primitive::kPrimInt:
+    case Primitive::kPrimFloat:
+    case Primitive::kPrimDouble:
+      LOG(FATAL) << "Type conversion from " << input_type
+                 << " to " << result_type << " not yet implemented";
+      break;
+
+    default:
+      LOG(FATAL) << "Unexpected type conversion from " << input_type
+                 << " to " << result_type;
+  }
+}
+
 void LocationsBuilderX86::VisitAdd(HAdd* add) {
   LocationSummary* locations =
       new (GetGraph()->GetArena()) LocationSummary(add, LocationSummary::kNoCall);
index 40eec9b..d9eb17c 100644 (file)
@@ -1104,6 +1104,92 @@ void InstructionCodeGeneratorX86_64::VisitNeg(HNeg* neg) {
   }
 }
 
+void LocationsBuilderX86_64::VisitTypeConversion(HTypeConversion* conversion) {
+  LocationSummary* locations =
+      new (GetGraph()->GetArena()) LocationSummary(conversion, LocationSummary::kNoCall);
+  Primitive::Type result_type = conversion->GetResultType();
+  Primitive::Type input_type = conversion->GetInputType();
+  switch (result_type) {
+    case Primitive::kPrimLong:
+      switch (input_type) {
+        case Primitive::kPrimByte:
+        case Primitive::kPrimShort:
+        case Primitive::kPrimInt:
+          // int-to-long conversion.
+          // TODO: We would benefit from a (to-be-implemented)
+          // Location::RegisterOrStackSlot requirement for this input.
+          locations->SetInAt(0, Location::RequiresRegister());
+          locations->SetOut(Location::RequiresRegister());
+          break;
+
+        case Primitive::kPrimFloat:
+        case Primitive::kPrimDouble:
+          LOG(FATAL) << "Type conversion from " << input_type << " to "
+                     << result_type << " not yet implemented";
+          break;
+
+        default:
+          LOG(FATAL) << "Unexpected type conversion from " << input_type
+                     << " to " << result_type;
+      }
+      break;
+
+    case Primitive::kPrimInt:
+    case Primitive::kPrimFloat:
+    case Primitive::kPrimDouble:
+      LOG(FATAL) << "Type conversion from " << input_type
+                 << " to " << result_type << " not yet implemented";
+      break;
+
+    default:
+      LOG(FATAL) << "Unexpected type conversion from " << input_type
+                 << " to " << result_type;
+  }
+}
+
+void InstructionCodeGeneratorX86_64::VisitTypeConversion(HTypeConversion* conversion) {
+  LocationSummary* locations = conversion->GetLocations();
+  Location out = locations->Out();
+  Location in = locations->InAt(0);
+  Primitive::Type result_type = conversion->GetResultType();
+  Primitive::Type input_type = conversion->GetInputType();
+  switch (result_type) {
+    case Primitive::kPrimLong:
+      switch (input_type) {
+        DCHECK(out.IsRegister());
+        case Primitive::kPrimByte:
+        case Primitive::kPrimShort:
+        case Primitive::kPrimInt:
+          // int-to-long conversion.
+          DCHECK(in.IsRegister());
+          __ movsxd(out.As<CpuRegister>(), in.As<CpuRegister>());
+          break;
+
+        case Primitive::kPrimFloat:
+        case Primitive::kPrimDouble:
+          LOG(FATAL) << "Type conversion from " << input_type << " to "
+                     << result_type << " not yet implemented";
+          break;
+
+        default:
+          LOG(FATAL) << "Unexpected type conversion from " << input_type
+                     << " to " << result_type;
+      }
+      break;
+
+    case Primitive::kPrimInt:
+    case Primitive::kPrimFloat:
+    case Primitive::kPrimDouble:
+      LOG(FATAL) << "Type conversion from " << input_type
+                 << " to " << result_type << " not yet implemented";
+      break;
+
+    default:
+      LOG(FATAL) << "Unexpected type conversion from " << input_type
+                 << " to " << result_type;
+  }
+}
+
 void LocationsBuilderX86_64::VisitAdd(HAdd* add) {
   LocationSummary* locations =
       new (GetGraph()->GetArena()) LocationSummary(add, LocationSummary::kNoCall);
index 79638b3..d7069ca 100644 (file)
@@ -516,6 +516,7 @@ class HBasicBlock : public ArenaObject<kArenaAllocMisc> {
   M(Sub, BinaryOperation)                                               \
   M(SuspendCheck, Instruction)                                          \
   M(Temporary, Instruction)                                             \
+  M(TypeConversion, Instruction)                                        \
 
 #define FOR_EACH_INSTRUCTION(M)                                         \
   FOR_EACH_CONCRETE_INSTRUCTION(M)                                      \
@@ -1761,6 +1762,28 @@ class HNot : public HUnaryOperation {
   DISALLOW_COPY_AND_ASSIGN(HNot);
 };
 
+class HTypeConversion : public HExpression<1> {
+ public:
+  // Instantiate a type conversion of `input` to `result_type`.
+  HTypeConversion(Primitive::Type result_type, HInstruction* input)
+      : HExpression(result_type, SideEffects::None()) {
+    SetRawInputAt(0, input);
+    DCHECK_NE(input->GetType(), result_type);
+  }
+
+  HInstruction* GetInput() const { return InputAt(0); }
+  Primitive::Type GetInputType() const { return GetInput()->GetType(); }
+  Primitive::Type GetResultType() const { return GetType(); }
+
+  bool CanBeMoved() const OVERRIDE { return true; }
+  bool InstructionDataEquals(HInstruction* /* other */) const OVERRIDE { return true; }
+
+  DECLARE_INSTRUCTION(TypeConversion);
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(HTypeConversion);
+};
+
 class HPhi : public HInstruction {
  public:
   HPhi(ArenaAllocator* arena, uint32_t reg_number, size_t number_of_inputs, Primitive::Type type)
index 2e951dd..5b70658 100644 (file)
@@ -351,6 +351,22 @@ void X86_64Assembler::movss(XmmRegister dst, XmmRegister src) {
 }
 
 
+void X86_64Assembler::movsxd(CpuRegister dst, CpuRegister src) {
+  AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+  EmitRex64(dst);
+  EmitUint8(0x63);
+  EmitRegisterOperand(dst.LowBits(), src.LowBits());
+}
+
+
+void X86_64Assembler::movsxd(CpuRegister dst, const Address& src) {
+  AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+  EmitRex64(dst);
+  EmitUint8(0x63);
+  EmitOperand(dst.LowBits(), src);
+}
+
+
 void X86_64Assembler::movd(XmmRegister dst, CpuRegister src) {
   AssemblerBuffer::EnsureCapacity ensured(&buffer_);
   EmitUint8(0x66);
index 5b16f08..ed80e44 100644 (file)
@@ -300,6 +300,9 @@ class X86_64Assembler FINAL : public Assembler {
   void movss(const Address& dst, XmmRegister src);
   void movss(XmmRegister dst, XmmRegister src);
 
+  void movsxd(CpuRegister dst, CpuRegister src);
+  void movsxd(CpuRegister dst, const Address& src);
+
   void movd(XmmRegister dst, CpuRegister src);
   void movd(CpuRegister dst, XmmRegister src);
 
diff --git a/test/422-type-conversion/expected.txt b/test/422-type-conversion/expected.txt
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/test/422-type-conversion/info.txt b/test/422-type-conversion/info.txt
new file mode 100644 (file)
index 0000000..e734f32
--- /dev/null
@@ -0,0 +1 @@
+Tests for type conversions.
diff --git a/test/422-type-conversion/src/Main.java b/test/422-type-conversion/src/Main.java
new file mode 100644 (file)
index 0000000..9974919
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// Note that $opt$ is a marker for the optimizing compiler to ensure
+// it does compile the method.
+public class Main {
+
+  public static void assertEquals(long expected, long result) {
+    if (expected != result) {
+      throw new Error("Expected: " + expected + ", found: " + result);
+    }
+  }
+
+  public static void main(String[] args) {
+    intToLong();
+  }
+
+  private static void intToLong() {
+    assertEquals(1L, $opt$IntToLong(1));
+    assertEquals(0L, $opt$IntToLong(0));
+    assertEquals(-1L, $opt$IntToLong(-1));
+    assertEquals(51L, $opt$IntToLong(51));
+    assertEquals(-51L, $opt$IntToLong(-51));
+    assertEquals(2147483647L, $opt$IntToLong(2147483647));  // (2^31) - 1
+    assertEquals(-2147483647L, $opt$IntToLong(-2147483647));  // -(2^31) - 1
+    assertEquals(-2147483648L, $opt$IntToLong(-2147483648));  // -(2^31)
+  }
+
+  static long $opt$IntToLong(int a){
+    return a;
+  }
+}
index 0a1e3e1..a317f8c 100644 (file)
@@ -406,6 +406,7 @@ TEST_ART_BROKEN_OPTIMIZING_ARM64_RUN_TESTS := \
   418-const-string \
   419-long-parameter \
   420-const-class \
+  422-type-conversion \
   700-LoadArgRegs \
   701-easy-div-rem \
   702-LargeBranchOffset \