tms34010: emit .data and string literals for GSPA
This commit is contained in:
1 parent
0512ce9d6b
commit
454fb4ac15
6 files changed
+392
-24
No files matched your search
@@ -9,17 +9,26 @@
|
||||
#include "TMS34010MCInstLower.h"
|
||||
#include "TMS34010.h"
|
||||
#include "TargetInfo/TMS34010TargetInfo.h"
|
||||
#include "llvm/ADT/ArrayRef.h"
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
#include "llvm/ADT/Twine.h"
|
||||
#include "llvm/CodeGen/AsmPrinter.h"
|
||||
#include "llvm/CodeGen/MachineInstr.h"
|
||||
#include "llvm/IR/Constants.h"
|
||||
#include "llvm/IR/DataLayout.h"
|
||||
#include "llvm/IR/GlobalVariable.h"
|
||||
#include "llvm/IR/Instruction.h"
|
||||
#include "llvm/IR/Module.h"
|
||||
#include "llvm/IR/Operator.h"
|
||||
#include "llvm/MC/MCInst.h"
|
||||
#include "llvm/MC/MCStreamer.h"
|
||||
#include "llvm/MC/TargetRegistry.h"
|
||||
#include "llvm/Support/Compiler.h"
|
||||
#include "llvm/Support/ErrorHandling.h"
|
||||
#include "llvm/Support/Format.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
#include "llvm/Target/TargetLoweringObjectFile.h"
|
||||
#include <algorithm>
|
||||
|
||||
using namespace llvm;
|
||||
|
||||
@@ -32,15 +41,94 @@ public:
|
||||
|
||||
StringRef getPassName() const override { return "TMS34010 Assembly Printer"; }
|
||||
|
||||
bool doInitialization(Module &M) override;
|
||||
|
||||
void emitInstruction(const MachineInstr *MI) override;
|
||||
|
||||
void emitGlobalVariable(const GlobalVariable *GV) override;
|
||||
|
||||
/// Emit one `.data` definition. Data is emitted during doInitialization so
|
||||
/// it precedes the code, which is how GSPA programs lay out a module.
|
||||
void emitDataGlobal(const GlobalVariable *GV);
|
||||
|
||||
/// Emit the GSPA directives for one constant initializer. The initializer
|
||||
/// is already in target (bit-addressed) form; no scaling happens here.
|
||||
void emitDataInitializer(const Constant *Init);
|
||||
|
||||
/// Emit a constant pointer as `.long <symbol>[+<bit addend>]`.
|
||||
void emitPointerInitializer(const Constant *Init);
|
||||
|
||||
/// Emit `.long <symbol>[+<bit addend>]`.
|
||||
void emitPointerReference(const GlobalValue *GV, int64_t Addend);
|
||||
|
||||
/// Emit byte values as wrapped `.byte` lines (16 values per line keeps the
|
||||
/// line well inside GSPA's DOS-era input buffer). DecimalZeros prints `0`
|
||||
/// instead of `000h`, used for zero-initialized byte arrays.
|
||||
void emitByteLines(ArrayRef<uint64_t> Bytes, bool DecimalZeros = false);
|
||||
|
||||
static char ID;
|
||||
};
|
||||
|
||||
} // end anonymous namespace
|
||||
|
||||
[[noreturn]] static void reportUnsupportedDataInitializer() {
|
||||
report_fatal_error(
|
||||
"M2 .data supports only integer, pointer and byte-array initializers",
|
||||
false);
|
||||
}
|
||||
|
||||
/// Match the integer expression produced by `tms-bitaddr --normalize` for a
|
||||
/// constant pointer: `ptrtoint(@g)` optionally plus a constant bit offset,
|
||||
/// with an `add` operand order that may be commuted.
|
||||
static bool decomposePointerInt(const Constant *C, const GlobalValue *&GV,
|
||||
int64_t &Addend) {
|
||||
const auto *CE = dyn_cast<ConstantExpr>(C);
|
||||
if (!CE)
|
||||
return false;
|
||||
|
||||
if (CE->getOpcode() == Instruction::PtrToInt) {
|
||||
GV = dyn_cast<GlobalValue>(CE->getOperand(0)->stripPointerCasts());
|
||||
Addend = 0;
|
||||
return GV != nullptr;
|
||||
}
|
||||
|
||||
if (CE->getOpcode() != Instruction::Add)
|
||||
return false;
|
||||
|
||||
const Constant *L = CE->getOperand(0);
|
||||
const Constant *R = CE->getOperand(1);
|
||||
|
||||
const GlobalValue *LGV = nullptr;
|
||||
int64_t LAddend = 0;
|
||||
if (decomposePointerInt(L, LGV, LAddend)) {
|
||||
if (const auto *CI = dyn_cast<ConstantInt>(R)) {
|
||||
GV = LGV;
|
||||
Addend = LAddend + CI->getSExtValue();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
const GlobalValue *RGV = nullptr;
|
||||
int64_t RAddend = 0;
|
||||
if (decomposePointerInt(R, RGV, RAddend)) {
|
||||
if (const auto *CI = dyn_cast<ConstantInt>(L)) {
|
||||
GV = RGV;
|
||||
Addend = RAddend + CI->getSExtValue();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/// A zero-initialized, writable, externally-visible object is one `.bss`
|
||||
/// line. Every other definition is emitted as GSPA `.data`.
|
||||
static bool isBSSGlobal(const GlobalVariable *GV) {
|
||||
return GV->hasInitializer() && GV->getInitializer()->isNullValue() &&
|
||||
!GV->isConstant() && !GV->hasPrivateLinkage() &&
|
||||
GV->getSection().empty() && !GV->isThreadLocal();
|
||||
}
|
||||
|
||||
void TMS34010AsmPrinter::emitInstruction(const MachineInstr *MI) {
|
||||
TMS34010MCInstLower MCInstLowering(OutContext, *this);
|
||||
|
||||
@@ -49,34 +137,243 @@ void TMS34010AsmPrinter::emitInstruction(const MachineInstr *MI) {
|
||||
EmitToStreamer(*OutStreamer, TmpInst);
|
||||
}
|
||||
|
||||
void TMS34010AsmPrinter::emitGlobalVariable(const GlobalVariable *GV) {
|
||||
// External declarations need no output in GSPA.
|
||||
if (GV->isDeclaration())
|
||||
void TMS34010AsmPrinter::emitPointerReference(const GlobalValue *GV,
|
||||
int64_t Addend) {
|
||||
Twine Sym = getSymbol(GV)->getName();
|
||||
if (Addend == 0) {
|
||||
OutStreamer->emitRawText(Twine("\t.long ") + Sym + "\n");
|
||||
return;
|
||||
}
|
||||
uint64_t Abs = Addend < 0 ? -static_cast<uint64_t>(Addend) : Addend;
|
||||
OutStreamer->emitRawText(Twine("\t.long ") + Sym + (Addend < 0 ? "-" : "+") +
|
||||
Twine(Abs) + "\n");
|
||||
}
|
||||
|
||||
// GSPA has no .comm/.local directives; a zero-initialized object is one
|
||||
// .bss line. Sizes and alignment in GSPA are in bits. Anything else
|
||||
// (initialized data, string literals, constant/private data) would fall
|
||||
// through to the generic ELF .data/.rodata/.p2align/.asciz printer, which
|
||||
// GSPA rejects; fail loudly instead.
|
||||
if (GV->hasInitializer() && GV->getInitializer()->isNullValue() &&
|
||||
!GV->isConstant() && !GV->hasPrivateLinkage() &&
|
||||
GV->getSection().empty() && !GV->isThreadLocal()) {
|
||||
const DataLayout &DL = GV->getParent()->getDataLayout();
|
||||
Align Alignment = getGVAlignment(GV, DL, GV->getAlign().valueOrOne());
|
||||
uint64_t SizeBits =
|
||||
DL.getTypeAllocSize(GV->getValueType()).getFixedValue() * 8;
|
||||
if (!GV->hasLocalLinkage())
|
||||
OutStreamer->emitSymbolAttribute(getSymbol(GV), MCSA_Global);
|
||||
OutStreamer->emitRawText(Twine("\t.bss\t") + getSymbol(GV)->getName() +
|
||||
"," + Twine(SizeBits) + "," +
|
||||
Twine(Alignment.value() * 8));
|
||||
void TMS34010AsmPrinter::emitPointerInitializer(const Constant *Init) {
|
||||
if (Init->isNullValue()) {
|
||||
OutStreamer->emitRawText("\t.long 0\n");
|
||||
return;
|
||||
}
|
||||
|
||||
report_fatal_error(
|
||||
"M1 supports only zero-initialized globals; .data/string literals are M2",
|
||||
false);
|
||||
const Value *V = Init->stripPointerCasts();
|
||||
|
||||
if (const auto *GV = dyn_cast<GlobalValue>(V)) {
|
||||
emitPointerReference(GV, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
// A constant GEP is a global address plus a bit offset. tms-bitaddr has
|
||||
// already scaled the byte index by eight, so print the addend as-is.
|
||||
if (const auto *GEP = dyn_cast<GEPOperator>(V)) {
|
||||
const auto *BaseGV =
|
||||
dyn_cast<GlobalValue>(GEP->getPointerOperand()->stripPointerCasts());
|
||||
if (!BaseGV || GEP->getNumOperands() != 2)
|
||||
reportUnsupportedDataInitializer();
|
||||
|
||||
const auto *Idx = dyn_cast<ConstantInt>(GEP->getOperand(1));
|
||||
if (!Idx)
|
||||
reportUnsupportedDataInitializer();
|
||||
|
||||
emitPointerReference(BaseGV, Idx->getSExtValue());
|
||||
return;
|
||||
}
|
||||
|
||||
// tms-bitaddr --normalize rewrites constant GEPs in initializers to
|
||||
// inttoptr (add (ptrtoint @g), <bit offset>); accept that shape too.
|
||||
if (const auto *CE = dyn_cast<ConstantExpr>(V)) {
|
||||
if (CE->getOpcode() == Instruction::IntToPtr) {
|
||||
const GlobalValue *BaseGV = nullptr;
|
||||
int64_t Addend = 0;
|
||||
if (decomposePointerInt(CE->getOperand(0), BaseGV, Addend)) {
|
||||
emitPointerReference(BaseGV, Addend);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
reportUnsupportedDataInitializer();
|
||||
}
|
||||
|
||||
void TMS34010AsmPrinter::emitByteLines(ArrayRef<uint64_t> Bytes,
|
||||
bool DecimalZeros) {
|
||||
constexpr unsigned ValuesPerLine = 16;
|
||||
for (size_t I = 0, E = Bytes.size(); I < E; I += ValuesPerLine) {
|
||||
std::string Line;
|
||||
raw_string_ostream OS(Line);
|
||||
OS << "\t.byte ";
|
||||
size_t LineEnd = std::min(E, I + ValuesPerLine);
|
||||
for (size_t J = I; J != LineEnd; ++J) {
|
||||
if (J != I)
|
||||
OS << ", ";
|
||||
if (DecimalZeros)
|
||||
OS << "0";
|
||||
else
|
||||
OS << format("0%02Xh", Bytes[J] & 0xFF);
|
||||
}
|
||||
OS << "\n";
|
||||
OutStreamer->emitRawText(OS.str());
|
||||
}
|
||||
}
|
||||
|
||||
void TMS34010AsmPrinter::emitDataInitializer(const Constant *Init) {
|
||||
// Integer scalar: GSPA's directive follows the IR width so that a char or
|
||||
// short does not occupy a full 32-bit word.
|
||||
if (const auto *CI = dyn_cast<ConstantInt>(Init)) {
|
||||
unsigned Bits = CI->getType()->getIntegerBitWidth();
|
||||
uint64_t Value = CI->getZExtValue();
|
||||
std::string Line;
|
||||
raw_string_ostream OS(Line);
|
||||
if (Bits <= 8)
|
||||
OS << "\t.byte " << format("0%02Xh", Value & 0xFF);
|
||||
else if (Bits <= 16)
|
||||
// The leading 0 is required: GSPA rejects a hex literal whose first
|
||||
// character is A-F (e.g. FFFFh), which every negative i16 hits.
|
||||
OS << "\t.word " << format("0%04Xh", Value & 0xFFFF);
|
||||
else if (Bits <= 32)
|
||||
OS << "\t.long " << (Value & 0xFFFFFFFF);
|
||||
else
|
||||
reportUnsupportedDataInitializer();
|
||||
OS << "\n";
|
||||
OutStreamer->emitRawText(OS.str());
|
||||
return;
|
||||
}
|
||||
|
||||
// Constant pointer, including a constant GEP.
|
||||
if (Init->getType()->isPointerTy()) {
|
||||
emitPointerInitializer(Init);
|
||||
return;
|
||||
}
|
||||
|
||||
// String literal / constant byte array.
|
||||
if (const auto *CDA = dyn_cast<ConstantDataArray>(Init)) {
|
||||
Type *ElemTy = CDA->getElementType();
|
||||
if (ElemTy->isIntegerTy(8)) {
|
||||
SmallVector<uint64_t, 32> Bytes;
|
||||
for (unsigned I = 0, E = CDA->getNumElements(); I != E; ++I)
|
||||
Bytes.push_back(CDA->getElementAsInteger(I) & 0xFF);
|
||||
emitByteLines(Bytes);
|
||||
return;
|
||||
}
|
||||
if (ElemTy->isIntegerTy() || ElemTy->isPointerTy()) {
|
||||
for (unsigned I = 0, E = CDA->getNumElements(); I != E; ++I)
|
||||
emitDataInitializer(CDA->getElementAsConstant(I));
|
||||
return;
|
||||
}
|
||||
reportUnsupportedDataInitializer();
|
||||
}
|
||||
|
||||
if (const auto *CA = dyn_cast<ConstantArray>(Init)) {
|
||||
Type *ElemTy = CA->getType()->getElementType();
|
||||
if (ElemTy->isIntegerTy(8)) {
|
||||
SmallVector<uint64_t, 32> Bytes;
|
||||
for (const Use &U : CA->operands()) {
|
||||
const auto *CI = dyn_cast<ConstantInt>(U.get());
|
||||
if (!CI)
|
||||
reportUnsupportedDataInitializer();
|
||||
Bytes.push_back(CI->getZExtValue() & 0xFF);
|
||||
}
|
||||
emitByteLines(Bytes);
|
||||
return;
|
||||
}
|
||||
if (ElemTy->isIntegerTy() || ElemTy->isPointerTy()) {
|
||||
for (const Use &U : CA->operands())
|
||||
emitDataInitializer(cast<Constant>(U.get()));
|
||||
return;
|
||||
}
|
||||
reportUnsupportedDataInitializer();
|
||||
}
|
||||
|
||||
// zeroinitializer in .data (constant or private objects do not take the
|
||||
// .bss path). The directive must follow the element width, or a
|
||||
// [N x i16] would silently occupy 32 bits per element.
|
||||
if (isa<ConstantAggregateZero>(Init)) {
|
||||
Type *Ty = Init->getType();
|
||||
if (Ty->isIntegerTy()) {
|
||||
unsigned Bits = Ty->getIntegerBitWidth();
|
||||
if (Bits <= 8)
|
||||
OutStreamer->emitRawText("\t.byte 0\n");
|
||||
else if (Bits <= 16)
|
||||
OutStreamer->emitRawText("\t.word 0\n");
|
||||
else
|
||||
OutStreamer->emitRawText("\t.long 0\n");
|
||||
return;
|
||||
}
|
||||
if (Ty->isPointerTy()) {
|
||||
OutStreamer->emitRawText("\t.long 0\n");
|
||||
return;
|
||||
}
|
||||
if (const auto *AT = dyn_cast<ArrayType>(Ty)) {
|
||||
Type *ElemTy = AT->getElementType();
|
||||
uint64_t N = AT->getNumElements();
|
||||
if (ElemTy->isIntegerTy(8)) {
|
||||
SmallVector<uint64_t, 32> Zeros(N, 0);
|
||||
emitByteLines(Zeros, /*DecimalZeros=*/true);
|
||||
return;
|
||||
}
|
||||
if (ElemTy->isIntegerTy(16)) {
|
||||
for (uint64_t I = 0; I != N; ++I)
|
||||
OutStreamer->emitRawText("\t.word 0\n");
|
||||
return;
|
||||
}
|
||||
if (ElemTy->isIntegerTy() || ElemTy->isPointerTy()) {
|
||||
for (uint64_t I = 0; I != N; ++I)
|
||||
OutStreamer->emitRawText("\t.long 0\n");
|
||||
return;
|
||||
}
|
||||
}
|
||||
reportUnsupportedDataInitializer();
|
||||
}
|
||||
|
||||
reportUnsupportedDataInitializer();
|
||||
}
|
||||
|
||||
bool TMS34010AsmPrinter::doInitialization(Module &M) {
|
||||
AsmPrinter::doInitialization(M);
|
||||
|
||||
// Emit initialized data before the code. Section switches go through the
|
||||
// streamer so the printer re-emits `.text` for the first function.
|
||||
// `available_externally` definitions are the linker's job, not ours: emitting
|
||||
// them as `.globl` definitions could cause a duplicate-definition error.
|
||||
for (const GlobalVariable &GV : M.globals())
|
||||
if (!GV.isDeclarationForLinker() && !isBSSGlobal(&GV))
|
||||
emitDataGlobal(&GV);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void TMS34010AsmPrinter::emitDataGlobal(const GlobalVariable *GV) {
|
||||
// Only constant initializers can be written as GSPA .data.
|
||||
const Constant *Init = GV->getInitializer();
|
||||
if (!Init || GV->isThreadLocal() || !GV->getSection().empty())
|
||||
reportUnsupportedDataInitializer();
|
||||
|
||||
OutStreamer->switchSection(getObjFileLowering().getDataSection());
|
||||
if (!GV->hasLocalLinkage())
|
||||
OutStreamer->emitSymbolAttribute(getSymbol(GV), MCSA_Global);
|
||||
OutStreamer->emitRawText(getSymbol(GV)->getName() + ":\n");
|
||||
emitDataInitializer(Init);
|
||||
}
|
||||
|
||||
void TMS34010AsmPrinter::emitGlobalVariable(const GlobalVariable *GV) {
|
||||
// External declarations (including available_externally) need no output.
|
||||
if (GV->isDeclarationForLinker())
|
||||
return;
|
||||
|
||||
// Initialized data has already been emitted by doInitialization.
|
||||
if (!isBSSGlobal(GV))
|
||||
return;
|
||||
|
||||
// GSPA has no .comm/.local directives; a zero-initialized object is one
|
||||
// .bss line. Sizes and alignment in GSPA are in bits.
|
||||
const DataLayout &DL = GV->getParent()->getDataLayout();
|
||||
Align Alignment = getGVAlignment(GV, DL, GV->getAlign().valueOrOne());
|
||||
uint64_t SizeBits =
|
||||
DL.getTypeAllocSize(GV->getValueType()).getFixedValue() * 8;
|
||||
if (!GV->hasLocalLinkage())
|
||||
OutStreamer->emitSymbolAttribute(getSymbol(GV), MCSA_Global);
|
||||
OutStreamer->emitRawText(Twine("\t.bss\t") + getSymbol(GV)->getName() + "," +
|
||||
Twine(SizeBits) + "," +
|
||||
Twine(Alignment.value() * 8));
|
||||
}
|
||||
|
||||
char TMS34010AsmPrinter::ID = 0;
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
#include "TMS34010.h"
|
||||
#include "TargetInfo/TMS34010TargetInfo.h"
|
||||
#include "llvm/ADT/SmallString.h"
|
||||
#include "llvm/ADT/StringExtras.h"
|
||||
#include "llvm/CodeGen/TargetLoweringObjectFileImpl.h"
|
||||
#include "llvm/CodeGen/TargetPassConfig.h"
|
||||
#include "llvm/IR/GlobalValue.h"
|
||||
@@ -29,6 +30,36 @@ using namespace llvm;
|
||||
static const char *const TMS34010DataLayout =
|
||||
"e-m:e-p:32:16-i8:8-i16:16-i32:16-i64:16-f32:16-f64:16-n8:16:32";
|
||||
|
||||
// GSPA 2.00 identifiers accept only alphanumerics and `_`; in particular a
|
||||
// private IR symbol such as `@.str` becomes `_.str`, which the assembler
|
||||
// rejects as an invalid opcode/expression. Encode every other character as
|
||||
// `_HH` so the mapping stays deterministic and collision-free.
|
||||
static void sanitizeGSPASymbolName(SmallVectorImpl<char> &Name) {
|
||||
bool NeedsSanitizing = false;
|
||||
for (char C : Name) {
|
||||
if (!isAlnum(C) && C != '_') {
|
||||
NeedsSanitizing = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!NeedsSanitizing)
|
||||
return;
|
||||
|
||||
SmallString<128> Sanitized;
|
||||
Sanitized.reserve(Name.size());
|
||||
for (char C : Name) {
|
||||
if (isAlnum(C) || C == '_') {
|
||||
Sanitized.push_back(C);
|
||||
} else {
|
||||
unsigned char Byte = static_cast<unsigned char>(C);
|
||||
Sanitized.push_back('_');
|
||||
Sanitized.push_back(hexdigit(Byte >> 4));
|
||||
Sanitized.push_back(hexdigit(Byte & 0xF));
|
||||
}
|
||||
}
|
||||
Name.assign(Sanitized.begin(), Sanitized.end());
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
class TMS34010ObjectFile : public TargetLoweringObjectFileELF {
|
||||
@@ -37,6 +68,7 @@ public:
|
||||
const TargetMachine &TM) const override {
|
||||
SmallString<128> Name("_");
|
||||
getMangler().getNameWithPrefix(Name, GV, /*CannotUsePrivateLabel=*/false);
|
||||
sanitizeGSPASymbolName(Name);
|
||||
return getContext().getOrCreateSymbol(Name);
|
||||
}
|
||||
|
||||
@@ -46,6 +78,7 @@ public:
|
||||
getMangler().getNameWithPrefix(Name, GV, /*CannotUsePrivateLabel=*/false);
|
||||
OutName.push_back('_');
|
||||
OutName.append(Name.begin(), Name.end());
|
||||
sanitizeGSPASymbolName(OutName);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
; RUN: llc -march=tms34010 -O0 -filetype=asm < %s | FileCheck %s
|
||||
;
|
||||
; available_externally definitions are resolved by the linker; emitting them as
|
||||
; .globl definitions could produce a duplicate-definition error.
|
||||
@avail = available_externally global i32 7
|
||||
@g = global i32 1
|
||||
|
||||
define ptr @gp() {
|
||||
entry:
|
||||
ret ptr @g
|
||||
}
|
||||
; CHECK-LABEL: _g:
|
||||
; CHECK: .long 1
|
||||
; CHECK-NOT: _avail
|
||||
@@ -1,7 +1,13 @@
|
||||
; RUN: llc -march=tms34010 -O2 -filetype=asm < %s | FileCheck %s
|
||||
@g = global i32 42
|
||||
@c = global i8 65
|
||||
@s = global i16 4660
|
||||
@mask = global i16 -1
|
||||
@arr = global [2 x i32] [i32 11, i32 22]
|
||||
@msg = private unnamed_addr constant [5 x i8] c"0::0\00", align 1
|
||||
@long = private unnamed_addr constant [21 x i8] c"ABCDEFGHIJKLMNOPQRST\00", align 1
|
||||
@zeros16 = private constant [2 x i16] zeroinitializer
|
||||
@zeros8 = private constant [3 x i8] zeroinitializer
|
||||
define ptr @msgp() {
|
||||
entry:
|
||||
ret ptr @msg
|
||||
@@ -9,7 +15,21 @@ entry:
|
||||
; CHECK: .data
|
||||
; CHECK-LABEL: _g:
|
||||
; CHECK: .long 42
|
||||
; CHECK-LABEL: _c:
|
||||
; CHECK: .byte 041h
|
||||
; CHECK-LABEL: _s:
|
||||
; CHECK: .word 01234h
|
||||
; CHECK-LABEL: _mask:
|
||||
; CHECK: .word 0FFFFh
|
||||
; CHECK-LABEL: _arr:
|
||||
; CHECK: .long 11
|
||||
; CHECK: .long 22
|
||||
; CHECK: .byte 030h, 03Ah, 03Ah, 030h, 000h
|
||||
; CHECK-LABEL: {{.*}}long:
|
||||
; CHECK: .byte 041h, 042h, 043h, 044h, 045h, 046h, 047h, 048h, 049h, 04Ah, 04Bh, 04Ch, 04Dh, 04Eh, 04Fh, 050h
|
||||
; CHECK: .byte 051h, 052h, 053h, 054h, 000h
|
||||
; CHECK-LABEL: {{.*}}zeros16:
|
||||
; CHECK: .word 0
|
||||
; CHECK: .word 0
|
||||
; CHECK-LABEL: {{.*}}zeros8:
|
||||
; CHECK: .byte 0, 0, 0
|
||||
@@ -1,6 +1,9 @@
|
||||
; RUN: llc -march=tms34010 -O0 -filetype=asm < %s | FileCheck %s
|
||||
@arr = global [2 x i32] [i32 11, i32 22]
|
||||
@p = global ptr getelementptr (i8, ptr @arr, i32 32)
|
||||
@pn = global ptr inttoptr (i32 add (i32 ptrtoint (ptr @arr to i32), i32 32) to ptr)
|
||||
; CHECK: _p:
|
||||
; CHECK: .long _arr+32
|
||||
; CHECK-NOT: _arr+4
|
||||
; CHECK-LABEL: _pn:
|
||||
; CHECK: .long _arr+32
|
||||
@@ -5,6 +5,7 @@ entry:
|
||||
ret ptr @.str
|
||||
}
|
||||
; CHECK: .data
|
||||
; CHECK: [[STR:__[A-Za-z0-9_]+]]:
|
||||
; CHECK: .byte 068h, 065h, 06Ch, 06Ch, 06Fh, 000h
|
||||
; CHECK: MOVI _{{.*}}, A{{[0-9]+}}
|
||||
; CHECK: MOVI [[STR]], A{{[0-9]+}}
|
||||
; CHECK: RETS 0
|
||||
Reference in new issue
Block a user