在特殊情况函数中展开循环

时间:2017-09-18 10:31:43

标签: c++ gcc loop-unrolling

所以我正在尝试优化一些代码。我有一个可变大小的循环函数。然而,为了提高效率,我想制作具有1,2和3大小的循环的特殊情况,这些特殊情况是完全展开的。到目前为止,我的方法是将循环大小声明为const参数,然后定义包装函数,该函数调用main函数,为const值处理文字。我已经包含了一个代码片段,它说明了我的想法。

inline void someFunction (const int a)
{
    for (int i=0; i<a; i++)
    {
        // do something with i.
    }
}

void specialCase()
{
    someFunction (3);
}

void generalCase(int a)
{
    someFunction (a);
}

所以我的问题是,我希望我的编译器(GCC)在specialCase中展开for循环是合理的。我的意思是显然我可以复制 - 将someFunction的内容粘贴到specialCase中并用3代替,但为了清楚起见,我宁愿只在代码中处理someFunction的一个定义。

3 个答案:

答案 0 :(得分:2)

  

然而,为了提高效率,我想制作具有1,2和3大小的循环的特殊情况,这些特殊情况是完全展开的。

您是否测量过这实际上更快?我怀疑它会是什么(或者编译器不会自动展开循环)。

  

到目前为止,我的方法是将循环大小声明为const参数,然后定义调用main函数的包装函数,并将其作为const值的文字。

import React, {Component} from 'react'; import {connect} from 'react-redux' import ReduxFormHelper from 'redux-form-helper' class MyForm extends Component { constructor(props) { super(props); this.helper = new ReduxFormHelper(props) this.helper.resetForm(); } onChange(e) { this.helper.processField(e) } onSubmit(e) { e.preventDefault() let {onSubmitForm} = this.props let ret = this.helper.processForm(e) ret && onSubmitForm(ret) } render() { let {formData, formErrors} = this.props return ( <div> {!!formErrors._flag && <div className="alert" role="alert"> Form has one or more errors. </div> } <form onSubmit={this.onSubmit.bind(this)} > <div className={'form-group' + (formErrors['field1']? ' has-error': '')}> <label>Field 1 *</label> <input type="text" name="field1" value={formData.field1} onChange={this.onChange.bind(this)} className="form-control" /> {!!formErrors['field1'] && <span className="help-block"> {formErrors['field1'] === 'invalid'? 'Must be a string of 2-50 characters' : 'Required field'} </span> } </div> ... <button type="submit" className="btn btn-default">Submit</button> </form> </div> ) } } const formModel = { field1: { required: true, validate: (value) => value.length >= 2 && value.length <= 50 }, ... } function mapStateToProps (state) { return { formData: state.formData, formErrors: state.formErrors, formModel } } function mapDispatchToProps (dispatch) { return { onUpdateForm: (data, errors) => { dispatch(doFormUpdate(data, errors)) }, onSubmitForm: (data) => { // dispatch some action which somehow updates state with form data } } } export default connect(mapStateToProps, mapDispatchToProps)(MyForm) 在这里没有任何意义。它不会影响编译器展开循环的能力。它只是意味着const不能在函数体内变异,但它仍然是运行时参数。

如果您想确保展开,请强行退出。使用C ++ 17非常容易。

a

live example on godbolt

答案 1 :(得分:2)

如果您不喜欢模板并且不信任您的编译器,那么总会有这种方法,它受到手动展开称为“duff设备”的循环的过时方法的启发:

void do_something(int i);

void do_something_n_times(int n)
{
    int i = 0;
    switch(n)
    {
        default:
            while(n > 3) {
                do_something(i++);
                --n;
            }
        case 3: do_something(i++);
        case 2: do_something(i++);
        case 1: do_something(i++);
    }
}

但我认为值得一提的是,如果你不相信你的编译器会为你做一个像循环展开这么简单的事情,那么可能是时候考虑一​​个新的编译器了。

请注意,Duff的设备最初被发明为用编译器编译的程序的微优化策略,这些编译器不会自动应用循环展开优化。

它是由汤姆达夫于1983年发明的。

https://en.wikipedia.org/wiki/Duff%27s_device

它与现代编译器的使用是值得怀疑的。

答案 2 :(得分:1)

如果你愿意使用所有流行编译器的强制内联(非标准)功能,我宁愿这样做:

__attribute__((always_inline))
void bodyOfLoop(int i) {
  // put code here
}

void specialCase() {
    bodyOfLoop(0);
    bodyOfLoop(1);
    bodyOfLoop(2);
}

void generalCase(int a) {
    for (int i=0; i<a; i++) {
        bodyOfLoop(i);
    }
}

注意:这是GCC / Clang解决方案。将__forceinline用于MSVC。