tms34010: add M4 zero-extending loads and module-unique private labels

This commit is contained in:
arti committed 2026-11-12 05:38:20 +00:00
1 parent 73c85350a4
commit df6a6128d2
7 files changed
+117 -36

No files matched your search

@@ -32,7 +32,6 @@ TMS34010TargetLowering::TMS34010TargetLowering(const TargetMachine &TM,
addRegisterClass(MVT::i32, &TMS34010::ARegsRegClass);
// MOVB is an 8-bit sign-extending load and an 8-bit truncating store.
// M1 only needs signed char, so a zero-extending byte load has no pattern.
setLoadExtAction(ISD::SEXTLOAD, MVT::i32, MVT::i8, Legal);
setTruncStoreAction(MVT::i32, MVT::i8, Legal);
@@ -40,6 +39,12 @@ TMS34010TargetLowering::TMS34010TargetLowering(const TargetMachine &TM,
setLoadExtAction(ISD::SEXTLOAD, MVT::i32, MVT::i16, Legal);
setTruncStoreAction(MVT::i32, MVT::i16, Legal);
// There is no zero-extending load instruction. Lower a zero-extending
// byte/short load as the sign-extending load followed by an ANDI mask that
// clears the sign-extension bits.
setLoadExtAction(ISD::ZEXTLOAD, MVT::i32, MVT::i8, Custom);
setLoadExtAction(ISD::ZEXTLOAD, MVT::i32, MVT::i16, Custom);
// There is no conditional move or dedicated setcc result; let the generic
// legalizer turn setcc into a select_cc over 1/0 and select into a
// select_cc, then lower the compare and branch ourselves.
@@ -444,6 +449,27 @@ SDValue TMS34010TargetLowering::LowerSELECT_CC(SDValue Op,
SDValue TMS34010TargetLowering::LowerOperation(SDValue Op,
SelectionDAG &DAG) const {
switch (Op.getOpcode()) {
case ISD::LOAD:
// A zero-extending narrow load becomes the legal sign-extending load plus
// an ANDI with the width mask. Returning merged values keeps the load's
// chain in the result.
if (auto *LD = dyn_cast<LoadSDNode>(Op.getNode())) {
if (LD->getExtensionType() == ISD::ZEXTLOAD) {
SDLoc DL(Op);
EVT MemVT = LD->getMemoryVT();
SDValue Ext = DAG.getExtLoad(ISD::SEXTLOAD, DL, MVT::i32,
LD->getChain(), LD->getBasePtr(), MemVT,
LD->getMemOperand());
unsigned Bits = MemVT.getSizeInBits();
assert((Bits == 8 || Bits == 16) &&
"unexpected zero-extending load width");
SDValue Mask = DAG.getConstant((1u << Bits) - 1u, DL, MVT::i32);
SDValue Zeroed = DAG.getNode(ISD::AND, DL, MVT::i32, Ext, Mask);
SDValue Ops[] = {Zeroed, Ext.getValue(1)};
return DAG.getMergeValues(Ops, DL);
}
}
return SDValue();
case ISD::BRCOND:
return LowerBRCOND(Op, DAG);
case ISD::BR_CC:
@@ -19,6 +19,7 @@
#include "llvm/IR/Function.h"
#include "llvm/IR/GlobalValue.h"
#include "llvm/IR/Mangler.h"
#include "llvm/IR/Module.h"
#include "llvm/MC/MCContext.h"
#include "llvm/MC/MCSymbol.h"
#include "llvm/MC/TargetRegistry.h"
@@ -67,6 +68,33 @@ static void sanitizeGSPASymbolName(SmallVectorImpl<char> &Name) {
Name.assign(Sanitized.begin(), Sanitized.end());
}
// Private/local IR symbols are module-scoped, but GSPA links every translation
// unit into one flat symbol table. Two modules that both contain `.str` would
// otherwise emit the same ``__.str`` label and GSPA reports a duplicate
// definition. Append a deterministic token derived from the module identifier
// to every local symbol; public names are left exactly as the IR spells them.
//
// llc gives a file input the file name as the module identifier (or the IR's
// own source_filename) and "<stdin>" for standard input, so the token is
// deterministic for a given input and stable for lit's stdin RUN lines.
static void appendModuleToken(SmallVectorImpl<char> &Name,
const GlobalValue *GV) {
const Module *M = GV->getParent();
StringRef ID = M ? M->getModuleIdentifier() : StringRef();
// FNV-1a, folded to 32 bits. Eight uppercase hex digits stay GSPA-safe and
// are short enough not to stress the 1987 assembler's identifier limits.
uint64_t Hash = 1469598103934665603ULL;
for (unsigned char C : ID) {
Hash ^= C;
Hash *= 1099511628211ULL;
}
unsigned Token = static_cast<unsigned>(Hash ^ (Hash >> 32));
Name.push_back('_');
for (int Shift = 28; Shift >= 0; Shift -= 4)
Name.push_back(hexdigit((Token >> Shift) & 0xF));
}
namespace {
class TMS34010ObjectFile : public TargetLoweringObjectFileELF {
@@ -76,6 +104,8 @@ public:
SmallString<128> Name("_");
getMangler().getNameWithPrefix(Name, GV, /*CannotUsePrivateLabel=*/false);
sanitizeGSPASymbolName(Name);
if (GV->hasLocalLinkage())
appendModuleToken(Name, GV);
return getContext().getOrCreateSymbol(Name);
}
@@ -86,6 +116,8 @@ public:
OutName.push_back('_');
OutName.append(Name.begin(), Name.end());
sanitizeGSPASymbolName(OutName);
if (GV->hasLocalLinkage())
appendModuleToken(OutName, GV);
}
};
+3 -3
View File
@@ -29,11 +29,11 @@ entry:
; CHECK: .long 11
; CHECK: .long 22
; CHECK: .byte 030h, 03Ah, 03Ah, 030h, 000h
; CHECK-LABEL: {{.*}}long:
; CHECK-LABEL: {{.*}}long{{[A-Za-z0-9_]*}}:
; 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-LABEL: {{.*}}zeros16{{[A-Za-z0-9_]*}}:
; CHECK: .word 0
; CHECK: .word 0
; CHECK-LABEL: {{.*}}zeros8:
; CHECK-LABEL: {{.*}}zeros8{{[A-Za-z0-9_]*}}:
; CHECK: .byte 0, 0, 0
+3 -3
View File
@@ -9,7 +9,7 @@ entry:
ret ptr inttoptr (i32 add (i32 ptrtoint (ptr @arr to i32), i32 32) to ptr)
}
; CHECK-LABEL: _second:
; CHECK: MOVI _arr+32, A{{[0-9]+}}
; CHECK-NOT: _arr+4,
; CHECK: MOVI _arr{{[A-Za-z0-9_]*}}+32, A{{[0-9]+}}
; CHECK-NOT: _arr{{[A-Za-z0-9_]*}}+4,
; CHECK: RETS 0
; CHECK: .bss _arr,128,16
; CHECK: .bss _arr{{[A-Za-z0-9_]*}},128,16
@@ -1,29 +0,0 @@
; RUN: not --crash llc -march=tms34010 -O0 -filetype=asm < %s 2>&1 | FileCheck %s --check-prefix=ZEXT8
; RUN: sed -n '/^; ZEXT16-BEGIN$/,$p' %s > %t.i16.ll
; RUN: not --crash llc -march=tms34010 -O0 -filetype=asm < %t.i16.ll 2>&1 | FileCheck %s --check-prefix=ZEXT16
;
; M3 has only sign-extending narrow loads: MOVB for signed char and the FS0
; MOVE for signed short. A zero-extending load (unsigned char, unsigned short,
; _Bool) would need a ZEXTLOAD pattern that M3 does not have, so llc stops with
; a raw "Cannot select" instead of silently producing wrong code. M4 carries
; the zero-extending patterns. This test keeps the limitation visible in the
; suite; it intentionally accepts the unpolished diagnostic (llc aborts, so the
; RUN lines use not --crash).
;
; ZEXT8: Cannot select: {{.*}} zext from i8
; ZEXT16: Cannot select: {{.*}} zext from i16
define i32 @zload8(ptr %p) {
entry:
%v = load i8, ptr %p, align 1
%r = zext i8 %v to i32
ret i32 %r
}
; ZEXT16-BEGIN
define i32 @zload16(ptr %p) {
entry:
%v = load i16, ptr %p, align 2
%r = zext i16 %v to i32
ret i32 %r
}
+30
View File
@@ -0,0 +1,30 @@
; RUN: llc -march=tms34010 -O0 -filetype=asm %s -o %t-a.s
; RUN: cp %s %t-b.ll
; RUN: llc -march=tms34010 -O0 -filetype=asm %t-b.ll -o %t-b.s
; RUN: llc -march=tms34010 -O0 -filetype=asm < %s -o %t-stdin.s
; RUN: FileCheck %s --check-prefix=SYM < %t-a.s
; RUN: FileCheck %s --check-prefix=PUBLIC < %t-a.s
; RUN: FileCheck %s --check-prefix=SYM < %t-b.s
; RUN: FileCheck %s --check-prefix=PUBLIC < %t-b.s
; RUN: FileCheck %s --check-prefix=STDIN < %t-stdin.s
; RUN: grep -oE '__2EL_2Estr_[0-9A-F]+' %t-a.s > %t-a.sym
; RUN: grep -oE '__2EL_2Estr_[0-9A-F]+' %t-b.s > %t-b.sym
; RUN: not diff %t-a.sym %t-b.sym
; GSPA has one flat symbol table per linked program, so a private label such as
; the string literal's ``__.str`` collides when two translation units are
; concatenated. M4 appends a deterministic module token to private/local
; symbols while leaving public names unchanged. Both files below are compiled
; under different module identifiers, so their private names must differ. The
; stdin RUN line pins the stable fallback token used when llc's module
; identifier is "<stdin>".
@.str = private unnamed_addr constant [5 x i8] c"same\00", align 1
define ptr @public_string() {
ret ptr @.str
}
; STDIN: __2EL_2Estr_6750C254:
; SYM: __2EL_2Estr_{{[0-9A-F]+}}:
; PUBLIC: .globl _public_string
; PUBLIC-LABEL: _public_string:
+22
View File
@@ -0,0 +1,22 @@
; RUN: llc -march=tms34010 -O2 -filetype=asm < %s | FileCheck %s
; M4 adds zero-extending narrow loads for unsigned char and unsigned short.
; MOVB and the FS0 MOVE are sign-extending, so the zero-extending load is the
; sign-extending load followed by an ANDI with the width mask. The GSPA text
; shows the mask the source wrote; the .td encoding one's-complements it.
define i32 @zext8(ptr %p) {
%v = load i8, ptr %p, align 1
%r = zext i8 %v to i32
ret i32 %r
}
define i32 @zext16(ptr %p) {
%v = load i16, ptr %p, align 1
%r = zext i16 %v to i32
ret i32 %r
}
; CHECK-LABEL: _zext8:
; CHECK: MOVB *A{{[0-9]+}}, A{{[0-9]+}}
; CHECK: ANDI 255
; CHECK-LABEL: _zext16:
; CHECK: MOVE *A{{[0-9]+}}, A{{[0-9]+}}, 0
; CHECK: ANDI 65535