Make volatile loads from IO/softswitches access exactly the byte(s) specified.

Previously, one-byte loads were typically done by reading a 16-bit value and then masking off the upper 8 bits. This is a problem when accessing softswitches or slot IO locations, because reading the subsequent byte may have some undesired effect. Now, ORCA/C will do an 8-bit read for such cases, if the volatile qualifier is used.

There were also a couple optimizations that could occasionally result in not all the bytes of a larger value actually being read. These are now disabled for volatile loads that may access softswitches or IO.

These changes should make ORCA/C more suitable for writing low-level software like device drivers.
This commit is contained in:
Stephen Heumann 2022-05-23 21:10:29 -05:00
parent 21f266c5df
commit daff1754b2
4 changed files with 38 additions and 16 deletions

View File

@ -349,11 +349,12 @@
{ } { }
{ pc_ind - load indirect } { pc_ind - load indirect }
{ } { }
{ Gen1t (pc_ind, disp, type) } { Gen2t (pc_ind, volatile, disp, type) }
{ } { }
{ A value of type TYPE is loaded from DISP bytes past the } { A value of type TYPE is loaded from DISP bytes past the }
{ address that is on the evaluation stack. The address is } { address that is on the evaluation stack. The address is }
{ removed from the stack and replaced with the value. } { removed from the stack and replaced with the value. }
{ VOLATILE is non-zero for a volatile load, or 0 otherwise. }
{ } { }
{ } { }
{ pc_ior - logical or } { pc_ior - logical or }

View File

@ -1414,7 +1414,8 @@ case op^.opcode of {check for optimizations of this node}
PeepHoleOptimization(opv); PeepHoleOptimization(opv);
end; {if} end; {if}
end {else if} end {else if}
else if op^.left^.opcode in [pc_lod,pc_ldo,pc_ind] then begin else if (op^.left^.opcode in [pc_lod,pc_ldo]) or
((op^.left^.opcode = pc_ind) and (op^.left^.r = 0)) then begin
if fromtype.optype in [cgWord,cgUWord] then if fromtype.optype in [cgWord,cgUWord] then
if totype.optype in [cgByte,cgUByte,cgWord,cgUWord] then begin if totype.optype in [cgByte,cgUByte,cgWord,cgUWord] then begin
op^.left^.optype := totype.optype; op^.left^.optype := totype.optype;
@ -1452,7 +1453,8 @@ case op^.opcode of {check for optimizations of this node}
with op^.left^ do with op^.left^ do
if opcode in [pc_slr,pc_vsr] then if opcode in [pc_slr,pc_vsr] then
if right^.opcode = pc_ldc then if right^.opcode = pc_ldc then
if left^.opcode in [pc_lod,pc_ldo,pc_ind] then begin if (left^.opcode in [pc_lod,pc_ldo]) or
((left^.opcode = pc_ind) and (left^.r = 0)) then begin
lq := right^.lval; lq := right^.lval;
if long(lq).msw = 0 then if long(lq).msw = 0 then
if long(lq).lsw in [8,16,24] then begin if long(lq).lsw in [8,16,24] then begin

View File

