@@ -1208,6 +1208,7 @@ pub(crate) fn lower_insn_to_regs<C: LowerCtx<I = Inst>>(
12081208 lower_icmp_or_ifcmp_to_flags ( ctx, ifcmp_insn, is_signed) ;
12091209 let rd = get_output_reg ( ctx, outputs[ 0 ] ) ;
12101210 ctx. emit ( Inst :: CSet { rd, cond } ) ;
1211+ normalize_bool_result ( ctx, insn, rd) ;
12111212 }
12121213
12131214 Opcode :: Trueff => {
@@ -1217,6 +1218,7 @@ pub(crate) fn lower_insn_to_regs<C: LowerCtx<I = Inst>>(
12171218 lower_fcmp_or_ffcmp_to_flags ( ctx, ffcmp_insn) ;
12181219 let rd = get_output_reg ( ctx, outputs[ 0 ] ) ;
12191220 ctx. emit ( Inst :: CSet { rd, cond } ) ;
1221+ normalize_bool_result ( ctx, insn, rd) ;
12201222 }
12211223
12221224 Opcode :: IsNull | Opcode :: IsInvalid => {
@@ -1240,6 +1242,7 @@ pub(crate) fn lower_insn_to_regs<C: LowerCtx<I = Inst>>(
12401242 let const_value = ResultRSEImm12 :: Imm12 ( Imm12 :: maybe_from_u64 ( const_value) . unwrap ( ) ) ;
12411243 ctx. emit ( alu_inst_imm12 ( alu_op, writable_zero_reg ( ) , rn, const_value) ) ;
12421244 ctx. emit ( Inst :: CSet { rd, cond : Cond :: Eq } ) ;
1245+ normalize_bool_result ( ctx, insn, rd) ;
12431246 }
12441247
12451248 Opcode :: Copy => {
@@ -1249,49 +1252,95 @@ pub(crate) fn lower_insn_to_regs<C: LowerCtx<I = Inst>>(
12491252 ctx. emit ( Inst :: gen_move ( rd, rn, ty) ) ;
12501253 }
12511254
1252- Opcode :: Bint | Opcode :: Breduce | Opcode :: Bextend | Opcode :: Ireduce => {
1253- // If this is a Bint from a Trueif/Trueff/IsNull/IsInvalid, then the result is already
1254- // 64-bit-zero-extended, even if the CLIF type doesn't say so, because it was produced
1255- // by a CSet. In this case, we do not need to do any zero-extension.
1256- let input_info = ctx. get_input ( insn, 0 ) ;
1257- let src_op = input_info
1258- . inst
1259- . map ( |( src_inst, _) | ctx. data ( src_inst) . opcode ( ) ) ;
1260- let narrow_mode = match ( src_op, op) {
1261- ( Some ( Opcode :: Trueif ) , Opcode :: Bint )
1262- | ( Some ( Opcode :: Trueff ) , Opcode :: Bint )
1263- | ( Some ( Opcode :: IsNull ) , Opcode :: Bint )
1264- | ( Some ( Opcode :: IsInvalid ) , Opcode :: Bint ) => NarrowValueMode :: None ,
1265- _ => NarrowValueMode :: ZeroExtend64 ,
1266- } ;
1267-
1268- // All of these ops are simply a move from a zero-extended source.
1269- // Here is why this works, in each case:
1270- //
1271- // - Bint: Bool-to-int. We always represent a bool as a 0 or 1, so we
1272- // merely need to zero-extend here.
1273- //
1274- // - Breduce, Bextend: changing width of a boolean. We represent a
1275- // bool as a 0 or 1, so again, this is a zero-extend / no-op.
1276- //
1277- // - Ireduce: changing width of an integer. Smaller ints are stored
1278- // with undefined high-order bits, so we can simply do a copy.
1279-
1280- let rn = put_input_in_reg ( ctx, inputs[ 0 ] , narrow_mode) ;
1255+ Opcode :: Breduce | Opcode :: Ireduce => {
1256+ // Smaller integers/booleans are stored with high-order bits
1257+ // undefined, so we can simply do a copy.
1258+ let rn = put_input_in_reg ( ctx, inputs[ 0 ] , NarrowValueMode :: None ) ;
12811259 let rd = get_output_reg ( ctx, outputs[ 0 ] ) ;
12821260 let ty = ctx. input_ty ( insn, 0 ) ;
12831261 ctx. emit ( Inst :: gen_move ( rd, rn, ty) ) ;
12841262 }
12851263
1286- Opcode :: Bmask => {
1287- // Bool is {0, 1}, so we can subtract from 0 to get all-1s.
1264+ Opcode :: Bextend | Opcode :: Bmask => {
1265+ // Bextend and Bmask both simply sign-extend. This works for:
1266+ // - Bextend, because booleans are stored as 0 / -1, so we
1267+ // sign-extend the -1 to a -1 in the wider width.
1268+ // - Bmask, because the resulting integer mask value must be
1269+ // all-ones (-1) if the argument is true.
1270+ //
1271+ // For a sign-extension from a 1-bit value (Case 1 below), we need
1272+ // to do things a bit specially, because the ISA does not have a
1273+ // 1-to-N-bit sign extension instruction. For 8-bit or wider
1274+ // sources (Case 2 below), we do a sign extension normally.
1275+
1276+ let from_ty = ctx. input_ty ( insn, 0 ) ;
1277+ let to_ty = ctx. output_ty ( insn, 0 ) ;
1278+ let from_bits = ty_bits ( from_ty) ;
1279+ let to_bits = ty_bits ( to_ty) ;
1280+
1281+ assert ! (
1282+ from_bits <= 64 && to_bits <= 64 ,
1283+ "Vector Bextend not supported yet"
1284+ ) ;
1285+ assert ! ( from_bits <= to_bits) ;
1286+
1287+ if from_bits == to_bits {
1288+ // Nothing.
1289+ } else if from_bits == 1 {
1290+ assert ! ( to_bits >= 8 ) ;
1291+ // Case 1: 1-bit to N-bit extension: AND the LSB of source into
1292+ // dest, generating a value of 0 or 1, then negate to get
1293+ // 0x000... or 0xfff...
1294+ let rn = put_input_in_reg ( ctx, inputs[ 0 ] , NarrowValueMode :: None ) ;
1295+ let rd = get_output_reg ( ctx, outputs[ 0 ] ) ;
1296+ // AND Rdest, Rsource, #1
1297+ ctx. emit ( Inst :: AluRRImmLogic {
1298+ alu_op : ALUOp :: And64 ,
1299+ rd,
1300+ rn,
1301+ imml : ImmLogic :: maybe_from_u64 ( 1 , I64 ) . unwrap ( ) ,
1302+ } ) ;
1303+ // SUB Rdest, XZR, Rdest (i.e., NEG Rdest)
1304+ ctx. emit ( Inst :: AluRRR {
1305+ alu_op : ALUOp :: Sub64 ,
1306+ rd,
1307+ rn : zero_reg ( ) ,
1308+ rm : rd. to_reg ( ) ,
1309+ } ) ;
1310+ } else {
1311+ // Case 2: 8-or-more-bit to N-bit extension: just sign-extend. A
1312+ // `true` (all ones, or `-1`) will be extended to -1 with the
1313+ // larger width.
1314+ assert ! ( from_bits >= 8 ) ;
1315+ let narrow_mode = if to_bits == 64 {
1316+ NarrowValueMode :: SignExtend64
1317+ } else {
1318+ assert ! ( to_bits <= 32 ) ;
1319+ NarrowValueMode :: SignExtend32
1320+ } ;
1321+ let rn = put_input_in_reg ( ctx, inputs[ 0 ] , narrow_mode) ;
1322+ let rd = get_output_reg ( ctx, outputs[ 0 ] ) ;
1323+ ctx. emit ( Inst :: gen_move ( rd, rn, to_ty) ) ;
1324+ }
1325+ }
1326+
1327+ Opcode :: Bint => {
1328+ // Booleans are stored as all-zeroes (0) or all-ones (-1). We AND
1329+ // out the LSB to give a 0 / 1-valued integer result.
1330+ let rn = put_input_in_reg ( ctx, inputs[ 0 ] , NarrowValueMode :: None ) ;
12881331 let rd = get_output_reg ( ctx, outputs[ 0 ] ) ;
1289- let rm = put_input_in_reg ( ctx, inputs[ 0 ] , NarrowValueMode :: ZeroExtend64 ) ;
1290- ctx. emit ( Inst :: AluRRR {
1291- alu_op : ALUOp :: Sub64 ,
1332+ let output_bits = ty_bits ( ctx. output_ty ( insn, 0 ) ) ;
1333+
1334+ let ( imm_ty, alu_op) = if output_bits > 32 {
1335+ ( I64 , ALUOp :: And64 )
1336+ } else {
1337+ ( I32 , ALUOp :: And32 )
1338+ } ;
1339+ ctx. emit ( Inst :: AluRRImmLogic {
1340+ alu_op,
12921341 rd,
1293- rn : zero_reg ( ) ,
1294- rm ,
1342+ rn,
1343+ imml : ImmLogic :: maybe_from_u64 ( 1 , imm_ty ) . unwrap ( ) ,
12951344 } ) ;
12961345 }
12971346
@@ -1369,7 +1418,8 @@ pub(crate) fn lower_insn_to_regs<C: LowerCtx<I = Inst>>(
13691418 let alu_op = choose_32_64 ( ty, ALUOp :: SubS32 , ALUOp :: SubS64 ) ;
13701419 let rm = put_input_in_rse_imm12 ( ctx, inputs[ 1 ] , narrow_mode) ;
13711420 ctx. emit ( alu_inst_imm12 ( alu_op, writable_zero_reg ( ) , rn, rm) ) ;
1372- ctx. emit ( Inst :: CondSet { cond, rd } ) ;
1421+ ctx. emit ( Inst :: CSet { cond, rd } ) ;
1422+ normalize_bool_result ( ctx, insn, rd) ;
13731423 } else {
13741424 let rm = put_input_in_reg ( ctx, inputs[ 1 ] , narrow_mode) ;
13751425 lower_vector_compare ( ctx, rd, rn, rm, ty, cond) ?;
@@ -1394,7 +1444,8 @@ pub(crate) fn lower_insn_to_regs<C: LowerCtx<I = Inst>>(
13941444 }
13951445 _ => panic ! ( "Bad float size" ) ,
13961446 }
1397- ctx. emit ( Inst :: CondSet { cond, rd } ) ;
1447+ ctx. emit ( Inst :: CSet { cond, rd } ) ;
1448+ normalize_bool_result ( ctx, insn, rd) ;
13981449 } else {
13991450 lower_vector_compare ( ctx, rd, rn, rm, ty, cond) ?;
14001451 }
@@ -1659,6 +1710,7 @@ pub(crate) fn lower_insn_to_regs<C: LowerCtx<I = Inst>>(
16591710 } ) ;
16601711
16611712 ctx. emit ( Inst :: CSet { rd, cond : Cond :: Ne } ) ;
1713+ normalize_bool_result ( ctx, insn, rd) ;
16621714 }
16631715
16641716 Opcode :: Shuffle
0 commit comments