mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-01-12 01:20:14 +00:00
The current expansion of kbps_to_icc() introduces unnecessary logic
when compiled from a general expression. Rewriting it allows compilers
to emit shorter and more efficient code across architectures.
For example, with gcc -O2:
arm64:
old:
tst x0, 7
add w1, w0, 7
cset w2, ne
cmp w0, 0
csel w0, w1, w0, lt
add w0, w2, w0, asr 3
new:
add w1, w0, 14
adds w0, w0, 7
csel w0, w1, w0, mi
asr w0, w0, 3
x86-64:
old:
xor eax, eax
test dil, 7
lea edx, [rdi+7]
setne al
test edi, edi
cmovns edx, edi
sar edx, 3
add eax, edx
new:
lea eax, [rdi+14]
add edi, 7
cmovns eax, edi
sar eax, 3
In both cases the old form relies on extra test and compare
instructions (tst, test, cmp) combined with conditional moves or sets,
while the new form uses fewer instructions by folding the addition and
flag update together (adds on arm64, add on x86).
This reduces the instruction sequence, prevents multiple evaluations of
x when it is an expression or a function call, and keeps the macro
simpler.
Signed-off-by: Kuan-Wei Chiu <visitorckw@gmail.com>
Link: https://lore.kernel.org/r/20250930043055.2200322-1-visitorckw@gmail.com
Signed-off-by: Georgi Djakov <djakov@kernel.org>
142 lines
3.4 KiB
C
142 lines
3.4 KiB
C
/* SPDX-License-Identifier: GPL-2.0 */
|
|
/*
|
|
* Copyright (c) 2018-2019, Linaro Ltd.
|
|
* Author: Georgi Djakov <georgi.djakov@linaro.org>
|
|
*/
|
|
|
|
#ifndef __LINUX_INTERCONNECT_H
|
|
#define __LINUX_INTERCONNECT_H
|
|
|
|
#include <linux/mutex.h>
|
|
#include <linux/types.h>
|
|
|
|
/* macros for converting to icc units */
|
|
#define Bps_to_icc(x) ((x) / 1000)
|
|
#define kBps_to_icc(x) (x)
|
|
#define MBps_to_icc(x) ((x) * 1000)
|
|
#define GBps_to_icc(x) ((x) * 1000 * 1000)
|
|
#define bps_to_icc(x) (1)
|
|
#define kbps_to_icc(x) (((x) + 7) / 8)
|
|
#define Mbps_to_icc(x) ((x) * 1000 / 8)
|
|
#define Gbps_to_icc(x) ((x) * 1000 * 1000 / 8)
|
|
|
|
/* macro to indicate dynamic id allocation */
|
|
#define ICC_ALLOC_DYN_ID -1
|
|
|
|
struct icc_path;
|
|
struct device;
|
|
|
|
/**
|
|
* struct icc_bulk_data - Data used for bulk icc operations.
|
|
*
|
|
* @path: reference to the interconnect path (internal use)
|
|
* @name: the name from the "interconnect-names" DT property
|
|
* @avg_bw: average bandwidth in icc units
|
|
* @peak_bw: peak bandwidth in icc units
|
|
*/
|
|
struct icc_bulk_data {
|
|
struct icc_path *path;
|
|
const char *name;
|
|
u32 avg_bw;
|
|
u32 peak_bw;
|
|
};
|
|
|
|
#if IS_ENABLED(CONFIG_INTERCONNECT)
|
|
|
|
struct icc_path *of_icc_get(struct device *dev, const char *name);
|
|
struct icc_path *devm_of_icc_get(struct device *dev, const char *name);
|
|
int devm_of_icc_bulk_get(struct device *dev, int num_paths, struct icc_bulk_data *paths);
|
|
struct icc_path *of_icc_get_by_index(struct device *dev, int idx);
|
|
void icc_put(struct icc_path *path);
|
|
int icc_enable(struct icc_path *path);
|
|
int icc_disable(struct icc_path *path);
|
|
int icc_set_bw(struct icc_path *path, u32 avg_bw, u32 peak_bw);
|
|
void icc_set_tag(struct icc_path *path, u32 tag);
|
|
const char *icc_get_name(struct icc_path *path);
|
|
int __must_check of_icc_bulk_get(struct device *dev, int num_paths,
|
|
struct icc_bulk_data *paths);
|
|
void icc_bulk_put(int num_paths, struct icc_bulk_data *paths);
|
|
int icc_bulk_set_bw(int num_paths, const struct icc_bulk_data *paths);
|
|
int icc_bulk_enable(int num_paths, const struct icc_bulk_data *paths);
|
|
void icc_bulk_disable(int num_paths, const struct icc_bulk_data *paths);
|
|
|
|
#else
|
|
|
|
static inline struct icc_path *of_icc_get(struct device *dev,
|
|
const char *name)
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
static inline struct icc_path *devm_of_icc_get(struct device *dev,
|
|
const char *name)
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
static inline struct icc_path *of_icc_get_by_index(struct device *dev, int idx)
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
static inline void icc_put(struct icc_path *path)
|
|
{
|
|
}
|
|
|
|
static inline int icc_enable(struct icc_path *path)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
static inline int icc_disable(struct icc_path *path)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
static inline int icc_set_bw(struct icc_path *path, u32 avg_bw, u32 peak_bw)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
static inline void icc_set_tag(struct icc_path *path, u32 tag)
|
|
{
|
|
}
|
|
|
|
static inline const char *icc_get_name(struct icc_path *path)
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
static inline int of_icc_bulk_get(struct device *dev, int num_paths, struct icc_bulk_data *paths)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
static inline int devm_of_icc_bulk_get(struct device *dev, int num_paths,
|
|
struct icc_bulk_data *paths)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
static inline void icc_bulk_put(int num_paths, struct icc_bulk_data *paths)
|
|
{
|
|
}
|
|
|
|
static inline int icc_bulk_set_bw(int num_paths, const struct icc_bulk_data *paths)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
static inline int icc_bulk_enable(int num_paths, const struct icc_bulk_data *paths)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
static inline void icc_bulk_disable(int num_paths, const struct icc_bulk_data *paths)
|
|
{
|
|
}
|
|
|
|
#endif /* CONFIG_INTERCONNECT */
|
|
|
|
#endif /* __LINUX_INTERCONNECT_H */
|