@ -2756,6 +2756,7 @@ var
et: baseTypeEnum; {temp storage for a base type} et: baseTypeEnum; {temp storage for a base type}
i: integer; {loop variable} i: integer; {loop variable}
isString: boolean; {was the ? : a string?} isString: boolean; {was the ? : a string?}
isVolatile: boolean; {is this a volatile op?}
lType: typePtr; {type of operands} lType: typePtr; {type of operands}
kind: typeKind; {temp type kind} kind: typeKind; {temp type kind}
size: longint; {size of an array element} size: longint; {size of an array element}
@ -3146,7 +3147,7 @@ var
Gen2t(pc_lbf, bitDisp, bitSize, tp); Gen2t(pc_lbf, bitDisp, bitSize, tp);
end {if} end {if}
else else
Gen1t(pc_ind, 0, tp); Gen2t(pc_ind, ord(tqVolatile in expressionType^.qualifiers), 0, tp);
if pc_l in [pc_lli,pc_lld] then if pc_l in [pc_lli,pc_lld] then
if expressionType^.cType in [ctBool,ctFloat,ctDouble,ctLongDouble, if expressionType^.cType in [ctBool,ctFloat,ctDouble,ctLongDouble,
ctComp] then begin ctComp] then begin
@ -3724,6 +3725,7 @@ case tree^.token.kind of
Gen2t(pc_lod, t1, 0, cgULong); Gen2t(pc_lod, t1, 0, cgULong);
Gen2t(pc_lod, t1, 0, cgULong); Gen2t(pc_lod, t1, 0, cgULong);
lType := expressionType^.pType; lType := expressionType^.pType;
isVolatile := tqVolatile in lType^.qualifiers;
if isBitField then begin if isBitField then begin
if unsigned then if unsigned then
Gen2t(pc_lbu, bitDisp, bitSize, lType^.baseType) Gen2t(pc_lbu, bitDisp, bitSize, lType^.baseType)
@ -3731,9 +3733,9 @@ case tree^.token.kind of
Gen2t(pc_lbf, bitDisp, bitSize, lType^.baseType); Gen2t(pc_lbf, bitDisp, bitSize, lType^.baseType);
end {if} end {if}
else if lType^.kind = pointerType then else if lType^.kind = pointerType then
Gen1t(pc_ind, 0, cgULong) Gen2t(pc_ind, ord(isVolatile), 0, cgULong)
else else
Gen1t(pc_ind, 0, lType^.baseType); Gen2t(pc_ind, ord(isVolatile), 0, lType^.baseType);
end; {else} end; {else}
if tqConst in lType^.qualifiers then if tqConst in lType^.qualifiers then
Error(93); Error(93);
@ -4481,13 +4483,14 @@ case tree^.token.kind of
else if lType^.kind = pointerType then else if lType^.kind = pointerType then
lType := lType^.pType; lType := lType^.pType;
expressionType := lType; expressionType := lType;
isVolatile := tqVolatile in lType^.qualifiers;
if lType^.kind = scalarType then if lType^.kind = scalarType then
if lType^.baseType = cgVoid then if lType^.baseType = cgVoid then
Gen1t(pc_ind, 0, cgULong) Gen2t(pc_ind, ord(isVolatile), 0, cgULong)
else else
Gen1t(pc_ind, 0, lType^.baseType) Gen2t(pc_ind, ord(isVolatile), 0, lType^.baseType)
else if lType^.kind = pointerType then else if lType^.kind = pointerType then
Gen1t(pc_ind, 0, cgULong) Gen2t(pc_ind, ord(isVolatile), 0, cgULong)
else if not else if not
((lType^.kind in [functionType,arrayType,structType,unionType]) ((lType^.kind in [functionType,arrayType,structType,unionType])
or ((lType^.kind = definedType) and {handle const struct/union} or ((lType^.kind = definedType) and {handle const struct/union}
@ -4513,6 +4516,7 @@ case tree^.token.kind of
size := 0; size := 0;
end; {else} end; {else}
kind := expressionType^.kind; kind := expressionType^.kind;
isVolatile := tqVolatile in expressionType^.qualifiers;
if kind = scalarType then begin if kind = scalarType then begin
et := expressionType^.baseType; et := expressionType^.baseType;
if isBitField then begin if isBitField then begin
@ -4524,12 +4528,12 @@ case tree^.token.kind of
Gen2t(pc_lbf, bitDisp, bitSize, et); Gen2t(pc_lbf, bitDisp, bitSize, et);
end {if} end {if}
else else
Gen1t(pc_ind, long(size).lsw, et); Gen2t(pc_ind, ord(isVolatile), long(size).lsw, et);
end {if} end {if}
else if kind = pointerType then else if kind = pointerType then
Gen1t(pc_ind, long(size).lsw, cgULong) Gen2t(pc_ind, ord(isVolatile), long(size).lsw, cgULong)
else if kind = enumType then else if kind = enumType then
Gen1t(pc_ind, long(size).lsw, cgWord) Gen2t(pc_ind, ord(isVolatile), long(size).lsw, cgWord)
else if size <> 0 then else if size <> 0 then
Gen1t(pc_inc, long(size).lsw, cgULong); Gen1t(pc_inc, long(size).lsw, cgULong);
end {if} end {if}

23
Gen.pas
View File

@ -2923,6 +2923,7 @@ var
lQuad: quadType; {requested quad address type} lQuad: quadType; {requested quad address type}
optype: baseTypeEnum; {op^.optype} optype: baseTypeEnum; {op^.optype}
q: integer; {op^.q} q: integer; {op^.q}
volatileByte: boolean; {is this a volatile byte access?}
begin {GenInd} begin {GenInd}
optype := op^.optype; optype := op^.optype;
@ -3068,22 +3069,36 @@ case optype of
cgByte,cgUByte,cgWord,cgUWord: begin cgByte,cgUByte,cgWord,cgUWord: begin
GetPointer(op^.left); GetPointer(op^.left);
if gLong.where = inPointer then begin if gLong.where = inPointer then begin
if q = 0 then volatileByte := (op^.r <> 0) and (optype in [cgByte,cgUByte]);
if q = 0 then begin
if volatileByte then
GenNative(m_sep, immediate, 32, nil, 0);
if gLong.fixedDisp then if gLong.fixedDisp then
GenNative(m_lda_indl, direct, gLong.disp, nil, 0) GenNative(m_lda_indl, direct, gLong.disp, nil, 0)
else else
GenNative(m_lda_indly, direct, gLong.disp, nil, 0) GenNative(m_lda_indly, direct, gLong.disp, nil, 0);
if volatileByte then
GenNative(m_rep, immediate, 32, nil, 0);
end {if}
else else
if gLong.fixedDisp then begin if gLong.fixedDisp then begin
if volatileByte then
GenNative(m_sep, immediate, 32, nil, 0);
GenNative(m_ldy_imm, immediate, q, nil, 0); GenNative(m_ldy_imm, immediate, q, nil, 0);
GenNative(m_lda_indly, direct, gLong.disp, nil, 0) GenNative(m_lda_indly, direct, gLong.disp, nil, 0);
if volatileByte then
GenNative(m_rep, immediate, 32, nil, 0);
end {if} end {if}
else begin else begin
GenImplied(m_tya); GenImplied(m_tya);
GenImplied(m_clc); GenImplied(m_clc);
GenNative(m_adc_imm, immediate, q, nil, 0); GenNative(m_adc_imm, immediate, q, nil, 0);
GenImplied(m_tay); GenImplied(m_tay);
GenNative(m_lda_indly, direct, gLong.disp, nil, 0) if volatileByte then
GenNative(m_sep, immediate, 32, nil, 0);
GenNative(m_lda_indly, direct, gLong.disp, nil, 0);
if volatileByte then
GenNative(m_rep, immediate, 32, nil, 0);
end; {else} end; {else}
end {if} end {if}
else if gLong.where = localAddress then begin else if gLong.where = localAddress then begin