Closed 4ntoine closed 9 years ago
WInterrupts.c
:
/* -*- mode: jde; c-basic-offset: 2; indent-tabs-mode: nil -*- */
/*
Part of the Wiring project - http://wiring.uniandes.edu.co
Copyright (c) 2004-05 Hernando Barragan
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General
Public License along with this library; if not, write to the
Free Software Foundation, Inc., 59 Temple Place, Suite 330,
Boston, MA 02111-1307 USA
Modified 24 November 2006 by David A. Mellis
Modified 1 August 2010 by Mark Sproul
*/
#include <inttypes.h>
#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/pgmspace.h>
#include <stdio.h>
#include "wiring_private.h"
static volatile voidFuncPtr intFunc[EXTERNAL_NUM_INTERRUPTS];
// volatile static voidFuncPtr twiIntFunc;
void attachInterrupt(uint8_t interruptNum, void (*userFunc)(void), int mode) {
if(interruptNum < EXTERNAL_NUM_INTERRUPTS) {
intFunc[interruptNum] = userFunc;
// Configure the interrupt mode (trigger on low input, any change, rising
// edge, or falling edge). The mode constants were chosen to correspond
// to the configuration bits in the hardware register, so we simply shift
// the mode into place.
// Enable the interrupt.
switch (interruptNum) {
#if defined(__AVR_ATmega32U4__)
// I hate doing this, but the register assignment differs between the 1280/2560
// and the 32U4. Since avrlib defines registers PCMSK1 and PCMSK2 that aren't
// even present on the 32U4 this is the only way to distinguish between them.
case 0:
EICRA = (EICRA & ~((1<<ISC00) | (1<<ISC01))) | (mode << ISC00);
EIMSK |= (1<<INT0);
break;
case 1:
EICRA = (EICRA & ~((1<<ISC10) | (1<<ISC11))) | (mode << ISC10);
EIMSK |= (1<<INT1);
break;
case 2:
EICRA = (EICRA & ~((1<<ISC20) | (1<<ISC21))) | (mode << ISC20);
EIMSK |= (1<<INT2);
break;
case 3:
EICRA = (EICRA & ~((1<<ISC30) | (1<<ISC31))) | (mode << ISC30);
EIMSK |= (1<<INT3);
break;
case 4:
EICRB = (EICRB & ~((1<<ISC60) | (1<<ISC61))) | (mode << ISC60);
EIMSK |= (1<<INT6);
break;
#elif defined(EICRA) && defined(EICRB) && defined(EIMSK)
case 2:
EICRA = (EICRA & ~((1 << ISC00) | (1 << ISC01))) | (mode << ISC00);
EIMSK |= (1 << INT0);
break;
case 3:
EICRA = (EICRA & ~((1 << ISC10) | (1 << ISC11))) | (mode << ISC10);
EIMSK |= (1 << INT1);
break;
case 4:
EICRA = (EICRA & ~((1 << ISC20) | (1 << ISC21))) | (mode << ISC20);
EIMSK |= (1 << INT2);
break;
case 5:
EICRA = (EICRA & ~((1 << ISC30) | (1 << ISC31))) | (mode << ISC30);
EIMSK |= (1 << INT3);
break;
case 0:
EICRB = (EICRB & ~((1 << ISC40) | (1 << ISC41))) | (mode << ISC40);
EIMSK |= (1 << INT4);
break;
case 1:
EICRB = (EICRB & ~((1 << ISC50) | (1 << ISC51))) | (mode << ISC50);
EIMSK |= (1 << INT5);
break;
case 6:
EICRB = (EICRB & ~((1 << ISC60) | (1 << ISC61))) | (mode << ISC60);
EIMSK |= (1 << INT6);
break;
case 7:
EICRB = (EICRB & ~((1 << ISC70) | (1 << ISC71))) | (mode << ISC70);
EIMSK |= (1 << INT7);
break;
#else
case 0:
#if defined(EICRA) && defined(ISC00) && defined(EIMSK)
EICRA = (EICRA & ~((1 << ISC00) | (1 << ISC01))) | (mode << ISC00);
EIMSK |= (1 << INT0);
#elif defined(MCUCR) && defined(ISC00) && defined(GICR)
MCUCR = (MCUCR & ~((1 << ISC00) | (1 << ISC01))) | (mode << ISC00);
GICR |= (1 << INT0);
#elif defined(MCUCR) && defined(ISC00) && defined(GIMSK)
MCUCR = (MCUCR & ~((1 << ISC00) | (1 << ISC01))) | (mode << ISC00);
GIMSK |= (1 << INT0);
#else
#error attachInterrupt not finished for this CPU (case 0)
#endif
break;
case 1:
#if defined(EICRA) && defined(ISC10) && defined(ISC11) && defined(EIMSK)
EICRA = (EICRA & ~((1 << ISC10) | (1 << ISC11))) | (mode << ISC10);
EIMSK |= (1 << INT1);
#elif defined(MCUCR) && defined(ISC10) && defined(ISC11) && defined(GICR)
MCUCR = (MCUCR & ~((1 << ISC10) | (1 << ISC11))) | (mode << ISC10);
GICR |= (1 << INT1);
#elif defined(MCUCR) && defined(ISC10) && defined(GIMSK) && defined(GIMSK)
MCUCR = (MCUCR & ~((1 << ISC10) | (1 << ISC11))) | (mode << ISC10);
GIMSK |= (1 << INT1);
#else
#warning attachInterrupt may need some more work for this cpu (case 1)
#endif
break;
case 2:
#if defined(EICRA) && defined(ISC20) && defined(ISC21) && defined(EIMSK)
EICRA = (EICRA & ~((1 << ISC20) | (1 << ISC21))) | (mode << ISC20);
EIMSK |= (1 << INT2);
#elif defined(MCUCR) && defined(ISC20) && defined(ISC21) && defined(GICR)
MCUCR = (MCUCR & ~((1 << ISC20) | (1 << ISC21))) | (mode << ISC20);
GICR |= (1 << INT2);
#elif defined(MCUCR) && defined(ISC20) && defined(GIMSK) && defined(GIMSK)
MCUCR = (MCUCR & ~((1 << ISC20) | (1 << ISC21))) | (mode << ISC20);
GIMSK |= (1 << INT2);
#endif
break;
#endif
}
}
}
void detachInterrupt(uint8_t interruptNum) {
if(interruptNum < EXTERNAL_NUM_INTERRUPTS) {
// Disable the interrupt. (We can't assume that interruptNum is equal
// to the number of the EIMSK bit to clear, as this isn't true on the
// ATmega8. There, INT0 is 6 and INT1 is 7.)
switch (interruptNum) {
#if defined(__AVR_ATmega32U4__)
case 0:
EIMSK &= ~(1<<INT0);
break;
case 1:
EIMSK &= ~(1<<INT1);
break;
case 2:
EIMSK &= ~(1<<INT2);
break;
case 3:
EIMSK &= ~(1<<INT3);
break;
case 4:
EIMSK &= ~(1<<INT6);
break;
#elif defined(EICRA) && defined(EICRB) && defined(EIMSK)
case 2:
EIMSK &= ~(1 << INT0);
break;
case 3:
EIMSK &= ~(1 << INT1);
break;
case 4:
EIMSK &= ~(1 << INT2);
break;
case 5:
EIMSK &= ~(1 << INT3);
break;
case 0:
EIMSK &= ~(1 << INT4);
break;
case 1:
EIMSK &= ~(1 << INT5);
break;
case 6:
EIMSK &= ~(1 << INT6);
break;
case 7:
EIMSK &= ~(1 << INT7);
break;
#else
case 0:
#if defined(EIMSK) && defined(INT0)
EIMSK &= ~(1 << INT0);
#elif defined(GICR) && defined(ISC00)
GICR &= ~(1 << INT0); // atmega32
#elif defined(GIMSK) && defined(INT0)
GIMSK &= ~(1 << INT0);
#else
#error detachInterrupt not finished for this cpu
#endif
break;
case 1:
#if defined(EIMSK) && defined(INT1)
EIMSK &= ~(1 << INT1);
#elif defined(GICR) && defined(INT1)
GICR &= ~(1 << INT1); // atmega32
#elif defined(GIMSK) && defined(INT1)
GIMSK &= ~(1 << INT1);
#else
#warning detachInterrupt may need some more work for this cpu (case 1)
#endif
break;
#endif
}
intFunc[interruptNum] = 0;
}
}
/*
void attachInterruptTwi(void (*userFunc)(void) ) {
twiIntFunc = userFunc;
}
*/
#if defined(__AVR_ATmega32U4__)
ISR(INT0_vect) {
if(intFunc[EXTERNAL_INT_0])
intFunc[EXTERNAL_INT_0]();
}
ISR(INT1_vect) {
if(intFunc[EXTERNAL_INT_1])
intFunc[EXTERNAL_INT_1]();
}
ISR(INT2_vect) {
if(intFunc[EXTERNAL_INT_2])
intFunc[EXTERNAL_INT_2]();
}
ISR(INT3_vect) {
if(intFunc[EXTERNAL_INT_3])
intFunc[EXTERNAL_INT_3]();
}
ISR(INT6_vect) {
if(intFunc[EXTERNAL_INT_4])
intFunc[EXTERNAL_INT_4]();
}
#elif defined(EICRA) && defined(EICRB)
ISR(INT0_vect) {
if(intFunc[EXTERNAL_INT_2])
intFunc[EXTERNAL_INT_2]();
}
ISR(INT1_vect) {
if(intFunc[EXTERNAL_INT_3])
intFunc[EXTERNAL_INT_3]();
}
ISR(INT2_vect) {
if(intFunc[EXTERNAL_INT_4])
intFunc[EXTERNAL_INT_4]();
}
ISR(INT3_vect) {
if(intFunc[EXTERNAL_INT_5])
intFunc[EXTERNAL_INT_5]();
}
ISR(INT4_vect) {
if(intFunc[EXTERNAL_INT_0])
intFunc[EXTERNAL_INT_0]();
}
ISR(INT5_vect) {
if(intFunc[EXTERNAL_INT_1])
intFunc[EXTERNAL_INT_1]();
}
ISR(INT6_vect) {
if(intFunc[EXTERNAL_INT_6])
intFunc[EXTERNAL_INT_6]();
}
ISR(INT7_vect) {
if(intFunc[EXTERNAL_INT_7])
intFunc[EXTERNAL_INT_7]();
}
#else
ISR(INT0_vect) {
if(intFunc[EXTERNAL_INT_0])
intFunc[EXTERNAL_INT_0]();
}
ISR(INT1_vect) {
if(intFunc[EXTERNAL_INT_1])
intFunc[EXTERNAL_INT_1]();
}
#if defined(EICRA) && defined(ISC20)
ISR(INT2_vect) {
if(intFunc[EXTERNAL_INT_2])
intFunc[EXTERNAL_INT_2]();
}
#endif
#endif
/*
ISR(TWI_vect) {
if(twiIntFunc)
twiIntFunc();
}
*/
Reduced testcases:
WInterrupts.ll
:
llc WInterrupts.ll -mcpu=atmega328p -filetype=obj
; ModuleID = '/usr/share/arduino/hardware/arduino/avr/cores/arduino/WInterrupts.c'
target datalayout = "e-p:16:8:8-i8:8:8-i16:8:8-i32:8:8-i64:8:8-f32:8:8-f64:8:8-n8"
target triple = "avr"
@intFunc = internal global [2 x void ()*] zeroinitializer, align 2
@llvm.used = appending global [2 x i8*] [i8* bitcast (void ()* @__vector_1 to i8*), i8* bitcast (void ()* @__vector_2 to i8*)], section "llvm.metadata"
; Function Attrs: nounwind optsize
define void @attachInterrupt(i8 zeroext %interruptNum, void ()* %userFunc, i16 %mode) #0 {
entry:
tail call void @llvm.dbg.value(metadata i8 %interruptNum, i64 0, metadata !18, metadata !39), !dbg !40
tail call void @llvm.dbg.value(metadata void ()* %userFunc, i64 0, metadata !19, metadata !39), !dbg !41
tail call void @llvm.dbg.value(metadata i16 %mode, i64 0, metadata !20, metadata !39), !dbg !42
%cmp = icmp ult i8 %interruptNum, 2, !dbg !43
br i1 %cmp, label %if.then, label %if.end, !dbg !45
if.then: ; preds = %entry
%conv = zext i8 %interruptNum to i16, !dbg !46
%arrayidx = getelementptr inbounds [2 x void ()*], [2 x void ()*]* @intFunc, i16 0, i16 %conv, !dbg !47
store volatile void ()* %userFunc, void ()** %arrayidx, align 2, !dbg !49, !tbaa !50
switch i8 %interruptNum, label %if.end [
i8 0, label %sw.bb
i8 1, label %sw.bb.8
], !dbg !54
sw.bb: ; preds = %if.then
%0 = load volatile i8, i8* inttoptr (i16 105 to i8*), align 1, !dbg !55, !tbaa !57
%conv3 = zext i8 %0 to i16, !dbg !55
%and = and i16 %conv3, 252, !dbg !58
%or = or i16 %and, %mode, !dbg !59
%conv4 = trunc i16 %or to i8, !dbg !60
store volatile i8 %conv4, i8* inttoptr (i16 105 to i8*), align 1, !dbg !61, !tbaa !57
%1 = load volatile i8, i8* inttoptr (i16 61 to i8*), align 1, !dbg !62, !tbaa !57
%or6 = or i8 %1, 1, !dbg !62
store volatile i8 %or6, i8* inttoptr (i16 61 to i8*), align 1, !dbg !62, !tbaa !57
br label %if.end, !dbg !63
sw.bb.8: ; preds = %if.then
%2 = load volatile i8, i8* inttoptr (i16 105 to i8*), align 1, !dbg !64, !tbaa !57
%conv9 = zext i8 %2 to i16, !dbg !64
%and10 = and i16 %conv9, 243, !dbg !65
%shl11 = shl i16 %mode, 2, !dbg !66
%or12 = or i16 %and10, %shl11, !dbg !67
%conv13 = trunc i16 %or12 to i8, !dbg !68
store volatile i8 %conv13, i8* inttoptr (i16 105 to i8*), align 1, !dbg !69, !tbaa !57
%3 = load volatile i8, i8* inttoptr (i16 61 to i8*), align 1, !dbg !70, !tbaa !57
%or15 = or i8 %3, 2, !dbg !70
store volatile i8 %or15, i8* inttoptr (i16 61 to i8*), align 1, !dbg !70, !tbaa !57
br label %if.end, !dbg !71
if.end: ; preds = %sw.bb, %sw.bb.8, %if.then, %entry
ret void, !dbg !72
}
; Function Attrs: nounwind optsize
define void @detachInterrupt(i8 zeroext %interruptNum) #0 {
entry:
tail call void @llvm.dbg.value(metadata i8 %interruptNum, i64 0, metadata !25, metadata !39), !dbg !73
%conv = zext i8 %interruptNum to i16, !dbg !74
%cmp = icmp ult i8 %interruptNum, 2, !dbg !76
br i1 %cmp, label %if.then, label %if.end, !dbg !77
if.then: ; preds = %entry
switch i8 %interruptNum, label %sw.epilog [
i8 0, label %sw.bb
i8 1, label %sw.bb.5
], !dbg !78
sw.bb: ; preds = %if.then
%0 = load volatile i8, i8* inttoptr (i16 61 to i8*), align 1, !dbg !80, !tbaa !57
%and = and i8 %0, -2, !dbg !80
store volatile i8 %and, i8* inttoptr (i16 61 to i8*), align 1, !dbg !80, !tbaa !57
br label %sw.epilog, !dbg !82
sw.bb.5: ; preds = %if.then
%1 = load volatile i8, i8* inttoptr (i16 61 to i8*), align 1, !dbg !83, !tbaa !57
%and7 = and i8 %1, -3, !dbg !83
store volatile i8 %and7, i8* inttoptr (i16 61 to i8*), align 1, !dbg !83, !tbaa !57
br label %sw.epilog, !dbg !84
sw.epilog: ; preds = %if.then, %sw.bb.5, %sw.bb
%arrayidx = getelementptr inbounds [2 x void ()*], [2 x void ()*]* @intFunc, i16 0, i16 %conv, !dbg !85
store volatile void ()* null, void ()** %arrayidx, align 2, !dbg !86, !tbaa !50
br label %if.end, !dbg !87
if.end: ; preds = %sw.epilog, %entry
ret void, !dbg !88
}
; Function Attrs: noinline nounwind optsize
define avr_signalcc void @__vector_1() #1 {
entry:
%0 = load volatile void ()*, void ()** getelementptr inbounds ([2 x void ()*], [2 x void ()*]* @intFunc, i16 0, i16 0), align 2, !dbg !89, !tbaa !50
%tobool = icmp eq void ()* %0, null, !dbg !89
br i1 %tobool, label %if.end, label %if.then, !dbg !91
if.then: ; preds = %entry
%1 = load volatile void ()*, void ()** getelementptr inbounds ([2 x void ()*], [2 x void ()*]* @intFunc, i16 0, i16 0), align 2, !dbg !92, !tbaa !50
tail call void %1() #3, !dbg !92
br label %if.end, !dbg !92
if.end: ; preds = %entry, %if.then
ret void, !dbg !93
}
; Function Attrs: noinline nounwind optsize
define avr_signalcc void @__vector_2() #1 {
entry:
%0 = load volatile void ()*, void ()** getelementptr inbounds ([2 x void ()*], [2 x void ()*]* @intFunc, i16 0, i16 1), align 2, !dbg !94, !tbaa !50
%tobool = icmp eq void ()* %0, null, !dbg !94
br i1 %tobool, label %if.end, label %if.then, !dbg !96
if.then: ; preds = %entry
%1 = load volatile void ()*, void ()** getelementptr inbounds ([2 x void ()*], [2 x void ()*]* @intFunc, i16 0, i16 1), align 2, !dbg !97, !tbaa !50
tail call void %1() #3, !dbg !97
br label %if.end, !dbg !97
if.end: ; preds = %entry, %if.then
ret void, !dbg !98
}
; Function Attrs: nounwind readnone
declare void @llvm.dbg.value(metadata, i64, metadata, metadata) #2
attributes #0 = { nounwind optsize "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="atmega328p" "unsafe-fp-math"="false" "use-soft-float"="false" }
attributes #1 = { noinline nounwind optsize "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="atmega328p" "unsafe-fp-math"="false" "use-soft-float"="false" }
attributes #2 = { nounwind readnone }
attributes #3 = { nounwind optsize }
!llvm.dbg.cu = !{!0}
!llvm.module.flags = !{!36, !37}
!llvm.ident = !{!38}
!0 = !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 3.7.0 (https://github.com/llvm-mirror/clang.git aebd4f6d15e44635ecc7338d4454389c4573bc2b) (https://github.com/llvm-mirror/llvm.git 2f1e7fe1e133874beba11f82834ce6cbb995510b)", isOptimized: true, runtimeVersion: 0, emissionKind: 1, enums: !2, retainedTypes: !3, subprograms: !9, globals: !28, imports: !2)
!1 = !DIFile(filename: "/usr/share/arduino/hardware/arduino/avr/cores/arduino/WInterrupts.c", directory: "/home/dylan/projects/builds/avr-llvm/llvm/bin")
!2 = !{}
!3 = !{!4}
!4 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !5, size: 16, align: 16)
!5 = !DIDerivedType(tag: DW_TAG_volatile_type, baseType: !6)
!6 = !DIDerivedType(tag: DW_TAG_typedef, name: "uint8_t", file: !7, line: 123, baseType: !8)
!7 = !DIFile(filename: "/usr/avr/include/stdint.h", directory: "/home/dylan/projects/builds/avr-llvm/llvm/bin")
!8 = !DIBasicType(name: "unsigned char", size: 8, align: 8, encoding: DW_ATE_unsigned_char)
!9 = !{!10, !21, !26, !27}
!10 = !DISubprogram(name: "attachInterrupt", scope: !1, file: !1, line: 38, type: !11, isLocal: false, isDefinition: true, scopeLine: 38, flags: DIFlagPrototyped, isOptimized: true, function: void (i8, void ()*, i16)* @attachInterrupt, variables: !17)
!11 = !DISubroutineType(types: !12)
!12 = !{null, !6, !13, !16}
!13 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !14, size: 16, align: 16)
!14 = !DISubroutineType(types: !15)
!15 = !{null}
!16 = !DIBasicType(name: "int", size: 16, align: 16, encoding: DW_ATE_signed)
!17 = !{!18, !19, !20}
!18 = !DILocalVariable(tag: DW_TAG_arg_variable, name: "interruptNum", arg: 1, scope: !10, file: !1, line: 38, type: !6)
!19 = !DILocalVariable(tag: DW_TAG_arg_variable, name: "userFunc", arg: 2, scope: !10, file: !1, line: 38, type: !13)
!20 = !DILocalVariable(tag: DW_TAG_arg_variable, name: "mode", arg: 3, scope: !10, file: !1, line: 38, type: !16)
!21 = !DISubprogram(name: "detachInterrupt", scope: !1, file: !1, line: 155, type: !22, isLocal: false, isDefinition: true, scopeLine: 155, flags: DIFlagPrototyped, isOptimized: true, function: void (i8)* @detachInterrupt, variables: !24)
!22 = !DISubroutineType(types: !23)
!23 = !{null, !6}
!24 = !{!25}
!25 = !DILocalVariable(tag: DW_TAG_arg_variable, name: "interruptNum", arg: 1, scope: !21, file: !1, line: 155, type: !6)
!26 = !DISubprogram(name: "__vector_1", scope: !1, file: !1, line: 309, type: !14, isLocal: false, isDefinition: true, scopeLine: 309, flags: DIFlagPrototyped, isOptimized: true, function: void ()* @__vector_1, variables: !2)
!27 = !DISubprogram(name: "__vector_2", scope: !1, file: !1, line: 314, type: !14, isLocal: false, isDefinition: true, scopeLine: 314, flags: DIFlagPrototyped, isOptimized: true, function: void ()* @__vector_2, variables: !2)
!28 = !{!29}
!29 = !DIGlobalVariable(name: "intFunc", scope: !0, file: !1, line: 35, type: !30, isLocal: true, isDefinition: true, variable: [2 x void ()*]* @intFunc)
!30 = !DICompositeType(tag: DW_TAG_array_type, baseType: !31, size: 32, align: 16, elements: !34)
!31 = !DIDerivedType(tag: DW_TAG_volatile_type, baseType: !32)
!32 = !DIDerivedType(tag: DW_TAG_typedef, name: "voidFuncPtr", file: !33, line: 65, baseType: !13)
!33 = !DIFile(filename: "/usr/share/arduino/hardware/arduino/avr/cores/arduino/wiring_private.h", directory: "/home/dylan/projects/builds/avr-llvm/llvm/bin")
!34 = !{!35}
!35 = !DISubrange(count: 2)
!36 = !{i32 2, !"Dwarf Version", i32 4}
!37 = !{i32 2, !"Debug Info Version", i32 3}
!38 = !{!"clang version 3.7.0 (https://github.com/llvm-mirror/clang.git aebd4f6d15e44635ecc7338d4454389c4573bc2b) (https://github.com/llvm-mirror/llvm.git 2f1e7fe1e133874beba11f82834ce6cbb995510b)"}
!39 = !DIExpression()
!40 = !DILocation(line: 38, column: 30, scope: !10)
!41 = !DILocation(line: 38, column: 51, scope: !10)
!42 = !DILocation(line: 38, column: 72, scope: !10)
!43 = !DILocation(line: 39, column: 19, scope: !44)
!44 = distinct !DILexicalBlock(scope: !10, file: !1, line: 39, column: 6)
!45 = !DILocation(line: 39, column: 6, scope: !10)
!46 = !DILocation(line: 39, column: 6, scope: !44)
!47 = !DILocation(line: 40, column: 5, scope: !48)
!48 = distinct !DILexicalBlock(scope: !44, file: !1, line: 39, column: 46)
!49 = !DILocation(line: 40, column: 27, scope: !48)
!50 = !{!51, !51, i64 0}
!51 = !{!"any pointer", !52, i64 0}
!52 = !{!"omnipotent char", !53, i64 0}
!53 = !{!"Simple C/C++ TBAA"}
!54 = !DILocation(line: 49, column: 5, scope: !48)
!55 = !DILocation(line: 110, column: 16, scope: !56)
!56 = distinct !DILexicalBlock(scope: !48, file: !1, line: 49, column: 27)
!57 = !{!52, !52, i64 0}
!58 = !DILocation(line: 110, column: 22, scope: !56)
!59 = !DILocation(line: 110, column: 56, scope: !56)
!60 = !DILocation(line: 110, column: 15, scope: !56)
!61 = !DILocation(line: 110, column: 13, scope: !56)
!62 = !DILocation(line: 111, column: 13, scope: !56)
!63 = !DILocation(line: 121, column: 7, scope: !56)
!64 = !DILocation(line: 125, column: 16, scope: !56)
!65 = !DILocation(line: 125, column: 22, scope: !56)
!66 = !DILocation(line: 125, column: 64, scope: !56)
!67 = !DILocation(line: 125, column: 56, scope: !56)
!68 = !DILocation(line: 125, column: 15, scope: !56)
!69 = !DILocation(line: 125, column: 13, scope: !56)
!70 = !DILocation(line: 126, column: 13, scope: !56)
!71 = !DILocation(line: 136, column: 7, scope: !56)
!72 = !DILocation(line: 153, column: 1, scope: !10)
!73 = !DILocation(line: 155, column: 30, scope: !21)
!74 = !DILocation(line: 156, column: 6, scope: !75)
!75 = distinct !DILexicalBlock(scope: !21, file: !1, line: 156, column: 6)
!76 = !DILocation(line: 156, column: 19, scope: !75)
!77 = !DILocation(line: 156, column: 6, scope: !21)
!78 = !DILocation(line: 160, column: 5, scope: !79)
!79 = distinct !DILexicalBlock(scope: !75, file: !1, line: 156, column: 46)
!80 = !DILocation(line: 205, column: 13, scope: !81)
!81 = distinct !DILexicalBlock(scope: !79, file: !1, line: 160, column: 27)
!82 = !DILocation(line: 213, column: 7, scope: !81)
!83 = !DILocation(line: 217, column: 13, scope: !81)
!84 = !DILocation(line: 225, column: 7, scope: !81)
!85 = !DILocation(line: 229, column: 5, scope: !79)
!86 = !DILocation(line: 229, column: 27, scope: !79)
!87 = !DILocation(line: 230, column: 3, scope: !79)
!88 = !DILocation(line: 231, column: 1, scope: !21)
!89 = !DILocation(line: 310, column: 6, scope: !90)
!90 = distinct !DILexicalBlock(scope: !26, file: !1, line: 310, column: 6)
!91 = !DILocation(line: 310, column: 6, scope: !26)
!92 = !DILocation(line: 311, column: 5, scope: !90)
!93 = !DILocation(line: 312, column: 1, scope: !26)
!94 = !DILocation(line: 315, column: 6, scope: !95)
!95 = distinct !DILexicalBlock(scope: !27, file: !1, line: 315, column: 6)
!96 = !DILocation(line: 315, column: 6, scope: !27)
!97 = !DILocation(line: 316, column: 5, scope: !95)
!98 = !DILocation(line: 317, column: 1, scope: !27)
WInterrupts.s
:
llvm-mc WInterrupts.s --triple avr -mcpu=atmega328p -filetype=obj
.text
.file "WInterrupts.ll"
.globl attachInterrupt
.align 2
.type attachInterrupt,@function
attachInterrupt: ; @attachInterrupt
; BB#0: ; %entry
;DEBUG_VALUE: attachInterrupt:interruptNum <- R24
;DEBUG_VALUE: attachInterrupt:userFunc <- R23R22
;DEBUG_VALUE: attachInterrupt:mode <- R21R20
ldi r25, 2
cp r24, r25
brsh LBB0_5
; BB#1: ; %if.then
;DEBUG_VALUE: attachInterrupt:interruptNum <- R24
;DEBUG_VALUE: attachInterrupt:userFunc <- R23R22
;DEBUG_VALUE: attachInterrupt:mode <- R21R20
mov r30, r24
eor r31, r31
lsl r30
rol r31
subi r30, lo8(-intFunc)
sbci r31, hi8(-intFunc)
st Z, r22
std Z+1, r23
ldi r25, 1
cp r24, r25
brne LBB0_3
; BB#2: ; %sw.bb.8
;DEBUG_VALUE: attachInterrupt:mode <- R21R20
lds r24, 105
andi r24, 243
andi r25, 0
lsl r20
rol r21
lsl r20
rol r21
or r20, r24
or r21, r25
sts 105, r20
sbi 29, 1
rjmp LBB0_5
LBB0_3: ; %if.then
;DEBUG_VALUE: attachInterrupt:interruptNum <- R24
;DEBUG_VALUE: attachInterrupt:mode <- R21R20
ldi r25, 0
cp r24, r25
brne LBB0_5
; BB#4: ; %sw.bb
;DEBUG_VALUE: attachInterrupt:mode <- R21R20
lds r24, 105
andi r24, 252
andi r25, 0
or r24, r20
or r25, r21
sts 105, r24
sbi 29, 0
ret
LBB0_5: ; %if.end
ret
.Lfunc_end0:
.size attachInterrupt, .Lfunc_end0-attachInterrupt
.globl detachInterrupt
.align 2
.type detachInterrupt,@function
detachInterrupt: ; @detachInterrupt
; BB#0: ; %entry
;DEBUG_VALUE: detachInterrupt:interruptNum <- R24
ldi r25, 2
cp r24, r25
brsh LBB1_6
; BB#1: ; %if.then
;DEBUG_VALUE: detachInterrupt:interruptNum <- R24
mov r30, r24
eor r31, r31
ldi r25, 1
cp r24, r25
brne LBB1_3
; BB#2: ; %sw.bb.5
cbi 29, 1
rjmp LBB1_5
LBB1_3: ; %if.then
;DEBUG_VALUE: detachInterrupt:interruptNum <- R24
ldi r25, 0
cp r24, r25
brne LBB1_5
; BB#4: ; %sw.bb
cbi 29, 0
LBB1_5: ; %sw.epilog
lsl r30
rol r31
subi r30, lo8(-intFunc)
sbci r31, hi8(-intFunc)
ldi r24, 0
ldi r25, 0
st Z, r24
std Z+1, r25
LBB1_6: ; %if.end
ret
.Lfunc_end1:
.size detachInterrupt, .Lfunc_end1-detachInterrupt
.globl __vector_1
.align 2
.type __vector_1,@function
__vector_1: ; @__vector_1
; BB#0: ; %entry
push r0
push r1
in r0, 63
push r0
push r0
push r1
push r18
push r19
push r20
push r21
push r22
push r23
push r24
push r25
push r26
push r27
push r30
push r31
ldi r24, 0
ldi r25, 0
lds r18, intFunc
lds r19, intFunc+1
cp r18, r24
cpc r19, r25
breq LBB2_2
; BB#1: ; %if.then
lds r30, intFunc
lds r31, intFunc+1
icall
LBB2_2: ; %if.end
pop r31
pop r30
pop r27
pop r26
pop r25
pop r24
pop r23
pop r22
pop r21
pop r20
pop r19
pop r18
pop r1
pop r0
pop r0
out 63, r0
pop r1
pop r0
reti
.Lfunc_end2:
.size __vector_1, .Lfunc_end2-__vector_1
.globl __vector_2
.align 2
.type __vector_2,@function
__vector_2: ; @__vector_2
; BB#0: ; %entry
push r0
push r1
in r0, 63
push r0
push r0
push r1
push r18
push r19
push r20
push r21
push r22
push r23
push r24
push r25
push r26
push r27
push r30
push r31
ldi r24, 0
ldi r25, 0
lds r18, intFunc+2
lds r19, intFunc+3
cp r18, r24
cpc r19, r25
breq LBB3_2
; BB#1: ; %if.then
lds r30, intFunc+2
lds r31, intFunc+3
icall
LBB3_2: ; %if.end
pop r31
pop r30
pop r27
pop r26
pop r25
pop r24
pop r23
pop r22
pop r21
pop r20
pop r19
pop r18
pop r1
pop r0
pop r0
out 63, r0
pop r1
pop r0
reti
.Lfunc_end3:
.size __vector_2, .Lfunc_end3-__vector_2
.type intFunc,@object ; @intFunc
.local intFunc
.comm intFunc,4,2
This is caused because AVRMCExpr::evaluateAsRelocatableImpl
doesn't handle the case where the hi8(..)
, lo8(..)
fixups have non-absolute immediates as targets (i.e. a label as a target).
Reduced, reduced test case:
llvm-mc -arch=avr -mcpu=atmega328p -filetype=obj
sbci r31, lo8(main)
Hehe, I'm already on it. Here is my test case:
foo: ldi r24, lo8(foo)
The whole fixup-relocation-expression-business seems a bit out of whack. Note, that this is probably (partly) my doing, since I beefed up AVRMCExpr a bit, left a dangling TODO... yadda yadda
Your testcase is nice, but it could use some work :)
I have strong doubts that you had anything to do with this bug due to how old it is.
still having the issue:
MBA-Anton:bin asmirnov$ ./clang --version
clang version 3.7.0 (https://github.com/avr-llvm/clang.git aebd4f6d15e44635ecc7338d4454389c4573bc2b) (llvm/llvm 9c7c5212863ed8b06323ad07fa84bad29ff051f8)
Target: x86_64-apple-darwin14.3.0
Thread model: posix
MBA-Anton:bin asmirnov$ ./clang -c -g -Os -Wall -ffunction-sections -fdata-sections -mmcu=atmega328p -DARDUINO=10600 -DARDUINO_AVR_UNO -DARDUINO_ARCH_AVR -DF_CPU=16000000L -MMD -DUSB_VID=null -DUSB_PID=null -I/Applications/Arduino.app/Contents/Resources/Java/hardware/arduino/avr/cores/arduino -I/Applications/Arduino.app/Contents/Resources/Java/hardware/arduino/avr/variants/standard -I/Applications/Arduino.app/Contents/Resources/Java/hardware/tools/avr/avr/include --target=avr /Applications/Arduino.app/Contents/Resources/Java/hardware/arduino/avr/cores/arduino/WInterrupts.c -o /tmp/arduino_test1/WInterrupts.c.o
In file included from /Applications/Arduino.app/Contents/Resources/Java/hardware/arduino/avr/cores/arduino/WInterrupts.c:31:
/Applications/Arduino.app/Contents/Resources/Java/hardware/tools/avr/avr/include/stdio.h:724:12: warning:
declaration of built-in function 'fprintf' requires inclusion of the header <stdio.h>
[-Wbuiltin-requires-header]
extern int fprintf(FILE *__stream, const char *__fmt, ...);
^
/Applications/Arduino.app/Contents/Resources/Java/hardware/tools/avr/avr/include/stdio.h:875:12: warning:
declaration of built-in function 'vfscanf' requires inclusion of the header <stdio.h>
[-Wbuiltin-requires-header]
extern int vfscanf(FILE *__stream, const char *__fmt, va_list __ap);
^
/Applications/Arduino.app/Contents/Resources/Java/hardware/tools/avr/avr/include/stdio.h:888:12: warning:
declaration of built-in function 'fscanf' requires inclusion of the header <stdio.h>
[-Wbuiltin-requires-header]
extern int fscanf(FILE *__stream, const char *__fmt, ...);
^
fatal error: error in backend: expected relocatable expression
Can you try llvm-mc --triple avr -mcpu=atmega328p -filetype=obj
and type ldi r24, lo8(main)
and then Enter Ctrl+D Enter
? does this succeed?