Skip to content

Commit

Permalink
[tlv] Optimize code size of processing context tags
Browse files Browse the repository at this point in the history
TLV tag is represented as uint64_t that encodes the
following components:
- 16-bit vendor ID
- 16-bit profile number
- 32-bit tag number

Context tags, which account for vast majority of tag usage
in the SDK, are encoded as having both vendor ID and profile
number equal to 0xFFFF. Anonymous tags are encoded in the
same way, but using 0xFFFFFFFF tag number.
This is correct because vendor IDs higher than 0xFFF0 shall
not be assigned to real manufacturers, but constructing
0xFF... constants in hundreds of places adds non-negligible
overhead to the flash usage.

Encode profile ID in the negated form internally to optimize
the code size when using special tags.
  • Loading branch information
Damian-Nordic committed Jan 2, 2023
1 parent 3eb17b4 commit 8a5002b
Showing 1 changed file with 35 additions and 10 deletions.
45 changes: 35 additions & 10 deletions src/lib/core/CHIPTLVTags.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,11 @@ class Tag
friend constexpr Tag AnonymousTag();
friend constexpr Tag UnknownImplicitTag();

// The following friend functions could be Tag class methods, but it turns out in some cases
// they may not be inlined and then passing the tag by argument/value results in smaller code
// than passing it by 'this' pointer. This can be worked around by applying 'always_inline'
// function attribute, but friend functions are likely a more portable solution.

friend constexpr uint32_t ProfileIdFromTag(Tag tag);
friend constexpr uint16_t VendorIdFromTag(Tag tag);
friend constexpr uint16_t ProfileNumFromTag(Tag tag);
Expand All @@ -60,9 +65,23 @@ class Tag
static constexpr uint32_t kVendorIdShift = 48;
static constexpr uint32_t kProfileNumShift = 32;
static constexpr uint32_t kSpecialTagProfileId = 0xFFFFFFFF;
static constexpr uint32_t kAnonymousTagNum = 0xFFFFFFFF;
static constexpr uint32_t kContextTagMaxNum = UINT8_MAX;

enum SpecialTagNumber : uint32_t
{
kContextTagMaxNum = UINT8_MAX,
kAnonymousTagNum,
kUnknownImplicitTagNum
};

// The API representation of the tag uses the following encoding:
//
// 63 47 31
// +-----------------------+-----------------------+----------------------------------------------+
// | Vendor id (negated) | Profile num (negated) | Tag number |
// +-----------------------+-----------------------+----------------------------------------------+
//
// Vendor id and profile number are negated in order to optimize the code size when using
// context tags, the most commonly used tags in the SDK.
uint64_t mVal;
};

Expand Down Expand Up @@ -115,7 +134,7 @@ enum
*/
constexpr Tag ProfileTag(uint32_t profileId, uint32_t tagNum)
{
return Tag((static_cast<uint64_t>(profileId) << Tag::kProfileIdShift) | tagNum);
return Tag((static_cast<uint64_t>(~profileId) << Tag::kProfileIdShift) | tagNum);
}

/**
Expand All @@ -128,12 +147,13 @@ constexpr Tag ProfileTag(uint32_t profileId, uint32_t tagNum)
*/
constexpr Tag ProfileTag(uint16_t vendorId, uint16_t profileNum, uint32_t tagNum)
{
return Tag((static_cast<uint64_t>(vendorId) << Tag::kVendorIdShift) |
(static_cast<uint64_t>(profileNum) << Tag::kProfileNumShift) | tagNum);
constexpr uint32_t kVendorIdShift = Tag::kVendorIdShift - Tag::kProfileIdShift;

return ProfileTag((static_cast<uint32_t>(vendorId) << kVendorIdShift) | profileNum, tagNum);
}

/**
* Generates the API representation for of context-specific TLV tag
* Generates the API representation of a context-specific TLV tag
*
* @param[in] tagNum The context-specific tag number assigned to the tag.
* @return A 64-bit integer representing the tag.
Expand Down Expand Up @@ -162,9 +182,12 @@ constexpr Tag AnonymousTag()
return ProfileTag(Tag::kSpecialTagProfileId, Tag::kAnonymousTagNum);
}

/**
* An invalid tag that represents a TLV element decoding error due to unknown implicit profile id.
*/
constexpr Tag UnknownImplicitTag()
{
return ProfileTag(Tag::kSpecialTagProfileId, 0xFFFFFFFE);
return ProfileTag(Tag::kSpecialTagProfileId, Tag::kUnknownImplicitTagNum);
}

/**
Expand All @@ -177,7 +200,7 @@ constexpr Tag UnknownImplicitTag()
*/
constexpr uint32_t ProfileIdFromTag(Tag tag)
{
return static_cast<uint32_t>(tag.mVal >> Tag::kProfileIdShift);
return ~static_cast<uint32_t>(tag.mVal >> Tag::kProfileIdShift);
}

/**
Expand All @@ -190,7 +213,9 @@ constexpr uint32_t ProfileIdFromTag(Tag tag)
*/
constexpr uint16_t VendorIdFromTag(Tag tag)
{
return static_cast<uint16_t>(tag.mVal >> Tag::kVendorIdShift);
constexpr uint32_t kVendorIdShift = Tag::kVendorIdShift - Tag::kProfileIdShift;

return static_cast<uint16_t>(ProfileIdFromTag(tag) >> kVendorIdShift);
}

/**
Expand All @@ -203,7 +228,7 @@ constexpr uint16_t VendorIdFromTag(Tag tag)
*/
constexpr uint16_t ProfileNumFromTag(Tag tag)
{
return static_cast<uint16_t>(tag.mVal >> Tag::kProfileNumShift);
return static_cast<uint16_t>(ProfileIdFromTag(tag));
}

/**
Expand Down

0 comments on commit 8a5002b

Please sign in to comment.