Start incorporating the ARM integrated assembler.
Extends the ARM32 assembler to be able to generate a trivial function
footprint using the -filetype=iasm option.
Also does a couple of cleanups:
1) Move UnimplementedError macro to common location so that it can be
used by everyone.
2) Add a GlobalContext argument to the assembler, so that it can
look at flags etc.
BUG= https://code.google.com/p/nativeclient/issues/detail?id=4334
R=stichnot@chromium.org
Review URL: https://codereview.chromium.org/1397933002 .
diff --git a/Makefile.standalone b/Makefile.standalone
index 1ae33c1..9d34419 100644
--- a/Makefile.standalone
+++ b/Makefile.standalone
@@ -196,6 +196,7 @@
SRCS = \
IceAssembler.cpp \
+ IceAssemblerARM32.cpp \
IceBrowserCompileServer.cpp \
IceCfg.cpp \
IceCfgNode.cpp \
diff --git a/src/DartARM32/assembler_arm.cc b/src/DartARM32/assembler_arm.cc
index 5c0a90e..fee25dc 100644
--- a/src/DartARM32/assembler_arm.cc
+++ b/src/DartARM32/assembler_arm.cc
@@ -1433,9 +1433,12 @@
}
+#if 0
+// Moved to: ARM32::AssemblerARM32.
void Assembler::bkpt(uint16_t imm16) {
Emit(BkptEncoding(imm16));
}
+#endif
void Assembler::b(Label* label, Condition cond) {
@@ -1447,7 +1450,8 @@
EmitBranch(cond, label, true);
}
-
+#if 0
+// Moved to: ARM32::AssemblerARM32.
void Assembler::bx(Register rm, Condition cond) {
ASSERT(rm != kNoRegister);
ASSERT(cond != kNoCondition);
@@ -1456,6 +1460,7 @@
(static_cast<int32_t>(rm) << kRmShift);
Emit(encoding);
}
+#endif
void Assembler::blx(Register rm, Condition cond) {
@@ -2314,7 +2319,10 @@
label->BindTo(bound_pc);
}
-
+#if 0
+// Moved to: ARM32::AssemblerARM32 as method bind(Label* Label)
+// Note: Most of this code isn't needed because instruction selection has
+// already been handler
void Assembler::BindARMv7(Label* label) {
ASSERT(!label->IsBound());
intptr_t bound_pc = buffer_.Size();
@@ -2381,6 +2389,7 @@
}
label->BindTo(bound_pc);
}
+#endif
void Assembler::Bind(Label* label) {
diff --git a/src/DartARM32/assembler_arm.h b/src/DartARM32/assembler_arm.h
index c686d60..7893d6f 100644
--- a/src/DartARM32/assembler_arm.h
+++ b/src/DartARM32/assembler_arm.h
@@ -27,7 +27,8 @@
class RuntimeEntry;
class StubEntry;
-
+#if 0
+// Moved to: ARM32::AssemblerARM32.
// Instruction encoding bits.
enum {
H = 1 << 5, // halfword (or byte)
@@ -68,7 +69,7 @@
B26 = 1 << 26,
B27 = 1 << 27,
};
-
+#endif
class Label : public ValueObject {
public:
@@ -532,6 +533,8 @@
void clrex();
void nop(Condition cond = AL);
+#if 0
+ // Moved to: ARM32::AssemblerARM32.
// Note that gdb sets breakpoints using the undefined instruction 0xe7f001f0.
void bkpt(uint16_t imm16);
@@ -540,6 +543,7 @@
return (AL << kConditionShift) | B24 | B21 |
((imm16 >> 4) << 8) | B6 | B5 | B4 | (imm16 & 0xf);
}
+#endif
static uword GetBreakInstructionFiller() {
return BkptEncoding(0);
@@ -660,7 +664,10 @@
// Branch instructions.
void b(Label* label, Condition cond = AL);
void bl(Label* label, Condition cond = AL);
+#if 0
+ // Moved to: ARM32::AssemblerARM32.
void bx(Register rm, Condition cond = AL);
+#endif
void blx(Register rm, Condition cond = AL);
void Branch(const StubEntry& stub_entry,
diff --git a/src/IceAssembler.cpp b/src/IceAssembler.cpp
index 9c77dce..7eb8b61 100644
--- a/src/IceAssembler.cpp
+++ b/src/IceAssembler.cpp
@@ -119,7 +119,7 @@
Buffer.size());
}
-void Assembler::emitIASBytes(GlobalContext *Ctx) const {
+void Assembler::emitIASBytes() const {
Ostream &Str = Ctx->getStrEmit();
intptr_t EndPosition = Buffer.size();
intptr_t CurPosition = 0;
diff --git a/src/IceAssembler.h b/src/IceAssembler.h
index 8247e66..2f5a505 100644
--- a/src/IceAssembler.h
+++ b/src/IceAssembler.h
@@ -64,17 +64,20 @@
return Position - kWordSize;
}
+ void setPosition(intptr_t NewValue) { Position = NewValue; }
+
bool isBound() const { return Position < 0; }
bool isLinked() const { return Position > 0; }
+
virtual bool isUnused() const { return Position == 0; }
-protected:
void bindTo(intptr_t position) {
assert(!isBound());
Position = -position - kWordSize;
assert(isBound());
}
+protected:
void linkTo(intptr_t position) {
assert(!isBound());
Position = position + kWordSize;
@@ -83,7 +86,6 @@
intptr_t Position = 0;
-private:
// TODO(jvoung): why are labels offset by this?
static constexpr uint32_t kWordSize = sizeof(uint32_t);
};
@@ -272,7 +274,7 @@
return Buffer.createFixup(Kind, Value);
}
- void emitIASBytes(GlobalContext *Ctx) const;
+ void emitIASBytes() const;
bool getInternal() const { return IsInternal; }
void setInternal(bool Internal) { IsInternal = Internal; }
const IceString &getFunctionName() { return FunctionName; }
@@ -286,8 +288,8 @@
AssemblerKind getKind() const { return Kind; }
protected:
- explicit Assembler(AssemblerKind Kind)
- : Kind(Kind), Allocator(), Buffer(*this) {}
+ explicit Assembler(AssemblerKind Kind, GlobalContext *Ctx)
+ : Kind(Kind), Allocator(), Ctx(Ctx), Buffer(*this) {}
private:
const AssemblerKind Kind;
@@ -305,6 +307,7 @@
bool Preliminary = false;
protected:
+ GlobalContext *Ctx;
// Buffer's constructor uses the Allocator, so it needs to appear after it.
// TODO(jpp): dependencies on construction order are a nice way of shooting
// yourself in the foot. Fix this.
diff --git a/src/IceAssemblerARM32.cpp b/src/IceAssemblerARM32.cpp
new file mode 100644
index 0000000..ab22450
--- /dev/null
+++ b/src/IceAssemblerARM32.cpp
@@ -0,0 +1,75 @@
+//===- subzero/src/IceAssemblerARM32.cpp - Assembler for ARM32 --*- C++ -*-===//
+//
+// Copyright (c) 2013, the Dart 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.
+//
+// Modified by the Subzero authors.
+//
+//===----------------------------------------------------------------------===//
+//
+// The Subzero Code Generator
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// This file implements the Assembler class for ARM32.
+///
+//===----------------------------------------------------------------------===//
+
+#include "IceAssemblerARM32.h"
+
+namespace Ice {
+
+Label *ARM32::AssemblerARM32::getOrCreateLabel(SizeT Number,
+ LabelVector &Labels) {
+ Label *L = nullptr;
+ if (Number == Labels.size()) {
+ L = new (this->allocate<Label>()) Label();
+ Labels.push_back(L);
+ return L;
+ }
+ if (Number > Labels.size()) {
+ Labels.resize(Number + 1);
+ }
+ L = Labels[Number];
+ if (!L) {
+ L = new (this->allocate<Label>()) Label();
+ Labels[Number] = L;
+ }
+ return L;
+}
+
+void ARM32::AssemblerARM32::bind(Label *label) {
+ intptr_t bound = Buffer.size();
+ assert(!label->isBound()); // Labels can only be bound once.
+ while (label->isLinked()) {
+ intptr_t position = label->getLinkPosition();
+ intptr_t next = Buffer.load<int32_t>(position);
+ Buffer.store<int32_t>(position, bound - (position + 4));
+ label->setPosition(next);
+ }
+ // TODO(kschimpf) Decide if we have near jumps.
+ label->bindTo(bound);
+}
+
+void ARM32::AssemblerARM32::bkpt(uint16_t imm16) {
+ AssemblerBuffer::EnsureCapacity ensured(&Buffer);
+ emitInt32(BkptEncoding(imm16));
+}
+
+void ARM32::AssemblerARM32::bx(RegARM32::GPRRegister rm, CondARM32::Cond cond) {
+ // cccc000100101111111111110001mmmm where mmmm=rm and cccc=Cond.
+ assert(rm != RegARM32::Encoded_Not_GPR);
+ assert(cond != CondARM32::kNone);
+ AssemblerBuffer::EnsureCapacity ensured(&Buffer);
+ int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) | B24 |
+ B21 | (0xfff << 8) | B4 |
+ (static_cast<int32_t>(rm) << kRmShift);
+ emitInt32(encoding);
+}
+
+} // end of namespace Ice
diff --git a/src/IceAssemblerARM32.h b/src/IceAssemblerARM32.h
index 2a42826..2b6bbb1 100644
--- a/src/IceAssemblerARM32.h
+++ b/src/IceAssemblerARM32.h
@@ -24,8 +24,11 @@
#define SUBZERO_SRC_ICEASSEMBLERARM32_H
#include "IceAssembler.h"
+#include "IceConditionCodesARM32.h"
#include "IceDefs.h"
#include "IceFixups.h"
+#include "IceRegistersARM32.h"
+#include "IceTargetLowering.h"
namespace Ice {
namespace ARM32 {
@@ -35,15 +38,24 @@
AssemblerARM32 &operator=(const AssemblerARM32 &) = delete;
public:
- explicit AssemblerARM32(bool use_far_branches = false)
- : Assembler(Asm_ARM32) {
- // This mode is only needed and implemented for MIPS and ARM.
- assert(!use_far_branches);
+ explicit AssemblerARM32(GlobalContext *Ctx, bool use_far_branches = false)
+ : Assembler(Asm_ARM32, Ctx) {
+ // TODO(kschimpf): Add mode if needed when branches are handled.
(void)use_far_branches;
}
~AssemblerARM32() override = default;
- void alignFunction() override { llvm_unreachable("Not yet implemented."); }
+ void alignFunction() override {
+ const SizeT Align = 1 << getBundleAlignLog2Bytes();
+ SizeT BytesNeeded = Utils::OffsetToAlignment(Buffer.getPosition(), Align);
+ constexpr SizeT InstSize = sizeof(int32_t);
+ assert(BytesNeeded % InstSize == 0);
+ while (BytesNeeded > 0) {
+ // TODO(kschimpf) Should this be NOP or some other instruction?
+ bkpt(0);
+ BytesNeeded -= InstSize;
+ }
+ }
SizeT getBundleAlignLog2Bytes() const override { return 4; }
@@ -67,18 +79,173 @@
}
void bindCfgNodeLabel(SizeT NodeNumber) override {
- (void)NodeNumber;
- llvm_unreachable("Not yet implemented.");
+ assert(!getPreliminary());
+ Label *L = getOrCreateCfgNodeLabel(NodeNumber);
+ this->bind(L);
}
bool fixupIsPCRel(FixupKind Kind) const override {
(void)Kind;
llvm_unreachable("Not yet implemented.");
}
+ void bind(Label *label);
+
+ void bkpt(uint16_t imm16);
+
+ void bx(RegARM32::GPRRegister rm, CondARM32::Cond cond = CondARM32::AL);
static bool classof(const Assembler *Asm) {
return Asm->getKind() == Asm_ARM32;
}
+
+private:
+ // Instruction encoding bits.
+
+ // halfword (or byte)
+ static constexpr uint32_t H = 1 << 5;
+ // load (or store)
+ static constexpr uint32_t L = 1 << 20;
+ // set condition code (or leave unchanged)
+ static constexpr uint32_t S = 1 << 20;
+ // writeback base register (or leave unchanged)
+ static constexpr uint32_t W = 1 << 21;
+ // accumulate in multiply instruction (or not)
+ static constexpr uint32_t A = 1 << 21;
+ // unsigned byte (or word)
+ static constexpr uint32_t B = 1 << 22;
+ // high/lo bit of start of s/d register range
+ static constexpr uint32_t D = 1 << 22;
+ // long (or short)
+ static constexpr uint32_t N = 1 << 22;
+ // positive (or negative) offset/index
+ static constexpr uint32_t U = 1 << 23;
+ // offset/pre-indexed addressing (or post-indexed addressing)
+ static constexpr uint32_t P = 1 << 24;
+ // immediate shifter operand (or not)
+ static constexpr uint32_t I = 1 << 25;
+
+ // The following define individual bits.
+ static constexpr uint32_t B0 = 1;
+ static constexpr uint32_t B1 = 1 << 1;
+ static constexpr uint32_t B2 = 1 << 2;
+ static constexpr uint32_t B3 = 1 << 3;
+ static constexpr uint32_t B4 = 1 << 4;
+ static constexpr uint32_t B5 = 1 << 5;
+ static constexpr uint32_t B6 = 1 << 6;
+ static constexpr uint32_t B7 = 1 << 7;
+ static constexpr uint32_t B8 = 1 << 8;
+ static constexpr uint32_t B9 = 1 << 9;
+ static constexpr uint32_t B10 = 1 << 10;
+ static constexpr uint32_t B11 = 1 << 11;
+ static constexpr uint32_t B12 = 1 << 12;
+ static constexpr uint32_t B16 = 1 << 16;
+ static constexpr uint32_t B17 = 1 << 17;
+ static constexpr uint32_t B18 = 1 << 18;
+ static constexpr uint32_t B19 = 1 << 19;
+ static constexpr uint32_t B20 = 1 << 20;
+ static constexpr uint32_t B21 = 1 << 21;
+ static constexpr uint32_t B22 = 1 << 22;
+ static constexpr uint32_t B23 = 1 << 23;
+ static constexpr uint32_t B24 = 1 << 24;
+ static constexpr uint32_t B25 = 1 << 25;
+ static constexpr uint32_t B26 = 1 << 26;
+ static constexpr uint32_t B27 = 1 << 27;
+
+ // Constants used for the decoding or encoding of the individual fields of
+ // instructions. Based on section A5.1 from the "ARM Architecture Reference
+ // Manual, ARMv7-A and ARMv7-R edition". See:
+ // http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ddi0406c
+ static constexpr uint32_t kConditionShift = 28;
+ static constexpr uint32_t kConditionBits = 4;
+ static constexpr uint32_t kTypeShift = 25;
+ static constexpr uint32_t kTypeBits = 3;
+ static constexpr uint32_t kLinkShift = 24;
+ static constexpr uint32_t kLinkBits = 1;
+ static constexpr uint32_t kUShift = 23;
+ static constexpr uint32_t kUBits = 1;
+ static constexpr uint32_t kOpcodeShift = 21;
+ static constexpr uint32_t kOpcodeBits = 4;
+ static constexpr uint32_t kSShift = 20;
+ static constexpr uint32_t kSBits = 1;
+ static constexpr uint32_t kRnShift = 16;
+ static constexpr uint32_t kRnBits = 4;
+ static constexpr uint32_t kRdShift = 12;
+ static constexpr uint32_t kRdBits = 4;
+ static constexpr uint32_t kRsShift = 8;
+ static constexpr uint32_t kRsBits = 4;
+ static constexpr uint32_t kRmShift = 0;
+ static constexpr uint32_t kRmBits = 4;
+
+ // Immediate instruction fields encoding.
+ static constexpr uint32_t kRotateShift = 8;
+ static constexpr uint32_t kRotateBits = 4;
+ static constexpr uint32_t kImmed8Shift = 0;
+ static constexpr uint32_t kImmed8Bits = 8;
+
+ // Shift instruction register fields encodings.
+ static constexpr uint32_t kShiftImmShift = 7;
+ static constexpr uint32_t kShiftRegisterShift = 8;
+ static constexpr uint32_t kShiftImmBits = 5;
+ static constexpr uint32_t kShiftShift = 5;
+ static constexpr uint32_t kShiftBits = 2;
+
+ // Load/store instruction offset field encoding.
+ static constexpr uint32_t kOffset12Shift = 0;
+ static constexpr uint32_t kOffset12Bits = 12;
+ static constexpr uint32_t kOffset12Mask = 0x00000fff;
+
+ // Mul instruction register field encodings.
+ static constexpr uint32_t kMulRdShift = 16;
+ static constexpr uint32_t kMulRdBits = 4;
+ static constexpr uint32_t kMulRnShift = 12;
+ static constexpr uint32_t kMulRnBits = 4;
+
+ // Div instruction register field encodings.
+ static constexpr uint32_t kDivRdShift = 16;
+ static constexpr uint32_t kDivRdBits = 4;
+ static constexpr uint32_t kDivRmShift = 8;
+ static constexpr uint32_t kDivRmBints = 4;
+ static constexpr uint32_t kDivRnShift = 0;
+ static constexpr uint32_t kDivRnBits = 4;
+
+ // ldrex/strex register field encodings.
+ static constexpr uint32_t kLdExRnShift = 16;
+ static constexpr uint32_t kLdExRtShift = 12;
+ static constexpr uint32_t kStrExRnShift = 16;
+ static constexpr uint32_t kStrExRdShift = 12;
+ static constexpr uint32_t kStrExRtShift = 0;
+
+ // MRC instruction offset field encoding.
+ static constexpr uint32_t kCRmShift = 0;
+ static constexpr uint32_t kCRmBits = 4;
+ static constexpr uint32_t kOpc2Shift = 5;
+ static constexpr uint32_t kOpc2Bits = 3;
+ static constexpr uint32_t kCoprocShift = 8;
+ static constexpr uint32_t kCoprocBits = 4;
+ static constexpr uint32_t kCRnShift = 16;
+ static constexpr uint32_t kCRnBits = 4;
+ static constexpr uint32_t kOpc1Shift = 21;
+ static constexpr uint32_t kOpc1Bits = 3;
+
+ static constexpr uint32_t kBranchOffsetMask = 0x00ffffff;
+
+ // A vector of pool-allocated x86 labels for CFG nodes.
+ using LabelVector = std::vector<Label *>;
+ LabelVector CfgNodeLabels;
+
+ Label *getOrCreateLabel(SizeT Number, LabelVector &Labels);
+ Label *getOrCreateCfgNodeLabel(SizeT NodeNumber) {
+ return getOrCreateLabel(NodeNumber, CfgNodeLabels);
+ }
+
+ void emitInt32(int32_t Value) { Buffer.emit<int32_t>(Value); }
+
+ static int32_t BkptEncoding(uint16_t imm16) {
+ // bkpt requires that the cond field is AL.
+ // cccc00010010iiiiiiiiiiii0111iiii where cccc=AL and i in imm16
+ return (CondARM32::AL << kConditionShift) | B24 | B21 |
+ ((imm16 >> 4) << 8) | B6 | B5 | B4 | (imm16 & 0xf);
+ }
};
} // end of namespace ARM32
diff --git a/src/IceAssemblerMIPS32.h b/src/IceAssemblerMIPS32.h
index 9af1151..9f6ba42 100644
--- a/src/IceAssemblerMIPS32.h
+++ b/src/IceAssemblerMIPS32.h
@@ -35,8 +35,8 @@
AssemblerMIPS32 &operator=(const AssemblerMIPS32 &) = delete;
public:
- explicit AssemblerMIPS32(bool use_far_branches = false)
- : Assembler(Asm_MIPS32) {
+ explicit AssemblerMIPS32(GlobalContext *Ctx, bool use_far_branches = false)
+ : Assembler(Asm_MIPS32, Ctx) {
// This mode is only needed and implemented for MIPS32 and ARM.
assert(!use_far_branches);
(void)use_far_branches;
diff --git a/src/IceAssemblerX8632.h b/src/IceAssemblerX8632.h
index fb9eedf..3672ecd 100644
--- a/src/IceAssemblerX8632.h
+++ b/src/IceAssemblerX8632.h
@@ -45,8 +45,8 @@
AssemblerX8632 &operator=(const AssemblerX8632 &) = delete;
public:
- explicit AssemblerX8632(bool use_far_branches = false)
- : X86Internal::AssemblerX86Base<TargetX8632>(Asm_X8632,
+ explicit AssemblerX8632(GlobalContext *Ctx, bool use_far_branches = false)
+ : X86Internal::AssemblerX86Base<TargetX8632>(Asm_X8632, Ctx,
use_far_branches) {}
~AssemblerX8632() override = default;
diff --git a/src/IceAssemblerX8664.h b/src/IceAssemblerX8664.h
index 5666810..43b50be 100644
--- a/src/IceAssemblerX8664.h
+++ b/src/IceAssemblerX8664.h
@@ -45,8 +45,8 @@
AssemblerX8664 &operator=(const AssemblerX8664 &) = delete;
public:
- explicit AssemblerX8664(bool use_far_branches = false)
- : X86Internal::AssemblerX86Base<TargetX8664>(Asm_X8664,
+ explicit AssemblerX8664(GlobalContext *Ctx, bool use_far_branches = false)
+ : X86Internal::AssemblerX86Base<TargetX8664>(Asm_X8664, Ctx,
use_far_branches) {}
~AssemblerX8664() override = default;
diff --git a/src/IceAssemblerX86Base.h b/src/IceAssemblerX86Base.h
index f9de5a5..6b8f3c1 100644
--- a/src/IceAssemblerX86Base.h
+++ b/src/IceAssemblerX86Base.h
@@ -115,8 +115,9 @@
AssemblerX86Base &operator=(const AssemblerX86Base &) = delete;
protected:
- AssemblerX86Base(AssemblerKind Kind, bool use_far_branches)
- : Assembler(Kind) {
+ AssemblerX86Base(AssemblerKind Kind, GlobalContext *Ctx,
+ bool use_far_branches)
+ : Assembler(Kind, Ctx) {
// This mode is only needed and implemented for MIPS and ARM.
assert(!use_far_branches);
(void)use_far_branches;
diff --git a/src/IceGlobalContext.cpp b/src/IceGlobalContext.cpp
index 24002d6..7b54feb 100644
--- a/src/IceGlobalContext.cpp
+++ b/src/IceGlobalContext.cpp
@@ -519,7 +519,7 @@
case FT_Iasm: {
OstreamLocker L(this);
Cfg::emitTextHeader(MangledName, this, Asm.get());
- Asm->emitIASBytes(this);
+ Asm->emitIASBytes();
} break;
case FT_Asm:
llvm::report_fatal_error("Unexpected FT_Asm");
diff --git a/src/IceInstARM32.cpp b/src/IceInstARM32.cpp
index b07b283..b45d2f1 100644
--- a/src/IceInstARM32.cpp
+++ b/src/IceInstARM32.cpp
@@ -969,8 +969,8 @@
}
void InstARM32Ret::emitIAS(const Cfg *Func) const {
- (void)Func;
- llvm_unreachable("Not yet implemented");
+ ARM32::AssemblerARM32 *Asm = Func->getAssembler<ARM32::AssemblerARM32>();
+ Asm->bx(RegARM32::Encoded_Reg_lr);
}
void InstARM32Ret::dump(const Cfg *Func) const {
diff --git a/src/IceTargetLowering.cpp b/src/IceTargetLowering.cpp
index 9a8a02a..8d67e8b 100644
--- a/src/IceTargetLowering.cpp
+++ b/src/IceTargetLowering.cpp
@@ -113,7 +113,7 @@
Cfg *Func) {
#define SUBZERO_TARGET(X) \
if (Target == Target_##X) \
- return std::unique_ptr<Assembler>(new X::Assembler##X());
+ return std::unique_ptr<Assembler>(new X::Assembler##X(Func->getContext()));
#include "llvm/Config/SZTargets.def"
Func->setError("Unsupported target assembler");
diff --git a/src/IceTargetLowering.h b/src/IceTargetLowering.h
index 32fdc44..ee0de8f 100644
--- a/src/IceTargetLowering.h
+++ b/src/IceTargetLowering.h
@@ -28,6 +28,18 @@
namespace Ice {
+// UnimplementedError is defined as a macro so that we can get actual line
+// numbers.
+#define UnimplementedError(Flags) \
+ do { \
+ if (!static_cast<const ClFlags &>(Flags).getSkipUnimplemented()) { \
+ /* Use llvm_unreachable instead of report_fatal_error, which gives \
+ better stack traces. */ \
+ llvm_unreachable("Not yet implemented"); \
+ abort(); \
+ } \
+ } while (0)
+
/// LoweringContext makes it easy to iterate through non-deleted instructions in
/// a node, and insert new (lowered) instructions at the current point. Along
/// with the instruction list container and associated iterators, it holds the
diff --git a/src/IceTargetLoweringARM32.cpp b/src/IceTargetLoweringARM32.cpp
index 2674190..2615b36 100644
--- a/src/IceTargetLoweringARM32.cpp
+++ b/src/IceTargetLoweringARM32.cpp
@@ -37,18 +37,6 @@
namespace {
-// UnimplementedError is defined as a macro so that we can get actual line
-// numbers.
-#define UnimplementedError(Flags) \
- do { \
- if (!static_cast<const ClFlags &>(Flags).getSkipUnimplemented()) { \
- /* Use llvm_unreachable instead of report_fatal_error, which gives \
- better stack traces. */ \
- llvm_unreachable("Not yet implemented"); \
- abort(); \
- } \
- } while (0)
-
// The following table summarizes the logic for lowering the icmp instruction
// for i32 and narrower types. Each icmp condition has a clear mapping to an
// ARM32 conditional move instruction.
@@ -3871,16 +3859,13 @@
case FT_Elf:
UnimplementedError(Ctx->getFlags());
break;
- case FT_Asm: {
+ case FT_Asm:
+ case FT_Iasm: {
OstreamLocker L(Ctx);
emitConstantPool<float>(Ctx);
emitConstantPool<double>(Ctx);
break;
}
- case FT_Iasm: {
- UnimplementedError(Ctx->getFlags());
- break;
- }
}
}
@@ -3895,7 +3880,7 @@
// Already emitted from Cfg
break;
case FT_Iasm: {
- UnimplementedError(Ctx->getFlags());
+ // TODO(kschimpf): Fill this in when we get more information.
break;
}
}
diff --git a/src/IceTargetLoweringMIPS32.cpp b/src/IceTargetLoweringMIPS32.cpp
index 98a698c..7cc65cf 100644
--- a/src/IceTargetLoweringMIPS32.cpp
+++ b/src/IceTargetLoweringMIPS32.cpp
@@ -31,17 +31,6 @@
namespace Ice {
-namespace {
-void UnimplementedError(const ClFlags &Flags) {
- if (!Flags.getSkipUnimplemented()) {
- // Use llvm_unreachable instead of report_fatal_error, which gives better
- // stack traces.
- llvm_unreachable("Not yet implemented");
- abort();
- }
-}
-} // end of anonymous namespace
-
TargetMIPS32::TargetMIPS32(Cfg *Func) : TargetLowering(Func) {
// TODO: Don't initialize IntegerRegisters and friends every time. Instead,
// initialize in some sort of static initializer for the class.
diff --git a/tests_lit/assembler/arm32/ret.ll b/tests_lit/assembler/arm32/ret.ll
new file mode 100644
index 0000000..27596c9
--- /dev/null
+++ b/tests_lit/assembler/arm32/ret.ll
@@ -0,0 +1,36 @@
+; Shows that the ARM integrated assembler can translate a trivial,
+; bundle-aligned function.
+
+; RUN: %p2i --filetype=asm -i %s --target=arm32 \
+; RUN: | FileCheck %s --check-prefix=ASM
+; RUN: %p2i --filetype=iasm -i %s --target=arm32 \
+; RUN: | FileCheck %s --check-prefix=IASM
+
+define internal void @f() {
+ ret void
+}
+
+; ASM-LABEL:f:
+; ASM-NEXT: .Lf$__0:
+; ASM-NEXT: bx lr
+
+; IASM-LABEL:f:
+; IASM-NEXT: .byte 0x1e
+; IASM-NEXT: .byte 0xff
+; IASM-NEXT: .byte 0x2f
+; IASM-NEXT: .byte 0xe1
+
+; IASM-NEXT: .byte 0x70
+; IASM-NEXT: .byte 0x0
+; IASM-NEXT: .byte 0x20
+; IASM-NEXT: .byte 0xe1
+
+; IASM-NEXT: .byte 0x70
+; IASM-NEXT: .byte 0x0
+; IASM-NEXT: .byte 0x20
+; IASM-NEXT: .byte 0xe1
+
+; IASM-NEXT: .byte 0x70
+; IASM-NEXT: .byte 0x0
+; IASM-NEXT: .byte 0x20
+; IASM-NEXT: .byte 0xe1