mirror of
https://github.com/golang/go
synced 2024-10-04 16:31:22 -06:00
fefae6eed1
The old code generated for a bounds check was CMP JLT ok CALL panicindex ok: ... The new code is (once the linker finishes with it): CMP JGE panic ... panic: CALL panicindex which moves the calls out of line, putting more useful code in each cache line. This matters especially in tight loops, such as in Fannkuch. The benefit is more modest elsewhere, but real. From test/bench/go1, amd64: benchmark old ns/op new ns/op delta BenchmarkBinaryTree17 6096092000 6088808000 -0.12% BenchmarkFannkuch11 6151404000 4020463000 -34.64% BenchmarkGobDecode 28990050 28894630 -0.33% BenchmarkGobEncode 12406310 12136730 -2.17% BenchmarkGzip 179923 179903 -0.01% BenchmarkGunzip 11219 11130 -0.79% BenchmarkJSONEncode 86429350 86515900 +0.10% BenchmarkJSONDecode 334593800 315728400 -5.64% BenchmarkRevcomp25M 1219763000 1180767000 -3.20% BenchmarkTemplate 492947600 483646800 -1.89% And 386: benchmark old ns/op new ns/op delta BenchmarkBinaryTree17 6354902000 6243000000 -1.76% BenchmarkFannkuch11 8043769000 7326965000 -8.91% BenchmarkGobDecode 19010800 18941230 -0.37% BenchmarkGobEncode 14077500 13792460 -2.02% BenchmarkGzip 194087 193619 -0.24% BenchmarkGunzip 12495 12457 -0.30% BenchmarkJSONEncode 125636400 125451400 -0.15% BenchmarkJSONDecode 696648600 685032800 -1.67% BenchmarkRevcomp25M 2058088000 2052545000 -0.27% BenchmarkTemplate 602140000 589876800 -2.04% To implement this, two new instruction forms: JLT target // same as always JLT $0, target // branch expected not taken JLT $1, target // branch expected taken The linker could also emit the prediction prefixes, but it does not: expected taken branches are reversed so that the expected case is not taken (as in example above), and the default expectaton for such a jump is not taken already. R=golang-dev, gri, r, dave CC=golang-dev https://golang.org/cl/6248049
181 lines
3.7 KiB
C
181 lines
3.7 KiB
C
// Copyright 2009 The Go Authors. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style
|
|
// license that can be found in the LICENSE file.
|
|
|
|
#ifndef EXTERN
|
|
#define EXTERN extern
|
|
#endif
|
|
|
|
#include "../gc/go.h"
|
|
#include "../8l/8.out.h"
|
|
|
|
typedef struct Addr Addr;
|
|
|
|
struct Addr
|
|
{
|
|
int32 offset;
|
|
int32 offset2;
|
|
|
|
double dval;
|
|
Prog* branch;
|
|
char sval[NSNAME];
|
|
|
|
Sym* gotype;
|
|
Sym* sym;
|
|
Node* node;
|
|
int width;
|
|
uchar type;
|
|
uchar index;
|
|
uchar etype;
|
|
uchar scale; /* doubles as width in DATA op */
|
|
uchar pun; /* dont register variable */
|
|
};
|
|
#define A ((Addr*)0)
|
|
|
|
struct Prog
|
|
{
|
|
short as; // opcode
|
|
uint32 loc; // pc offset in this func
|
|
uint32 lineno; // source line that generated this
|
|
Addr from; // src address
|
|
Addr to; // dst address
|
|
Prog* link; // next instruction in this func
|
|
void* reg; // pointer to containing Reg struct
|
|
};
|
|
|
|
#define TEXTFLAG from.scale
|
|
|
|
// foptoas flags
|
|
enum
|
|
{
|
|
Frev = 1<<0,
|
|
Fpop = 1<<1,
|
|
Fpop2 = 1<<2,
|
|
};
|
|
|
|
EXTERN int32 dynloc;
|
|
EXTERN uchar reg[D_NONE];
|
|
EXTERN int32 pcloc; // instruction counter
|
|
EXTERN Strlit emptystring;
|
|
extern char* anames[];
|
|
EXTERN Prog zprog;
|
|
EXTERN Node* newproc;
|
|
EXTERN Node* deferproc;
|
|
EXTERN Node* deferreturn;
|
|
EXTERN Node* panicindex;
|
|
EXTERN Node* panicslice;
|
|
EXTERN Node* throwreturn;
|
|
EXTERN int maxstksize;
|
|
extern uint32 unmappedzero;
|
|
|
|
|
|
/*
|
|
* ggen.c
|
|
*/
|
|
void compile(Node*);
|
|
void proglist(void);
|
|
void gen(Node*);
|
|
Node* lookdot(Node*, Node*, int);
|
|
void cgen_as(Node*, Node*);
|
|
void cgen_callmeth(Node*, int);
|
|
void cgen_callinter(Node*, Node*, int);
|
|
void cgen_proc(Node*, int);
|
|
void cgen_callret(Node*, Node*);
|
|
void cgen_div(int, Node*, Node*, Node*);
|
|
void cgen_bmul(int, Node*, Node*, Node*);
|
|
void cgen_shift(int, int, Node*, Node*, Node*);
|
|
void cgen_dcl(Node*);
|
|
int needconvert(Type*, Type*);
|
|
void genconv(Type*, Type*);
|
|
void allocparams(void);
|
|
void checklabels();
|
|
void ginscall(Node*, int);
|
|
|
|
/*
|
|
* cgen.c
|
|
*/
|
|
void agen(Node*, Node*);
|
|
void agenr(Node *n, Node *a, Node *res);
|
|
void igen(Node*, Node*, Node*);
|
|
vlong fieldoffset(Type*, Node*);
|
|
void bgen(Node*, int, Prog*);
|
|
void sgen(Node*, Node*, int64);
|
|
void gmove(Node*, Node*);
|
|
Prog* gins(int, Node*, Node*);
|
|
int samaddr(Node*, Node*);
|
|
void naddr(Node*, Addr*, int);
|
|
void cgen_aret(Node*, Node*);
|
|
int cgen_inline(Node*, Node*);
|
|
Node* ncon(uint32);
|
|
void mgen(Node*, Node*, Node*);
|
|
void mfree(Node*);
|
|
|
|
/*
|
|
* cgen64.c
|
|
*/
|
|
void cmp64(Node*, Node*, int, Prog*);
|
|
void cgen64(Node*, Node*);
|
|
|
|
/*
|
|
* gsubr.c
|
|
*/
|
|
void clearp(Prog*);
|
|
void proglist(void);
|
|
Prog* gbranch(int, Type*);
|
|
void expecttaken(Prog*, int);
|
|
Prog* prog(int);
|
|
void gaddoffset(Node*);
|
|
void gconv(int, int);
|
|
int conv2pt(Type*);
|
|
vlong convvtox(vlong, int);
|
|
void fnparam(Type*, int, int);
|
|
Prog* gop(int, Node*, Node*, Node*);
|
|
void setconst(Addr*, vlong);
|
|
void setaddr(Addr*, Node*);
|
|
int optoas(int, Type*);
|
|
int foptoas(int, Type*, int);
|
|
void ginit(void);
|
|
void gclean(void);
|
|
void regalloc(Node*, Type*, Node*);
|
|
void regfree(Node*);
|
|
Node* nodarg(Type*, int);
|
|
void nodreg(Node*, Type*, int);
|
|
void nodindreg(Node*, Type*, int);
|
|
void nodconst(Node*, Type*, int64);
|
|
void gconreg(int, vlong, int);
|
|
void datagostring(Strlit*, Addr*);
|
|
void datastring(char*, int, Addr*);
|
|
void buildtxt(void);
|
|
Plist* newplist(void);
|
|
int isfat(Type*);
|
|
void sudoclean(void);
|
|
int sudoaddable(int, Node*, Addr*);
|
|
int dotaddable(Node*, Node*);
|
|
void afunclit(Addr*);
|
|
void split64(Node*, Node*, Node*);
|
|
void splitclean(void);
|
|
void nswap(Node*, Node*);
|
|
|
|
/*
|
|
* cplx.c
|
|
*/
|
|
int complexop(Node*, Node*);
|
|
void complexmove(Node*, Node*);
|
|
void complexgen(Node*, Node*);
|
|
void complexbool(int, Node*, Node*, int, Prog*);
|
|
|
|
/*
|
|
* list.c
|
|
*/
|
|
int Aconv(Fmt*);
|
|
int Dconv(Fmt*);
|
|
int Pconv(Fmt*);
|
|
int Rconv(Fmt*);
|
|
int Yconv(Fmt*);
|
|
void listinit(void);
|
|
|
|
void zaddr(Biobuf*, Addr*, int, int);
|
|
|
|
#pragma varargck type "D" Addr*
|
|
#pragma varargck type "lD" Addr*
|