MSP430: interrupt vector number out of bounds error in v6/trunk (with patch)

When building with Clang for the MSP430 architecture against headers
distributed with TI MSP GCC, interrupt service routine
interrupt(vector_number) attribute is rejected:

   __attribute__ ((interrupt(USCI_A0_VECTOR))) void ISR(void) { }

   error: 'interrupt' attribute parameter 48 is out of bounds

This is due to the check in tools/clang/lib/Sema/SemaDeclAttr.cpp:5104

    unsigned Num = NumParams.getLimitedValue(255);
    if ((Num & 1) || Num > 30) {
        S.Diag(AL.getLoc(), diag::err_attribute_argument_out_of_bounds)
            << AL.getName() << (int)NumParams.getSExtValue()
            << NumParamsExpr->getSourceRange();

Also, the __isr_ symbol is emitted with the vector number divided by 2.

    // Step 3: Emit ISR vector alias.
    unsigned Num = attr->getNumber() / 2;
                              "__isr_" + Twine(Num), F);

Eliminating the check causes a duplicate symbol error among __isr_
symbols, because odd and even vector numbers generate the same symbol.

Neither the check for even and under 30, nor the division by 2 is
necessary when compiling and assembling with the TI MSP GCC, whose
msp430*.h headers define vector number macros, like.

    #define EUSCI_A0_VECTOR (48) /* 0xFFF0 */

My guess is that the current LLVM code from above has been left over
from very old and deprecated community project MSPGCC, which is very
different from TI MSP GCC and is no longer supported.

To make interrupts work, I had to apply attached patch and then in the
app code, define the symbol manually (name of the symbol does not
matter) and allocate it to the section __interrupt_vector_ for that
vector number that is defined by the linker script shipped by TI MSP

    #define VNUM(x) x // to drop parenthesis around *_VECTOR values from TI
    #define ISR_NAME(vect) CONCAT(ISR_, vect)
    #define ISR(vect) \
        void ISR_NAME(VNUM vect)(void); \
        __attribute__((section("__interrupt_vector_" STR(VNUM vect)), aligned(2))) \
        void(*CONCAT(__vector_, VNUM vect))(void) = ISR_NAME(VNUM vect); \
        __attribute__ ((interrupt(vect))) void ISR_NAME(VNUM vect)(void)


Perhaps a better fix would be to emit the alias and allocate it in the
correct section (by name, as I did above manually), but I couldn't find
a way to do this in LLVM. With the current patch, the vector number is
unused, so might need to be removed entirely.

Note that with TI MSP GCC, it is not necessary to define the symbol
and allocate it manually; the following just works:

    #define ISR(vect) \
        __attribute__ ((interrupt(vect))) void ISR_NAME(VNUM vect)(void)


Same info here: How to define an interrupt service routine for MSP430 with LLVM/Clang+GCC? - Stack Overflow

clang-MSP430-accept-all-interrupt-vector-numbers.patch (2.86 KB)

For some time I've been using this defines that allowed me compile the code using both clang and gcc:

#ifdef __clang__
#define ISR_BEGIN(id) __attribute__((interrupt(0)))
#define ISR_BEGIN(id) __attribute__((interrupt(id), used))

#ifdef __clang__
#define ISR_END(name) \
    __attribute__((section("__interrupt_vector_" #name), aligned(2))) void ( \
        *__vector_##name)(void) = name;
#define ISR_END(name)

And I use it like this

void usci_a0(void)

void usci_b0(void)

But of course fixing it in the compiler would be great.