diff --git a/llvm/lib/Target/TMS34010/TMS34010ISelLowering.cpp b/llvm/lib/Target/TMS34010/TMS34010ISelLowering.cpp index 6bbb0325e618..01a89bc2fc8a 100644 --- a/llvm/lib/Target/TMS34010/TMS34010ISelLowering.cpp +++ b/llvm/lib/Target/TMS34010/TMS34010ISelLowering.cpp @@ -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(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: diff --git a/llvm/lib/Target/TMS34010/TMS34010TargetMachine.cpp b/llvm/lib/Target/TMS34010/TMS34010TargetMachine.cpp index 3daa1d86489e..f92d0a77a62f 100644 --- a/llvm/lib/Target/TMS34010/TMS34010TargetMachine.cpp +++ b/llvm/lib/Target/TMS34010/TMS34010TargetMachine.cpp @@ -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 &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 "" for standard input, so the token is +// deterministic for a given input and stable for lit's stdin RUN lines. +static void appendModuleToken(SmallVectorImpl &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(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); } }; diff --git a/llvm/test/CodeGen/TMS34010/m2-data.ll b/llvm/test/CodeGen/TMS34010/m2-data.ll index 90dce51e354e..e1b8744f4247 100644 --- a/llvm/test/CodeGen/TMS34010/m2-data.ll +++ b/llvm/test/CodeGen/TMS34010/m2-data.ll @@ -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 diff --git a/llvm/test/CodeGen/TMS34010/m2-global.ll b/llvm/test/CodeGen/TMS34010/m2-global.ll index 9d5aa5716810..172df030a118 100644 --- a/llvm/test/CodeGen/TMS34010/m2-global.ll +++ b/llvm/test/CodeGen/TMS34010/m2-global.ll @@ -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 diff --git a/llvm/test/CodeGen/TMS34010/m3-reject-zext.ll b/llvm/test/CodeGen/TMS34010/m3-reject-zext.ll deleted file mode 100644 index 052ddd90e5fc..000000000000 --- a/llvm/test/CodeGen/TMS34010/m3-reject-zext.ll +++ /dev/null @@ -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 -} diff --git a/llvm/test/CodeGen/TMS34010/m4-private.ll b/llvm/test/CodeGen/TMS34010/m4-private.ll new file mode 100644 index 000000000000..310d20fa0606 --- /dev/null +++ b/llvm/test/CodeGen/TMS34010/m4-private.ll @@ -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 "". +@.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: diff --git a/llvm/test/CodeGen/TMS34010/m4-zext.ll b/llvm/test/CodeGen/TMS34010/m4-zext.ll new file mode 100644 index 000000000000..ae29c83a22e3 --- /dev/null +++ b/llvm/test/CodeGen/TMS34010/m4-zext.ll @@ -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