summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--compiler/elf_writer.cc13
-rw-r--r--compiler/elf_writer.h4
-rw-r--r--compiler/image_writer.cc2
-rw-r--r--compiler/optimizing/code_generator.h7
-rw-r--r--compiler/optimizing/constant_folding.cc8
-rw-r--r--compiler/optimizing/nodes.cc79
-rw-r--r--compiler/optimizing/nodes.h4
-rw-r--r--patchoat/patchoat.cc19
-rw-r--r--runtime/elf_file.cc40
-rw-r--r--runtime/elf_file.h2
-rw-r--r--runtime/elf_file_impl.h4
-rw-r--r--test/422-type-conversion/src/Main.java64
-rw-r--r--test/442-checker-constant-folding/src/Main.java192
13 files changed, 379 insertions, 59 deletions
diff --git a/compiler/elf_writer.cc b/compiler/elf_writer.cc
index 47402f38c2..f75638d517 100644
--- a/compiler/elf_writer.cc
+++ b/compiler/elf_writer.cc
@@ -39,16 +39,17 @@ uintptr_t ElfWriter::GetOatDataAddress(ElfFile* elf_file) {
}
void ElfWriter::GetOatElfInformation(File* file,
- size_t& oat_loaded_size,
- size_t& oat_data_offset) {
+ size_t* oat_loaded_size,
+ size_t* oat_data_offset) {
std::string error_msg;
std::unique_ptr<ElfFile> elf_file(ElfFile::Open(file, false, false, &error_msg));
CHECK(elf_file.get() != nullptr) << error_msg;
- oat_loaded_size = elf_file->GetLoadedSize();
- CHECK_NE(0U, oat_loaded_size);
- oat_data_offset = GetOatDataAddress(elf_file.get());
- CHECK_NE(0U, oat_data_offset);
+ bool success = elf_file->GetLoadedSize(oat_loaded_size, &error_msg);
+ CHECK(success) << error_msg;
+ CHECK_NE(0U, *oat_loaded_size);
+ *oat_data_offset = GetOatDataAddress(elf_file.get());
+ CHECK_NE(0U, *oat_data_offset);
}
bool ElfWriter::Fixup(File* file, uintptr_t oat_data_begin) {
diff --git a/compiler/elf_writer.h b/compiler/elf_writer.h
index 033c1f8c05..8e13b51bbe 100644
--- a/compiler/elf_writer.h
+++ b/compiler/elf_writer.h
@@ -38,8 +38,8 @@ class ElfWriter {
// Looks up information about location of oat file in elf file container.
// Used for ImageWriter to perform memory layout.
static void GetOatElfInformation(File* file,
- size_t& oat_loaded_size,
- size_t& oat_data_offset);
+ size_t* oat_loaded_size,
+ size_t* oat_data_offset);
// Returns runtime oat_data runtime address for an opened ElfFile.
static uintptr_t GetOatDataAddress(ElfFile* elf_file);
diff --git a/compiler/image_writer.cc b/compiler/image_writer.cc
index 4dc75091e7..195949bf3c 100644
--- a/compiler/image_writer.cc
+++ b/compiler/image_writer.cc
@@ -166,7 +166,7 @@ bool ImageWriter::Write(const std::string& image_filename,
size_t oat_loaded_size = 0;
size_t oat_data_offset = 0;
- ElfWriter::GetOatElfInformation(oat_file.get(), oat_loaded_size, oat_data_offset);
+ ElfWriter::GetOatElfInformation(oat_file.get(), &oat_loaded_size, &oat_data_offset);
Thread::Current()->TransitionFromSuspendedToRunnable();
CreateHeader(oat_loaded_size, oat_data_offset);
diff --git a/compiler/optimizing/code_generator.h b/compiler/optimizing/code_generator.h
index bdbd571133..fcfedab9bb 100644
--- a/compiler/optimizing/code_generator.h
+++ b/compiler/optimizing/code_generator.h
@@ -34,10 +34,15 @@ static int64_t constexpr k2Pow32EncodingForDouble = INT64_C(0x41F0000000000000);
// Binary encoding of 2^31 for type double.
static int64_t constexpr k2Pow31EncodingForDouble = INT64_C(0x41E0000000000000);
+// Minimum value for a primitive integer.
+static int32_t constexpr kPrimIntMin = 0x80000000;
+// Minimum value for a primitive long.
+static int64_t constexpr kPrimLongMin = INT64_C(0x8000000000000000);
+
// Maximum value for a primitive integer.
static int32_t constexpr kPrimIntMax = 0x7fffffff;
// Maximum value for a primitive long.
-static int64_t constexpr kPrimLongMax = 0x7fffffffffffffff;
+static int64_t constexpr kPrimLongMax = INT64_C(0x7fffffffffffffff);
class Assembler;
class CodeGenerator;
diff --git a/compiler/optimizing/constant_folding.cc b/compiler/optimizing/constant_folding.cc
index 5a1d9b488f..20ce1105ce 100644
--- a/compiler/optimizing/constant_folding.cc
+++ b/compiler/optimizing/constant_folding.cc
@@ -71,6 +71,14 @@ void HConstantFolding::Run() {
inst->ReplaceWith(constant);
inst->GetBlock()->RemoveInstruction(inst);
}
+ } else if (inst->IsTypeConversion()) {
+ // Constant folding: replace `TypeConversion(a)' with a constant at
+ // compile time if `a' is a constant.
+ HConstant* constant = inst->AsTypeConversion()->TryStaticEvaluation();
+ if (constant != nullptr) {
+ inst->ReplaceWith(constant);
+ inst->GetBlock()->RemoveInstruction(inst);
+ }
} else if (inst->IsDivZeroCheck()) {
// We can safely remove the check if the input is a non-null constant.
HDivZeroCheck* check = inst->AsDivZeroCheck();
diff --git a/compiler/optimizing/nodes.cc b/compiler/optimizing/nodes.cc
index 41adc7223e..47da9cc17c 100644
--- a/compiler/optimizing/nodes.cc
+++ b/compiler/optimizing/nodes.cc
@@ -16,6 +16,7 @@
#include "nodes.h"
+#include "code_generator.h"
#include "ssa_builder.h"
#include "base/bit_vector-inl.h"
#include "utils/growable_array.h"
@@ -794,6 +795,84 @@ void HGraphVisitor::VisitBasicBlock(HBasicBlock* block) {
}
}
+HConstant* HTypeConversion::TryStaticEvaluation() const {
+ HGraph* graph = GetBlock()->GetGraph();
+ if (GetInput()->IsIntConstant()) {
+ int32_t value = GetInput()->AsIntConstant()->GetValue();
+ switch (GetResultType()) {
+ case Primitive::kPrimLong:
+ return graph->GetLongConstant(static_cast<int64_t>(value));
+ case Primitive::kPrimFloat:
+ return graph->GetFloatConstant(static_cast<float>(value));
+ case Primitive::kPrimDouble:
+ return graph->GetDoubleConstant(static_cast<double>(value));
+ default:
+ return nullptr;
+ }
+ } else if (GetInput()->IsLongConstant()) {
+ int64_t value = GetInput()->AsLongConstant()->GetValue();
+ switch (GetResultType()) {
+ case Primitive::kPrimInt:
+ return graph->GetIntConstant(static_cast<int32_t>(value));
+ case Primitive::kPrimFloat:
+ return graph->GetFloatConstant(static_cast<float>(value));
+ case Primitive::kPrimDouble:
+ return graph->GetDoubleConstant(static_cast<double>(value));
+ default:
+ return nullptr;
+ }
+ } else if (GetInput()->IsFloatConstant()) {
+ float value = GetInput()->AsFloatConstant()->GetValue();
+ switch (GetResultType()) {
+ case Primitive::kPrimInt:
+ if (std::isnan(value))
+ return graph->GetIntConstant(0);
+ if (value >= kPrimIntMax)
+ return graph->GetIntConstant(kPrimIntMax);
+ if (value <= kPrimIntMin)
+ return graph->GetIntConstant(kPrimIntMin);
+ return graph->GetIntConstant(static_cast<int32_t>(value));
+ case Primitive::kPrimLong:
+ if (std::isnan(value))
+ return graph->GetLongConstant(0);
+ if (value >= kPrimLongMax)
+ return graph->GetLongConstant(kPrimLongMax);
+ if (value <= kPrimLongMin)
+ return graph->GetLongConstant(kPrimLongMin);
+ return graph->GetLongConstant(static_cast<int64_t>(value));
+ case Primitive::kPrimDouble:
+ return graph->GetDoubleConstant(static_cast<double>(value));
+ default:
+ return nullptr;
+ }
+ } else if (GetInput()->IsDoubleConstant()) {
+ double value = GetInput()->AsDoubleConstant()->GetValue();
+ switch (GetResultType()) {
+ case Primitive::kPrimInt:
+ if (std::isnan(value))
+ return graph->GetIntConstant(0);
+ if (value >= kPrimIntMax)
+ return graph->GetIntConstant(kPrimIntMax);
+ if (value <= kPrimLongMin)
+ return graph->GetIntConstant(kPrimIntMin);
+ return graph->GetIntConstant(static_cast<int32_t>(value));
+ case Primitive::kPrimLong:
+ if (std::isnan(value))
+ return graph->GetLongConstant(0);
+ if (value >= kPrimLongMax)
+ return graph->GetLongConstant(kPrimLongMax);
+ if (value <= kPrimLongMin)
+ return graph->GetLongConstant(kPrimLongMin);
+ return graph->GetLongConstant(static_cast<int64_t>(value));
+ case Primitive::kPrimFloat:
+ return graph->GetFloatConstant(static_cast<float>(value));
+ default:
+ return nullptr;
+ }
+ }
+ return nullptr;
+}
+
HConstant* HUnaryOperation::TryStaticEvaluation() const {
if (GetInput()->IsIntConstant()) {
int32_t value = Evaluate(GetInput()->AsIntConstant()->GetValue());
diff --git a/compiler/optimizing/nodes.h b/compiler/optimizing/nodes.h
index 0089f22169..cb2e5ccab4 100644
--- a/compiler/optimizing/nodes.h
+++ b/compiler/optimizing/nodes.h
@@ -2982,6 +2982,10 @@ class HTypeConversion : public HExpression<1> {
bool CanBeMoved() const OVERRIDE { return true; }
bool InstructionDataEquals(HInstruction* other ATTRIBUTE_UNUSED) const OVERRIDE { return true; }
+ // Try to statically evaluate the conversion and return a HConstant
+ // containing the result. If the input cannot be converted, return nullptr.
+ HConstant* TryStaticEvaluation() const;
+
DECLARE_INSTRUCTION(TypeConversion);
private:
diff --git a/patchoat/patchoat.cc b/patchoat/patchoat.cc
index 4dc0967bc0..ef84a1717c 100644
--- a/patchoat/patchoat.cc
+++ b/patchoat/patchoat.cc
@@ -650,29 +650,34 @@ bool PatchOat::PatchElf() {
template <typename ElfFileImpl>
bool PatchOat::PatchElf(ElfFileImpl* oat_file) {
TimingLogger::ScopedTiming t("Fixup Elf Text Section", timings_);
+
+ // Fix up absolute references to locations within the boot image.
if (!oat_file->ApplyOatPatchesTo(".text", delta_)) {
return false;
}
+ // Update the OatHeader fields referencing the boot image.
if (!PatchOatHeader<ElfFileImpl>(oat_file)) {
return false;
}
- bool need_fixup = false;
+ bool need_boot_oat_fixup = true;
for (unsigned int i = 0; i < oat_file->GetProgramHeaderNum(); ++i) {
auto hdr = oat_file->GetProgramHeader(i);
- if ((hdr->p_vaddr != 0 && hdr->p_vaddr != hdr->p_offset) ||
- (hdr->p_paddr != 0 && hdr->p_paddr != hdr->p_offset)) {
- need_fixup = true;
+ if (hdr->p_type == PT_LOAD && hdr->p_vaddr == 0u) {
+ need_boot_oat_fixup = false;
break;
}
}
- if (!need_fixup) {
- // This was never passed through ElfFixup so all headers/symbols just have their offset as
- // their addr. Therefore we do not need to update these parts.
+ if (!need_boot_oat_fixup) {
+ // This is an app oat file that can be loaded at an arbitrary address in memory.
+ // Boot image references were patched above and there's nothing else to do.
return true;
}
+ // This is a boot oat file that's loaded at a particular address and we need
+ // to patch all absolute addresses, starting with ELF program headers.
+
t.NewTiming("Fixup Elf Headers");
// Fixup Phdr's
oat_file->FixupProgramHeaders(delta_);
diff --git a/runtime/elf_file.cc b/runtime/elf_file.cc
index e909e64e7a..0c5210dc9d 100644
--- a/runtime/elf_file.cc
+++ b/runtime/elf_file.cc
@@ -1080,9 +1080,9 @@ typename ElfTypes::Rela& ElfFileImpl<ElfTypes>::GetRela(Elf_Shdr& section_header
// Base on bionic phdr_table_get_load_size
template <typename ElfTypes>
-size_t ElfFileImpl<ElfTypes>::GetLoadedSize() const {
- Elf_Addr min_vaddr = 0xFFFFFFFFu;
- Elf_Addr max_vaddr = 0x00000000u;
+bool ElfFileImpl<ElfTypes>::GetLoadedSize(size_t* size, std::string* error_msg) const {
+ Elf_Addr min_vaddr = static_cast<Elf_Addr>(-1);
+ Elf_Addr max_vaddr = 0u;
for (Elf_Word i = 0; i < GetProgramHeaderNum(); i++) {
Elf_Phdr* program_header = GetProgramHeader(i);
if (program_header->p_type != PT_LOAD) {
@@ -1093,6 +1093,15 @@ size_t ElfFileImpl<ElfTypes>::GetLoadedSize() const {
min_vaddr = begin_vaddr;
}
Elf_Addr end_vaddr = program_header->p_vaddr + program_header->p_memsz;
+ if (UNLIKELY(begin_vaddr > end_vaddr)) {
+ std::ostringstream oss;
+ oss << "Program header #" << i << " has overflow in p_vaddr+p_memsz: 0x" << std::hex
+ << program_header->p_vaddr << "+0x" << program_header->p_memsz << "=0x" << end_vaddr
+ << " in ELF file \"" << file_->GetPath() << "\"";
+ *error_msg = oss.str();
+ *size = static_cast<size_t>(-1);
+ return false;
+ }
if (end_vaddr > max_vaddr) {
max_vaddr = end_vaddr;
}
@@ -1100,8 +1109,18 @@ size_t ElfFileImpl<ElfTypes>::GetLoadedSize() const {
min_vaddr = RoundDown(min_vaddr, kPageSize);
max_vaddr = RoundUp(max_vaddr, kPageSize);
CHECK_LT(min_vaddr, max_vaddr) << file_->GetPath();
- size_t loaded_size = max_vaddr - min_vaddr;
- return loaded_size;
+ Elf_Addr loaded_size = max_vaddr - min_vaddr;
+ // Check that the loaded_size fits in size_t.
+ if (UNLIKELY(loaded_size > std::numeric_limits<size_t>::max())) {
+ std::ostringstream oss;
+ oss << "Loaded size is 0x" << std::hex << loaded_size << " but maximum size_t is 0x"
+ << std::numeric_limits<size_t>::max() << " for ELF file \"" << file_->GetPath() << "\"";
+ *error_msg = oss.str();
+ *size = static_cast<size_t>(-1);
+ return false;
+ }
+ *size = loaded_size;
+ return true;
}
template <typename ElfTypes>
@@ -1164,9 +1183,14 @@ bool ElfFileImpl<ElfTypes>::Load(bool executable, std::string* error_msg) {
}
std::string reservation_name("ElfFile reservation for ");
reservation_name += file_->GetPath();
+ size_t loaded_size;
+ if (!GetLoadedSize(&loaded_size, error_msg)) {
+ DCHECK(!error_msg->empty());
+ return false;
+ }
std::unique_ptr<MemMap> reserve(MemMap::MapAnonymous(reservation_name.c_str(),
reserve_base_override,
- GetLoadedSize(), PROT_NONE, false, false,
+ loaded_size, PROT_NONE, false, false,
error_msg));
if (reserve.get() == nullptr) {
*error_msg = StringPrintf("Failed to allocate %s: %s",
@@ -1915,8 +1939,8 @@ uint64_t ElfFile::FindSymbolAddress(unsigned section_type,
DELEGATE_TO_IMPL(FindSymbolAddress, section_type, symbol_name, build_map);
}
-size_t ElfFile::GetLoadedSize() const {
- DELEGATE_TO_IMPL(GetLoadedSize);
+bool ElfFile::GetLoadedSize(size_t* size, std::string* error_msg) const {
+ DELEGATE_TO_IMPL(GetLoadedSize, size, error_msg);
}
bool ElfFile::Strip(File* file, std::string* error_msg) {
diff --git a/runtime/elf_file.h b/runtime/elf_file.h
index fe6896dfe7..48cb4b8b2e 100644
--- a/runtime/elf_file.h
+++ b/runtime/elf_file.h
@@ -66,7 +66,7 @@ class ElfFile {
const std::string& symbol_name,
bool build_map);
- size_t GetLoadedSize() const;
+ bool GetLoadedSize(size_t* size, std::string* error_msg) const;
// Strip an ELF file of unneeded debugging information.
// Returns true on success, false on failure.
diff --git a/runtime/elf_file_impl.h b/runtime/elf_file_impl.h
index 80950c6197..3ad096f983 100644
--- a/runtime/elf_file_impl.h
+++ b/runtime/elf_file_impl.h
@@ -106,8 +106,8 @@ class ElfFileImpl {
Elf_Word GetRelaNum(Elf_Shdr&) const;
Elf_Rela& GetRela(Elf_Shdr&, Elf_Word) const;
- // Returns the expected size when the file is loaded at runtime
- size_t GetLoadedSize() const;
+ // Retrieves the expected size when the file is loaded at runtime. Returns true if successful.
+ bool GetLoadedSize(size_t* size, std::string* error_msg) const;
// Load segments into memory based on PT_LOAD program headers.
// executable is true at run time, false at compile time.
diff --git a/test/422-type-conversion/src/Main.java b/test/422-type-conversion/src/Main.java
index 7ce2868283..447b9b8fd2 100644
--- a/test/422-type-conversion/src/Main.java
+++ b/test/422-type-conversion/src/Main.java
@@ -625,65 +625,67 @@ public class Main {
assertCharEquals((char)0, $opt$IntToChar(-2147483648)); // -(2^31)
}
+ // A dummy value to defeat inlining of these routines.
+ static boolean doThrow = false;
// These methods produce int-to-long Dex instructions.
- static long $opt$ByteToLong(byte a) { return (long)a; }
- static long $opt$ShortToLong(short a) { return (long)a; }
- static long $opt$IntToLong(int a) { return (long)a; }
- static long $opt$CharToLong(int a) { return (long)a; }
+ static long $opt$ByteToLong(byte a) { if (doThrow) throw new Error(); return (long)a; }
+ static long $opt$ShortToLong(short a) { if (doThrow) throw new Error(); return (long)a; }
+ static long $opt$IntToLong(int a) { if (doThrow) throw new Error(); return (long)a; }
+ static long $opt$CharToLong(int a) { if (doThrow) throw new Error(); return (long)a; }
// These methods produce int-to-float Dex instructions.
- static float $opt$ByteToFloat(byte a) { return (float)a; }
- static float $opt$ShortToFloat(short a) { return (float)a; }
- static float $opt$IntToFloat(int a) { return (float)a; }
- static float $opt$CharToFloat(char a) { return (float)a; }
+ static float $opt$ByteToFloat(byte a) { if (doThrow) throw new Error(); return (float)a; }
+ static float $opt$ShortToFloat(short a) { if (doThrow) throw new Error(); return (float)a; }
+ static float $opt$IntToFloat(int a) { if (doThrow) throw new Error(); return (float)a; }
+ static float $opt$CharToFloat(char a) { if (doThrow) throw new Error(); return (float)a; }
// These methods produce int-to-double Dex instructions.
- static double $opt$ByteToDouble(byte a) { return (double)a; }
- static double $opt$ShortToDouble(short a) { return (double)a; }
- static double $opt$IntToDouble(int a) { return (double)a; }
- static double $opt$CharToDouble(int a) { return (double)a; }
+ static double $opt$ByteToDouble(byte a) { if (doThrow) throw new Error(); return (double)a; }
+ static double $opt$ShortToDouble(short a) { if (doThrow) throw new Error(); return (double)a; }
+ static double $opt$IntToDouble(int a) { if (doThrow) throw new Error(); return (double)a; }
+ static double $opt$CharToDouble(int a) { if (doThrow) throw new Error(); return (double)a; }
// These methods produce long-to-int Dex instructions.
- static int $opt$LongToInt(long a) { return (int)a; }
- static int $opt$LongLiteralToInt() { return (int)42L; }
+ static int $opt$LongToInt(long a) { if (doThrow) throw new Error(); return (int)a; }
+ static int $opt$LongLiteralToInt() { if (doThrow) throw new Error(); return (int)42L; }
// This method produces a long-to-float Dex instruction.
- static float $opt$LongToFloat(long a) { return (float)a; }
+ static float $opt$LongToFloat(long a) { if (doThrow) throw new Error(); return (float)a; }
// This method produces a long-to-double Dex instruction.
- static double $opt$LongToDouble(long a) { return (double)a; }
+ static double $opt$LongToDouble(long a) { if (doThrow) throw new Error(); return (double)a; }
// This method produces a float-to-int Dex instruction.
- static int $opt$FloatToInt(float a) { return (int)a; }
+ static int $opt$FloatToInt(float a) { if (doThrow) throw new Error(); return (int)a; }
// This method produces a float-to-long Dex instruction.
- static long $opt$FloatToLong(float a){ return (long)a; }
+ static long $opt$FloatToLong(float a){ if (doThrow) throw new Error(); return (long)a; }
// This method produces a float-to-double Dex instruction.
- static double $opt$FloatToDouble(float a) { return (double)a; }
+ static double $opt$FloatToDouble(float a) { if (doThrow) throw new Error(); return (double)a; }
// This method produces a double-to-int Dex instruction.
- static int $opt$DoubleToInt(double a){ return (int)a; }
+ static int $opt$DoubleToInt(double a){ if (doThrow) throw new Error(); return (int)a; }
// This method produces a double-to-long Dex instruction.
- static long $opt$DoubleToLong(double a){ return (long)a; }
+ static long $opt$DoubleToLong(double a){ if (doThrow) throw new Error(); return (long)a; }
// This method produces a double-to-float Dex instruction.
- static float $opt$DoubleToFloat(double a) { return (float)a; }
+ static float $opt$DoubleToFloat(double a) { if (doThrow) throw new Error(); return (float)a; }
// These methods produce int-to-byte Dex instructions.
- static byte $opt$ShortToByte(short a) { return (byte)a; }
- static byte $opt$IntToByte(int a) { return (byte)a; }
- static byte $opt$CharToByte(char a) { return (byte)a; }
+ static byte $opt$ShortToByte(short a) { if (doThrow) throw new Error(); return (byte)a; }
+ static byte $opt$IntToByte(int a) { if (doThrow) throw new Error(); return (byte)a; }
+ static byte $opt$CharToByte(char a) { if (doThrow) throw new Error(); return (byte)a; }
// These methods produce int-to-short Dex instructions.
- static short $opt$ByteToShort(byte a) { return (short)a; }
- static short $opt$IntToShort(int a) { return (short)a; }
- static short $opt$CharToShort(char a) { return (short)a; }
+ static short $opt$ByteToShort(byte a) { if (doThrow) throw new Error(); return (short)a; }
+ static short $opt$IntToShort(int a) { if (doThrow) throw new Error(); return (short)a; }
+ static short $opt$CharToShort(char a) { if (doThrow) throw new Error(); return (short)a; }
// These methods produce int-to-char Dex instructions.
- static char $opt$ByteToChar(byte a) { return (char)a; }
- static char $opt$ShortToChar(short a) { return (char)a; }
- static char $opt$IntToChar(int a) { return (char)a; }
+ static char $opt$ByteToChar(byte a) { if (doThrow) throw new Error(); return (char)a; }
+ static char $opt$ShortToChar(short a) { if (doThrow) throw new Error(); return (char)a; }
+ static char $opt$IntToChar(int a) { if (doThrow) throw new Error(); return (char)a; }
}
diff --git a/test/442-checker-constant-folding/src/Main.java b/test/442-checker-constant-folding/src/Main.java
index c89ab4dffe..6699acd96e 100644
--- a/test/442-checker-constant-folding/src/Main.java
+++ b/test/442-checker-constant-folding/src/Main.java
@@ -34,6 +34,18 @@ public class Main {
}
}
+ public static void assertFloatEquals(float expected, float result) {
+ if (expected != result) {
+ throw new Error("Expected: " + expected + ", found: " + result);
+ }
+ }
+
+ public static void assertDoubleEquals(double expected, double result) {
+ if (expected != result) {
+ throw new Error("Expected: " + expected + ", found: " + result);
+ }
+ }
+
/**
* Tiny three-register program exercising int constant folding
* on negation.
@@ -461,6 +473,174 @@ public class Main {
return arg < Double.NaN;
}
+ // CHECK-START: int Main.ReturnInt33() constant_folding (before)
+ // CHECK-DAG: [[Const33:j\d+]] LongConstant 33
+ // CHECK-DAG: [[Convert:i\d+]] TypeConversion [[Const33]]
+ // CHECK-DAG: Return [ [[Convert]] ]
+
+ // CHECK-START: int Main.ReturnInt33() constant_folding (after)
+ // CHECK-DAG: [[Const33:i\d+]] IntConstant 33
+ // CHECK-DAG: Return [ [[Const33]] ]
+
+ public static int ReturnInt33() {
+ long imm = 33L;
+ return (int) imm;
+ }
+
+ // CHECK-START: int Main.ReturnIntMax() constant_folding (before)
+ // CHECK-DAG: [[ConstMax:f\d+]] FloatConstant 1e+34
+ // CHECK-DAG: [[Convert:i\d+]] TypeConversion [[ConstMax]]
+ // CHECK-DAG: Return [ [[Convert]] ]
+
+ // CHECK-START: int Main.ReturnIntMax() constant_folding (after)
+ // CHECK-DAG: [[ConstMax:i\d+]] IntConstant 2147483647
+ // CHECK-DAG: Return [ [[ConstMax]] ]
+
+ public static int ReturnIntMax() {
+ float imm = 1.0e34f;
+ return (int) imm;
+ }
+
+ // CHECK-START: int Main.ReturnInt0() constant_folding (before)
+ // CHECK-DAG: [[ConstNaN:d\d+]] DoubleConstant nan
+ // CHECK-DAG: [[Convert:i\d+]] TypeConversion [[ConstNaN]]
+ // CHECK-DAG: Return [ [[Convert]] ]
+
+ // CHECK-START: int Main.ReturnInt0() constant_folding (after)
+ // CHECK-DAG: [[Const0:i\d+]] IntConstant 0
+ // CHECK-DAG: Return [ [[Const0]] ]
+
+ public static int ReturnInt0() {
+ double imm = Double.NaN;
+ return (int) imm;
+ }
+
+ // CHECK-START: long Main.ReturnLong33() constant_folding (before)
+ // CHECK-DAG: [[Const33:i\d+]] IntConstant 33
+ // CHECK-DAG: [[Convert:j\d+]] TypeConversion [[Const33]]
+ // CHECK-DAG: Return [ [[Convert]] ]
+
+ // CHECK-START: long Main.ReturnLong33() constant_folding (after)
+ // CHECK-DAG: [[Const33:j\d+]] LongConstant 33
+ // CHECK-DAG: Return [ [[Const33]] ]
+
+ public static long ReturnLong33() {
+ int imm = 33;
+ return (long) imm;
+ }
+
+ // CHECK-START: long Main.ReturnLong34() constant_folding (before)
+ // CHECK-DAG: [[Const34:f\d+]] FloatConstant 34
+ // CHECK-DAG: [[Convert:j\d+]] TypeConversion [[Const34]]
+ // CHECK-DAG: Return [ [[Convert]] ]
+
+ // CHECK-START: long Main.ReturnLong34() constant_folding (after)
+ // CHECK-DAG: [[Const34:j\d+]] LongConstant 34
+ // CHECK-DAG: Return [ [[Const34]] ]
+
+ public static long ReturnLong34() {
+ float imm = 34.0f;
+ return (long) imm;
+ }
+
+ // CHECK-START: long Main.ReturnLong0() constant_folding (before)
+ // CHECK-DAG: [[ConstNaN:d\d+]] DoubleConstant nan
+ // CHECK-DAG: [[Convert:j\d+]] TypeConversion [[ConstNaN]]
+ // CHECK-DAG: Return [ [[Convert]] ]
+
+ // CHECK-START: long Main.ReturnLong0() constant_folding (after)
+ // CHECK-DAG: [[Const0:j\d+]] LongConstant 0
+ // CHECK-DAG: Return [ [[Const0]] ]
+
+ public static long ReturnLong0() {
+ double imm = -Double.NaN;
+ return (long) imm;
+ }
+
+ // CHECK-START: float Main.ReturnFloat33() constant_folding (before)
+ // CHECK-DAG: [[Const33:i\d+]] IntConstant 33
+ // CHECK-DAG: [[Convert:f\d+]] TypeConversion [[Const33]]
+ // CHECK-DAG: Return [ [[Convert]] ]
+
+ // CHECK-START: float Main.ReturnFloat33() constant_folding (after)
+ // CHECK-DAG: [[Const33:f\d+]] FloatConstant 33
+ // CHECK-DAG: Return [ [[Const33]] ]
+
+ public static float ReturnFloat33() {
+ int imm = 33;
+ return (float) imm;
+ }
+
+ // CHECK-START: float Main.ReturnFloat34() constant_folding (before)
+ // CHECK-DAG: [[Const34:j\d+]] LongConstant 34
+ // CHECK-DAG: [[Convert:f\d+]] TypeConversion [[Const34]]
+ // CHECK-DAG: Return [ [[Convert]] ]
+
+ // CHECK-START: float Main.ReturnFloat34() constant_folding (after)
+ // CHECK-DAG: [[Const34:f\d+]] FloatConstant 34
+ // CHECK-DAG: Return [ [[Const34]] ]
+
+ public static float ReturnFloat34() {
+ long imm = 34L;
+ return (float) imm;
+ }
+
+ // CHECK-START: float Main.ReturnFloat99P25() constant_folding (before)
+ // CHECK-DAG: [[Const:d\d+]] DoubleConstant 99.25
+ // CHECK-DAG: [[Convert:f\d+]] TypeConversion [[Const]]
+ // CHECK-DAG: Return [ [[Convert]] ]
+
+ // CHECK-START: float Main.ReturnFloat99P25() constant_folding (after)
+ // CHECK-DAG: [[Const:f\d+]] FloatConstant 99.25
+ // CHECK-DAG: Return [ [[Const]] ]
+
+ public static float ReturnFloat99P25() {
+ double imm = 99.25;
+ return (float) imm;
+ }
+
+ // CHECK-START: double Main.ReturnDouble33() constant_folding (before)
+ // CHECK-DAG: [[Const33:i\d+]] IntConstant 33
+ // CHECK-DAG: [[Convert:d\d+]] TypeConversion [[Const33]]
+ // CHECK-DAG: Return [ [[Convert]] ]
+
+ // CHECK-START: double Main.ReturnDouble33() constant_folding (after)
+ // CHECK-DAG: [[Const33:d\d+]] DoubleConstant 33
+ // CHECK-DAG: Return [ [[Const33]] ]
+
+ public static double ReturnDouble33() {
+ int imm = 33;
+ return (double) imm;
+ }
+
+ // CHECK-START: double Main.ReturnDouble34() constant_folding (before)
+ // CHECK-DAG: [[Const34:j\d+]] LongConstant 34
+ // CHECK-DAG: [[Convert:d\d+]] TypeConversion [[Const34]]
+ // CHECK-DAG: Return [ [[Convert]] ]
+
+ // CHECK-START: double Main.ReturnDouble34() constant_folding (after)
+ // CHECK-DAG: [[Const34:d\d+]] DoubleConstant 34
+ // CHECK-DAG: Return [ [[Const34]] ]
+
+ public static double ReturnDouble34() {
+ long imm = 34L;
+ return (double) imm;
+ }
+
+ // CHECK-START: double Main.ReturnDouble99P25() constant_folding (before)
+ // CHECK-DAG: [[Const:f\d+]] FloatConstant 99.25
+ // CHECK-DAG: [[Convert:d\d+]] TypeConversion [[Const]]
+ // CHECK-DAG: Return [ [[Convert]] ]
+
+ // CHECK-START: double Main.ReturnDouble99P25() constant_folding (after)
+ // CHECK-DAG: [[Const:d\d+]] DoubleConstant 99.25
+ // CHECK-DAG: Return [ [[Const]] ]
+
+ public static double ReturnDouble99P25() {
+ float imm = 99.25f;
+ return (double) imm;
+ }
+
public static void main(String[] args) {
assertIntEquals(IntNegation(), -42);
assertIntEquals(IntAddition1(), 3);
@@ -485,5 +665,17 @@ public class Main {
assertIntEquals(XorSameInt(arbitrary), 0);
assertFalse(CmpFloatGreaterThanNaN(arbitrary));
assertFalse(CmpDoubleLessThanNaN(arbitrary));
+ assertIntEquals(ReturnInt33(), 33);
+ assertIntEquals(ReturnIntMax(), 2147483647);
+ assertIntEquals(ReturnInt0(), 0);
+ assertLongEquals(ReturnLong33(), 33);
+ assertLongEquals(ReturnLong34(), 34);
+ assertLongEquals(ReturnLong0(), 0);
+ assertFloatEquals(ReturnFloat33(), 33);
+ assertFloatEquals(ReturnFloat34(), 34);
+ assertFloatEquals(ReturnFloat99P25(), 99.25f);
+ assertDoubleEquals(ReturnDouble33(), 33);
+ assertDoubleEquals(ReturnDouble34(), 34);
+ assertDoubleEquals(ReturnDouble99P25(), 99.25);
}
}