In Thumb2, direct branches can be encoded as either a "short" conditional branch...
[oota-llvm.git] / lib / Target / ARM / ARMAsmBackend.cpp
index e2a23acd0ceab0904509abbc03e01f46be1f3df8..cb0c54386ed67e95d7663b157d773d7d5ef039cd 100644 (file)
@@ -98,16 +98,29 @@ static unsigned adjustFixupValue(unsigned Kind, uint64_t Value) {
     Value = (Hi4 << 16) | (Lo12);
     return Value;
   }
-  case ARM::fixup_arm_ldst_pcrel_12: {
-    bool isAdd = true;
+  case ARM::fixup_arm_ldst_pcrel_12:
     // ARM PC-relative values are offset by 8.
-    Value -= 8;
+    Value -= 4;
+    // FALLTHROUGH
+  case ARM::fixup_t2_ldst_pcrel_12: {
+    // Offset by 4, adjusted by two due to the half-word ordering of thumb.
+    Value -= 4;
+    bool isAdd = true;
     if ((int64_t)Value < 0) {
       Value = -Value;
       isAdd = false;
     }
     assert ((Value < 4096) && "Out of range pc-relative fixup value!");
     Value |= isAdd << 23;
+
+    // Same addressing mode as fixup_arm_pcrel_10,
+    // but with 16-bit halfwords swapped.
+    if (Kind == ARM::fixup_t2_ldst_pcrel_12) {
+      uint64_t swapped = (Value & 0xFFFF0000) >> 16;
+      swapped |= (Value & 0x0000FFFF) << 16;
+      return swapped;
+    }
+
     return Value;
   }
   case ARM::fixup_arm_adr_pcrel_12: {
@@ -127,8 +140,29 @@ static unsigned adjustFixupValue(unsigned Kind, uint64_t Value) {
     // These values don't encode the low two bits since they're always zero.
     // Offset by 8 just as above.
     return 0xffffff & ((Value - 8) >> 2);
-  case ARM::fixup_t2_branch: {
-    Value = Value - 6;
+  case ARM::fixup_t2_uncondbranch: {
+    Value = Value - 4;
+    Value >>= 1; // Low bit is not encoded.
+
+    uint32_t out = 0;
+    bool I =  Value & 0x800000;
+    bool J1 = Value & 0x400000;
+    bool J2 = Value & 0x200000;
+    J1 ^= I;
+    J2 ^= I;
+    
+    out |= I  << 26; // S bit
+    out |= !J1 << 13; // J1 bit
+    out |= !J2 << 11; // J2 bit
+    out |= (Value & 0x1FF800)  << 5; // imm6 field
+    out |= (Value & 0x0007FF);        // imm11 field
+    
+    uint64_t swapped = (out & 0xFFFF0000) >> 16;
+    swapped |= (out & 0x0000FFFF) << 16;
+    return swapped;
+  }
+  case ARM::fixup_t2_condbranch: {
+    Value = Value - 4;
     Value >>= 1; // Low bit is not encoded.
     
     uint64_t out = 0;
@@ -137,8 +171,8 @@ static unsigned adjustFixupValue(unsigned Kind, uint64_t Value) {
     out |= (Value & 0x20000) >> 4; // J1 bit
     out |= (Value & 0x1F800) << 5; // imm6 field
     out |= (Value & 0x007FF);      // imm11 field
-    
-    uint64_t swapped = (out & 0xFFFF0000) >> 16;
+
+    uint32_t swapped = (out & 0xFFFF0000) >> 16;
     swapped |= (out & 0x0000FFFF) << 16;
     return swapped;
   }
@@ -146,9 +180,9 @@ static unsigned adjustFixupValue(unsigned Kind, uint64_t Value) {
     // The value doesn't encode the low bit (always zero) and is offset by
     // four. The value is encoded into disjoint bit positions in the destination
     // opcode. x = unchanged, I = immediate value bit, S = sign extension bit
-    // 
+    //
     //   BL:  xxxxxSIIIIIIIIII xxxxxIIIIIIIIIII
-    // 
+    //
     // Note that the halfwords are stored high first, low second; so we need
     // to transpose the fixup value here to map properly.
     unsigned isNeg = (int64_t(Value) < 0) ? 1 : 0;
@@ -164,9 +198,9 @@ static unsigned adjustFixupValue(unsigned Kind, uint64_t Value) {
     // four (see fixup_arm_thumb_cp). The value is encoded into disjoint bit
     // positions in the destination opcode. x = unchanged, I = immediate value
     // bit, S = sign extension bit, 0 = zero.
-    // 
+    //
     //   BLX: xxxxxSIIIIIIIIII xxxxxIIIIIIIIII0
-    // 
+    //
     // Note that the halfwords are stored high first, low second; so we need
     // to transpose the fixup value here to map properly.
     unsigned isNeg = (int64_t(Value) < 0) ? 1 : 0;
@@ -182,18 +216,24 @@ static unsigned adjustFixupValue(unsigned Kind, uint64_t Value) {
     // 'off by 4' is implicitly handled by the half-word ordering of the
     // Thumb encoding, so we only need to adjust by 2 here.
     return ((Value - 2) >> 2) & 0xff;
-  case ARM::fixup_arm_thumb_br: {
+  case ARM::fixup_arm_thumb_cb: {
     // Offset by 4 and don't encode the lower bit, which is always 0.
     uint32_t Binary = (Value - 4) >> 1;
     return ((Binary & 0x20) << 9) | ((Binary & 0x1f) << 3);
   }
+  case ARM::fixup_arm_thumb_br:
+    // Offset by 4 and don't encode the lower bit, which is always 0.
+    return ((Value - 4) >> 1) & 0x7ff;
+  case ARM::fixup_arm_thumb_bcc:
+    // Offset by 4 and don't encode the lower bit, which is always 0.
+    return ((Value - 4) >> 1) & 0xff;
   case ARM::fixup_arm_pcrel_10:
-    Value = Value - 6; // ARM fixups offset by an additional word and don't
+    Value = Value - 4; // ARM fixups offset by an additional word and don't
                        // need to adjust for the half-word ordering.
     // Fall through.
   case ARM::fixup_t2_pcrel_10: {
     // Offset by 4, adjusted by two due to the half-word ordering of thumb.
-    Value = Value - 2;
+    Value = Value - 4;
     bool isAdd = true;
     if ((int64_t)Value < 0) {
       Value = -Value;
@@ -207,7 +247,7 @@ static unsigned adjustFixupValue(unsigned Kind, uint64_t Value) {
     // Same addressing mode as fixup_arm_pcrel_10,
     // but with 16-bit halfwords swapped.
     if (Kind == ARM::fixup_t2_pcrel_10) {
-      uint64_t swapped = (Value & 0xFFFF0000) >> 16;
+      uint32_t swapped = (Value & 0xFFFF0000) >> 16;
       swapped |= (Value & 0x0000FFFF) << 16;
       return swapped;
     }
@@ -297,10 +337,12 @@ static unsigned getFixupKindNumBytes(unsigned Kind) {
   default:
     llvm_unreachable("Unknown fixup kind!");
 
+  case ARM::fixup_arm_thumb_bcc:
   case ARM::fixup_arm_thumb_cp:
     return 1;
 
   case ARM::fixup_arm_thumb_br:
+  case ARM::fixup_arm_thumb_cb:
     return 2;
 
   case ARM::fixup_arm_ldst_pcrel_12:
@@ -310,7 +352,9 @@ static unsigned getFixupKindNumBytes(unsigned Kind) {
     return 3;
 
   case FK_Data_4:
-  case ARM::fixup_t2_branch:
+  case ARM::fixup_t2_ldst_pcrel_12:
+  case ARM::fixup_t2_condbranch:
+  case ARM::fixup_t2_uncondbranch:
   case ARM::fixup_t2_pcrel_10:
   case ARM::fixup_arm_thumb_bl:
   case ARM::fixup_arm_thumb_blx: