Commit a83bfde6 by John Porto

Subzero. Implements TargetDataARM32::lowerConstants.

parent 69660557
......@@ -75,8 +75,7 @@ void Cfg::swapNodes(NodeList &NewNodes) {
Nodes[I]->resetIndex(I);
}
template <>
Variable *Cfg::makeVariable<Variable>(Type Ty) {
template <> Variable *Cfg::makeVariable<Variable>(Type Ty) {
SizeT Index = Variables.size();
Variable *Var = Target->shouldSplitToVariable64On32(Ty)
? Variable64On32::create(this, Ty, Index)
......
......@@ -545,8 +545,8 @@ class Variable64On32 : public Variable {
public:
static Variable64On32 *create(Cfg *Func, Type Ty, SizeT Index) {
return new (Func->allocate<Variable64On32>()) Variable64On32(
kVariable64On32, Ty, Index);
return new (Func->allocate<Variable64On32>())
Variable64On32(kVariable64On32, Ty, Index);
}
void setName(Cfg *Func, const IceString &NewName) override {
......@@ -591,8 +591,7 @@ public:
}
protected:
Variable64On32(OperandKind K, Type Ty, SizeT Index)
: Variable(K, Ty, Index) {
Variable64On32(OperandKind K, Type Ty, SizeT Index) : Variable(K, Ty, Index) {
assert(typeWidthInBytes(Ty) == 8);
}
......
......@@ -29,6 +29,8 @@
#include "IceUtils.h"
#include "llvm/Support/MathExtras.h"
#include <algorithm>
namespace Ice {
namespace {
......@@ -3112,16 +3114,125 @@ void TargetDataARM32::lowerGlobals(const VariableDeclarationList &Vars,
}
}
namespace {
template <typename T> struct ConstantPoolEmitterTraits;
static_assert(sizeof(uint64_t) == 8,
"uint64_t is supposed to be 8 bytes wide.");
// TODO(jpp): implement the following when implementing constant randomization:
// * template <> struct ConstantPoolEmitterTraits<uint8_t>
// * template <> struct ConstantPoolEmitterTraits<uint16_t>
// * template <> struct ConstantPoolEmitterTraits<uint32_t>
template <> struct ConstantPoolEmitterTraits<float> {
using ConstantType = ConstantFloat;
static constexpr Type IceType = IceType_f32;
// AsmTag and TypeName can't be constexpr because llvm::StringRef is unhappy
// about them being constexpr.
static const char AsmTag[];
static const char TypeName[];
static uint64_t bitcastToUint64(float Value) {
static_assert(sizeof(Value) == sizeof(uint32_t),
"Float should be 4 bytes.");
uint32_t IntValue = *reinterpret_cast<uint32_t *>(&Value);
return static_cast<uint64_t>(IntValue);
}
};
const char ConstantPoolEmitterTraits<float>::AsmTag[] = ".long";
const char ConstantPoolEmitterTraits<float>::TypeName[] = "f32";
template <> struct ConstantPoolEmitterTraits<double> {
using ConstantType = ConstantDouble;
static constexpr Type IceType = IceType_f64;
static const char AsmTag[];
static const char TypeName[];
static uint64_t bitcastToUint64(double Value) {
static_assert(sizeof(double) == sizeof(uint64_t),
"Double should be 8 bytes.");
return *reinterpret_cast<uint64_t *>(&Value);
}
};
const char ConstantPoolEmitterTraits<double>::AsmTag[] = ".quad";
const char ConstantPoolEmitterTraits<double>::TypeName[] = "f64";
template <typename T>
void emitConstant(
Ostream &Str,
const typename ConstantPoolEmitterTraits<T>::ConstantType *Const) {
using Traits = ConstantPoolEmitterTraits<T>;
Const->emitPoolLabel(Str);
Str << ":\n\t" << Traits::AsmTag << "\t0x";
T Value = Const->getValue();
Str.write_hex(Traits::bitcastToUint64(Value));
Str << "\t@" << Traits::TypeName << " " << Value << "\n";
}
template <typename T> void emitConstantPool(GlobalContext *Ctx) {
if (!BuildDefs::dump()) {
return;
}
using Traits = ConstantPoolEmitterTraits<T>;
static constexpr size_t MinimumAlignment = 4;
SizeT Align = std::max(MinimumAlignment, typeAlignInBytes(Traits::IceType));
assert((Align % 4) == 0 && "Constants should be aligned");
Ostream &Str = Ctx->getStrEmit();
ConstantList Pool = Ctx->getConstantPool(Traits::IceType);
Str << "\t.section\t.rodata.cst" << Align << ",\"aM\",%progbits," << Align
<< "\n"
<< "\t.align\t" << Align << "\n";
if (Ctx->getFlags().shouldReorderPooledConstants()) {
// TODO(jpp): add constant pooling.
UnimplementedError(Ctx->getFlags());
}
for (Constant *C : Pool) {
if (!C->getShouldBePooled()) {
continue;
}
emitConstant<T>(Str, llvm::dyn_cast<typename Traits::ConstantType>(C));
}
}
} // end of anonymous namespace
void TargetDataARM32::lowerConstants() {
if (Ctx->getFlags().getDisableTranslation())
return;
UnimplementedError(Ctx->getFlags());
switch (Ctx->getFlags().getOutFileType()) {
case FT_Elf:
UnimplementedError(Ctx->getFlags());
break;
case FT_Asm: {
OstreamLocker L(Ctx);
emitConstantPool<float>(Ctx);
emitConstantPool<double>(Ctx);
break;
}
case FT_Iasm: {
UnimplementedError(Ctx->getFlags());
break;
}
}
}
void TargetDataARM32::lowerJumpTables() {
if (Ctx->getFlags().getDisableTranslation())
return;
UnimplementedError(Ctx->getFlags());
switch (Ctx->getFlags().getOutFileType()) {
case FT_Elf:
UnimplementedError(Ctx->getFlags());
break;
case FT_Asm:
// Already emitted from Cfg
break;
case FT_Iasm: {
UnimplementedError(Ctx->getFlags());
break;
}
}
}
TargetHeaderARM32::TargetHeaderARM32(GlobalContext *Ctx)
......
......@@ -533,7 +533,6 @@ protected:
private:
~TargetDataARM32() override = default;
template <typename T> static void emitConstantPool(GlobalContext *Ctx);
};
class TargetHeaderARM32 final : public TargetHeaderLowering {
......
......@@ -4,6 +4,11 @@
; RUN: %p2i -i %s --filetype=obj --disassemble --args -O2 | FileCheck %s
; RUN: %if --need=allow_dump --need=target_ARM32 --command %p2i --filetype=asm \
; RUN: --target arm32 -i %s --args -O2 --skip-unimplemented \
; RUN: | %if --need=allow_dump --need=target_ARM32 --command FileCheck %s \
; RUN: --check-prefix=ARM32
declare void @use_value(i32)
; Basic cmp/branch folding.
......@@ -20,6 +25,9 @@ branch2:
; CHECK-LABEL: fold_cmp_br
; CHECK: cmp
; CHECK: jge
; ARM32-LABEL: fold_cmp_br
; ARM32: cmp
; ARM32: beq
; Cmp/branch folding with intervening instructions.
......@@ -39,6 +47,13 @@ branch2:
; CHECK: call
; CHECK: cmp
; CHECK: jge
; ARM32-LABEL: fold_cmp_br_intervening_insts
; ARM32: push {{[{].*[}]}}
; ARM32: movlt [[TMP:r[0-9]+]], #1
; ARM32: mov [[P:r[4-7]]], [[TMP]]
; ARM32: bl
; ARM32: cmp [[P]], #0
; ARM32: beq
; Cmp/branch non-folding because of live-out.
......@@ -59,6 +74,11 @@ branch2:
; CHECK: set
; CHECK: cmp
; CHECK: je
; ARM32-LABEL: no_fold_cmp_br_liveout
; ARM32: cmp
; ARM32: movlt [[REG:r[0-9]+]]
; ARM32: cmp [[REG]], #0
; ARM32: beq
; Cmp/branch non-folding because of extra non-whitelisted uses.
......@@ -79,6 +99,14 @@ branch2:
; CHECK: movzx
; CHECK: cmp
; CHECK: je
; ARM32-LABEL: no_fold_cmp_br_non_whitelist
; ARM32: mov [[R:r[0-9]+]], #0
; ARM32: cmp r0, r1
; ARM32: movlt [[R]], #1
; ARM32: mov [[R2:r[0-9]+]], [[R]]
; ARM32: and [[R3:r[0-9]+]], [[R2]], #1
; ARM32: cmp [[R]]
; ARM32: beq
; Basic cmp/select folding.
......@@ -92,6 +120,11 @@ entry:
; CHECK-LABEL: fold_cmp_select
; CHECK: cmp
; CHECK: cmovl
; ARM32-LABEL: fold_cmp_select
; ARM32: mov [[R:r[0-9]+]], #0
; ARM32: cmp r0, r1
; ARM32: movlt [[R]], #1
; ARM32: cmp [[R]], #0
; 64-bit cmp/select folding.
......@@ -108,6 +141,17 @@ entry:
; CHECK: cmp
; CHECK: cmovl
; CHECK: cmovl
; ARM32-LABEL: fold_cmp_select_64
; ARM32: mov [[R:r[0-9]+]], #0
; ARM32: cmp r0, r2
; ARM32: movlt [[R]], #1
; ARM32: cmp [[R]], #0
; ARM32: movne
; ARM32: movne
; ARM32-DAG: mov r0
; ARM32-DAG: mov r1
; ARM32: bx lr
define i64 @fold_cmp_select_64_undef(i64 %arg1) {
entry:
......@@ -120,6 +164,16 @@ entry:
; CHECK: cmp
; CHECK: cmovl
; CHECK: cmovl
; ARM32-LABEL: fold_cmp_select_64_undef
; ARM32: cmp {{r[0-9]+}}, r0
; ARM32: movlt [[R:r[0-9]+]], #1
; ARM32: cmp [[R]]
; ARM32: movne
; ARM32: movne
; ARM32-DAG: mov r0
; ARM32-DAG: mov r1
; ARM32: bx lr
; Cmp/select folding with intervening instructions.
define i32 @fold_cmp_select_intervening_insts(i32 %arg1, i32 %arg2) {
......@@ -135,6 +189,17 @@ entry:
; CHECK: call
; CHECK: cmp
; CHECK: cmovl
; ARM32-LABEL: fold_cmp_select_intervening_insts
; ARM32: mov [[RES0:r[4-7]+]], r0
; ARM32: mov [[RES1:r[4-7]+]], r1
; ARM32: mov [[R:r[0-9]+]], #0
; ARM32: cmp r{{[0-9]+}}, r{{[0-9]+}}
; ARM32: movlt [[R]], #1
; ARM32: mov [[R2:r[4-7]]], [[R]]
; ARM32: bl use_value
; ARM32: cmp [[R2]], #0
; ARM32: movne [[RES1]], [[RES0]]
; ARM32: mov r0, [[RES1]]
; Cmp/multi-select folding.
......@@ -158,6 +223,21 @@ entry:
; CHECK: cmovge
; CHECK: add
; CHECK: add
; ARM32-LABEL: fold_cmp_select_multi
; ARM32-DAG: mov [[T0:r[0-9]+]], #0
; ARM32-DAG: cmp r0, r1
; ARM32: movlt [[T0]], #1
; ARM32-DAG: mov [[T1:r[0-9]+]], r1
; ARM32-DAG: cmp [[T0]], #0
; ARM32: [[T1]], r0
; ARM32-DAG: mov [[T2:r[0-9]+]], r0
; ARM32-DAG: cmp [[T0]], #0
; ARM32: [[T2]], r1
; ARM32: cmp [[T0]], #0
; ARM32: movne
; ARM32: add
; ARM32: add
; ARM32: bx lr
; Cmp/multi-select non-folding because of live-out.
......@@ -184,7 +264,22 @@ next:
; CHECK: cmove
; CHECK: add
; CHECK: add
; ARM32-LABEL: no_fold_cmp_select_multi_liveout
; ARM32-LABEL: fold_cmp_select_multi
; ARM32-DAG: mov [[T0:r[0-9]+]], #0
; ARM32-DAG: cmp r0, r1
; ARM32: movlt [[T0]], #1
; ARM32-DAG: mov [[T1:r[0-9]+]], r1
; ARM32-DAG: cmp [[T0]], #0
; ARM32: [[T1]], r0
; ARM32-DAG: mov [[T2:r[0-9]+]], r0
; ARM32-DAG: cmp [[T0]], #0
; ARM32: [[T2]], r1
; ARM32: cmp [[T0]], #0
; ARM32: movne
; ARM32: add
; ARM32: add
; ARM32: bx lr
; Cmp/multi-select non-folding because of extra non-whitelisted uses.
define i32 @no_fold_cmp_select_multi_non_whitelist(i32 %arg1, i32 %arg2) {
......@@ -212,3 +307,20 @@ entry:
; CHECK: add
; CHECK: add
; CHECK: add
; ARM32-LABEL: no_fold_cmp_select_multi_non_whitelist
; ARM32-DAG: mov [[T0:r[0-9]+]], #0
; ARM32-DAG: cmp r0, r1
; ARM32: movlt [[T0]], #1
; ARM32-DAG: mov [[T1:r[0-9]+]], r1
; ARM32-DAG: cmp [[T0]], #0
; ARM32: [[T1]], r0
; ARM32-DAG: mov [[T2:r[0-9]+]], r0
; ARM32-DAG: cmp [[T0]], #0
; ARM32: [[T2]], r1
; ARM32: cmp [[T0]], #0
; ARM32: movne
; ARM32: and {{.*}}, [[T0]], #1
; ARM32: add
; ARM32: add
; ARM32: add
; ARM32: bx lr
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment